@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.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Component, ChangeDetectionStrategy, Input, Output, ViewChild, EventEmitter as EventEmitter$1 } from '@angular/core';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import DOMPurify2 from 'dompurify';
|
|
4
|
+
import * as pdfjsLib from 'pdfjs-dist';
|
|
4
5
|
import * as docx from 'docx-preview';
|
|
5
6
|
import { unzipSync, strFromU8, unzip } from 'fflate';
|
|
6
7
|
import * as XLSX from 'xlsx';
|
|
@@ -527,11 +528,21 @@ var ToolbarController = class {
|
|
|
527
528
|
el;
|
|
528
529
|
toolbarEl;
|
|
529
530
|
actions = [];
|
|
531
|
+
pageInputEl = null;
|
|
532
|
+
pageLabelEl = null;
|
|
530
533
|
constructor(container) {
|
|
531
534
|
this.el = container;
|
|
532
535
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
533
536
|
this.el.appendChild(this.toolbarEl);
|
|
534
537
|
}
|
|
538
|
+
setPage(page, max) {
|
|
539
|
+
if (this.pageInputEl) {
|
|
540
|
+
this.pageInputEl.value = page.toString();
|
|
541
|
+
}
|
|
542
|
+
if (max !== void 0 && this.pageLabelEl) {
|
|
543
|
+
this.pageLabelEl.textContent = ` / ${max}`;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
535
546
|
update(actions) {
|
|
536
547
|
this.actions = actions;
|
|
537
548
|
this.render();
|
|
@@ -574,6 +585,7 @@ var ToolbarController = class {
|
|
|
574
585
|
if (action.type === "separator") {
|
|
575
586
|
groupEl.appendChild(createElement("div", { className: "fp-toolbar-separator" }));
|
|
576
587
|
} else if (action.type === "page-nav") {
|
|
588
|
+
const max = action.max ?? 1;
|
|
577
589
|
const prevBtn = this.createButton(
|
|
578
590
|
"prev",
|
|
579
591
|
ICON_PAGE_PREV,
|
|
@@ -592,7 +604,6 @@ var ToolbarController = class {
|
|
|
592
604
|
"Next Page",
|
|
593
605
|
() => {
|
|
594
606
|
const cur = parseInt(input.value, 10) || 1;
|
|
595
|
-
const max = action.max ?? 1;
|
|
596
607
|
if (cur < max) {
|
|
597
608
|
input.value = (cur + 1).toString();
|
|
598
609
|
action.execute("next", cur + 1);
|
|
@@ -604,15 +615,18 @@ var ToolbarController = class {
|
|
|
604
615
|
type: "number",
|
|
605
616
|
value: (action.value ?? 1).toString(),
|
|
606
617
|
min: "1",
|
|
607
|
-
max:
|
|
618
|
+
max: max.toString()
|
|
608
619
|
});
|
|
609
620
|
input.addEventListener("change", () => {
|
|
610
|
-
|
|
611
|
-
if (
|
|
612
|
-
|
|
613
|
-
|
|
621
|
+
let val = parseInt(input.value, 10);
|
|
622
|
+
if (isNaN(val)) val = 1;
|
|
623
|
+
val = Math.max(1, Math.min(max, val));
|
|
624
|
+
input.value = val.toString();
|
|
625
|
+
action.execute("go", val);
|
|
614
626
|
});
|
|
615
|
-
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${
|
|
627
|
+
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
628
|
+
this.pageInputEl = input;
|
|
629
|
+
this.pageLabelEl = label;
|
|
616
630
|
groupEl.appendChild(prevBtn);
|
|
617
631
|
groupEl.appendChild(input);
|
|
618
632
|
groupEl.appendChild(label);
|
|
@@ -790,7 +804,13 @@ var FilePreviewViewer = class {
|
|
|
790
804
|
buffer,
|
|
791
805
|
options,
|
|
792
806
|
signal,
|
|
793
|
-
emit: (event, payload) =>
|
|
807
|
+
emit: (event, payload) => {
|
|
808
|
+
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
809
|
+
const total = payload.total ?? payload.totalPages;
|
|
810
|
+
this.toolbar?.setPage(payload.page, total);
|
|
811
|
+
}
|
|
812
|
+
this.eventEmitter.emit(event, payload);
|
|
813
|
+
}
|
|
794
814
|
});
|
|
795
815
|
this.activeInstance = instance;
|
|
796
816
|
this.hideLoading();
|
|
@@ -824,6 +844,7 @@ var FilePreviewViewer = class {
|
|
|
824
844
|
if (thumbnails && thumbnails.length > 0 && this.thumbnailPanel) {
|
|
825
845
|
this.thumbnailPanel.update(thumbnails, (index) => {
|
|
826
846
|
instance.goToPage?.(index + 1);
|
|
847
|
+
this.toolbar?.setPage(index + 1);
|
|
827
848
|
});
|
|
828
849
|
if (options.showThumbnails) {
|
|
829
850
|
this.thumbnailPanel.show();
|
|
@@ -949,9 +970,13 @@ var FilePreviewViewer = class {
|
|
|
949
970
|
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
950
971
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
951
972
|
this.activeInstance.goToPage?.(cur + 1);
|
|
973
|
+
const nextCur = this.activeInstance.getCurrentPage?.() ?? cur + 1;
|
|
974
|
+
this.toolbar?.setPage(nextCur);
|
|
952
975
|
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
953
976
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
954
977
|
this.activeInstance.goToPage?.(Math.max(1, cur - 1));
|
|
978
|
+
const prevCur = this.activeInstance.getCurrentPage?.() ?? Math.max(1, cur - 1);
|
|
979
|
+
this.toolbar?.setPage(prevCur);
|
|
955
980
|
} else if (e.key === "+" || e.key === "=") {
|
|
956
981
|
this.activeInstance.zoomIn?.();
|
|
957
982
|
} else if (e.key === "-" || e.key === "_") {
|
|
@@ -1217,30 +1242,62 @@ var CfbfReader = class {
|
|
|
1217
1242
|
return result.subarray(0, targetSize);
|
|
1218
1243
|
}
|
|
1219
1244
|
};
|
|
1220
|
-
|
|
1221
|
-
|
|
1245
|
+
if (typeof window !== "undefined" && pdfjsLib.GlobalWorkerOptions) {
|
|
1246
|
+
if (!pdfjsLib.GlobalWorkerOptions.workerSrc) {
|
|
1247
|
+
pdfjsLib.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjsLib.version || "4.10.38"}/build/pdf.worker.min.mjs`;
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1222
1250
|
var PdfPlugin = class {
|
|
1223
1251
|
id = "pdf";
|
|
1224
|
-
name = "PDF Preview";
|
|
1252
|
+
name = "PDF Document Preview";
|
|
1225
1253
|
extensions = [".pdf"];
|
|
1226
1254
|
mimeTypes = ["application/pdf"];
|
|
1227
1255
|
weight = 100;
|
|
1228
1256
|
supports(file) {
|
|
1229
1257
|
const ext = file.metadata.extension?.toLowerCase();
|
|
1230
1258
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
1231
|
-
|
|
1259
|
+
if (ext) return this.extensions.includes(ext);
|
|
1260
|
+
return this.mimeTypes.includes(mime || "");
|
|
1232
1261
|
}
|
|
1233
1262
|
getToolbarActions(instance) {
|
|
1263
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1264
|
+
const curPage = instance.getCurrentPage?.() ?? 1;
|
|
1234
1265
|
return [
|
|
1266
|
+
{
|
|
1267
|
+
id: "thumbnails",
|
|
1268
|
+
icon: "thumbnails",
|
|
1269
|
+
label: "Page Thumbnails",
|
|
1270
|
+
type: "button",
|
|
1271
|
+
group: "navigation",
|
|
1272
|
+
execute: () => instance.toggleThumbnails?.()
|
|
1273
|
+
},
|
|
1274
|
+
{
|
|
1275
|
+
id: "page-nav",
|
|
1276
|
+
icon: "",
|
|
1277
|
+
label: "Page Navigation",
|
|
1278
|
+
type: "page-nav",
|
|
1279
|
+
group: "navigation",
|
|
1280
|
+
value: curPage,
|
|
1281
|
+
max: totalPages,
|
|
1282
|
+
execute: (action, page) => {
|
|
1283
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1284
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1285
|
+
if (action === "prev") {
|
|
1286
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1287
|
+
} else if (action === "next") {
|
|
1288
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1289
|
+
} else if (typeof page === "number") {
|
|
1290
|
+
instance.goToPage?.(page);
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
},
|
|
1235
1294
|
{
|
|
1236
1295
|
id: "zoom-out",
|
|
1237
1296
|
icon: "zoom-out",
|
|
1238
1297
|
label: "Zoom Out",
|
|
1239
1298
|
type: "button",
|
|
1240
1299
|
group: "zoom",
|
|
1241
|
-
execute: () =>
|
|
1242
|
-
instance.zoomOut?.();
|
|
1243
|
-
}
|
|
1300
|
+
execute: () => instance.zoomOut?.()
|
|
1244
1301
|
},
|
|
1245
1302
|
{
|
|
1246
1303
|
id: "zoom-in",
|
|
@@ -1248,9 +1305,7 @@ var PdfPlugin = class {
|
|
|
1248
1305
|
label: "Zoom In",
|
|
1249
1306
|
type: "button",
|
|
1250
1307
|
group: "zoom",
|
|
1251
|
-
execute: () =>
|
|
1252
|
-
instance.zoomIn?.();
|
|
1253
|
-
}
|
|
1308
|
+
execute: () => instance.zoomIn?.()
|
|
1254
1309
|
},
|
|
1255
1310
|
{
|
|
1256
1311
|
id: "fit-page",
|
|
@@ -1258,39 +1313,23 @@ var PdfPlugin = class {
|
|
|
1258
1313
|
label: "Fit to Page",
|
|
1259
1314
|
type: "button",
|
|
1260
1315
|
group: "zoom",
|
|
1261
|
-
execute: () =>
|
|
1262
|
-
instance.fitToPage?.();
|
|
1263
|
-
}
|
|
1316
|
+
execute: () => instance.fitToPage?.()
|
|
1264
1317
|
},
|
|
1265
1318
|
{
|
|
1266
1319
|
id: "rotate-cw",
|
|
1267
1320
|
icon: "rotate-cw",
|
|
1268
|
-
label: "Rotate",
|
|
1321
|
+
label: "Rotate Clockwise",
|
|
1269
1322
|
type: "button",
|
|
1270
1323
|
group: "view",
|
|
1271
|
-
execute: () =>
|
|
1272
|
-
instance.rotateCW?.();
|
|
1273
|
-
}
|
|
1274
|
-
},
|
|
1275
|
-
{
|
|
1276
|
-
id: "page-nav",
|
|
1277
|
-
icon: "page-nav",
|
|
1278
|
-
label: "Page Navigation",
|
|
1279
|
-
type: "page-nav",
|
|
1280
|
-
group: "navigation",
|
|
1281
|
-
execute: (page) => {
|
|
1282
|
-
if (typeof page === "number") instance.goToPage?.(page);
|
|
1283
|
-
}
|
|
1324
|
+
execute: () => instance.rotateCW?.()
|
|
1284
1325
|
},
|
|
1285
1326
|
{
|
|
1286
1327
|
id: "download",
|
|
1287
1328
|
icon: "download",
|
|
1288
|
-
label: "Download",
|
|
1329
|
+
label: "Download PDF",
|
|
1289
1330
|
type: "button",
|
|
1290
1331
|
group: "actions",
|
|
1291
|
-
execute: () =>
|
|
1292
|
-
instance.download?.();
|
|
1293
|
-
}
|
|
1332
|
+
execute: () => instance.download?.()
|
|
1294
1333
|
},
|
|
1295
1334
|
{
|
|
1296
1335
|
id: "print",
|
|
@@ -1298,99 +1337,213 @@ var PdfPlugin = class {
|
|
|
1298
1337
|
label: "Print",
|
|
1299
1338
|
type: "button",
|
|
1300
1339
|
group: "actions",
|
|
1301
|
-
execute: () =>
|
|
1302
|
-
instance.print?.();
|
|
1303
|
-
}
|
|
1340
|
+
execute: () => instance.print?.()
|
|
1304
1341
|
}
|
|
1305
1342
|
];
|
|
1306
1343
|
}
|
|
1307
1344
|
async render(ctx) {
|
|
1308
|
-
const
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1345
|
+
const container = document.createElement("div");
|
|
1346
|
+
container.className = "fp-pdf-container";
|
|
1347
|
+
container.style.width = "100%";
|
|
1348
|
+
container.style.height = "100%";
|
|
1349
|
+
container.style.overflow = "auto";
|
|
1350
|
+
container.style.display = "flex";
|
|
1351
|
+
container.style.flexDirection = "column";
|
|
1352
|
+
container.style.alignItems = "center";
|
|
1353
|
+
container.style.padding = "24px 16px";
|
|
1354
|
+
container.style.backgroundColor = "#0f172a";
|
|
1355
|
+
container.style.boxSizing = "border-box";
|
|
1356
|
+
container.style.position = "relative";
|
|
1357
|
+
const pageCard = document.createElement("div");
|
|
1358
|
+
pageCard.className = "fp-pdf-page-card";
|
|
1359
|
+
pageCard.style.boxShadow = "0 10px 35px rgba(0, 0, 0, 0.5)";
|
|
1360
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
1361
|
+
pageCard.style.borderRadius = "4px";
|
|
1362
|
+
pageCard.style.overflow = "hidden";
|
|
1363
|
+
pageCard.style.lineHeight = "0";
|
|
1364
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
1365
|
+
pageCard.style.position = "relative";
|
|
1366
|
+
const canvas = document.createElement("canvas");
|
|
1367
|
+
pageCard.appendChild(canvas);
|
|
1368
|
+
container.appendChild(pageCard);
|
|
1369
|
+
const indicator = document.createElement("div");
|
|
1370
|
+
indicator.className = "fp-pdf-page-indicator";
|
|
1371
|
+
indicator.style.position = "sticky";
|
|
1372
|
+
indicator.style.bottom = "16px";
|
|
1373
|
+
indicator.style.marginTop = "16px";
|
|
1374
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1375
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
1376
|
+
indicator.style.color = "#f8fafc";
|
|
1377
|
+
indicator.style.fontSize = "12px";
|
|
1378
|
+
indicator.style.fontWeight = "600";
|
|
1379
|
+
indicator.style.padding = "5px 14px";
|
|
1380
|
+
indicator.style.borderRadius = "20px";
|
|
1381
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1382
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1383
|
+
indicator.style.zIndex = "10";
|
|
1384
|
+
indicator.style.userSelect = "none";
|
|
1385
|
+
indicator.style.pointerEvents = "none";
|
|
1386
|
+
container.appendChild(indicator);
|
|
1387
|
+
ctx.container.appendChild(container);
|
|
1388
|
+
const loadingTask = pdfjsLib.getDocument({
|
|
1389
|
+
data: new Uint8Array(ctx.buffer),
|
|
1390
|
+
cMapUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib.version || "4.10.38"}/cmaps/`,
|
|
1391
|
+
cMapPacked: true,
|
|
1392
|
+
standardFontDataUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib.version || "4.10.38"}/standard_fonts/`
|
|
1393
|
+
});
|
|
1394
|
+
const pdfDoc = await loadingTask.promise;
|
|
1395
|
+
const totalPages = Math.max(1, pdfDoc.numPages);
|
|
1324
1396
|
let currentPage = 1;
|
|
1325
|
-
let
|
|
1397
|
+
let zoomScale = 1;
|
|
1326
1398
|
let rotation = 0;
|
|
1399
|
+
let currentRenderTask = null;
|
|
1400
|
+
const renderPage = async (pageNum) => {
|
|
1401
|
+
if (currentRenderTask) {
|
|
1402
|
+
try {
|
|
1403
|
+
currentRenderTask.cancel();
|
|
1404
|
+
} catch {
|
|
1405
|
+
}
|
|
1406
|
+
currentRenderTask = null;
|
|
1407
|
+
}
|
|
1408
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1409
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1410
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1411
|
+
const page = await pdfDoc.getPage(currentPage);
|
|
1412
|
+
const containerWidth = container.clientWidth || 900;
|
|
1413
|
+
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1414
|
+
const baseScale = Math.min((containerWidth - 64) / unscaledVp.width, 1.6);
|
|
1415
|
+
const effectiveScale = (baseScale > 0 ? baseScale : 1) * zoomScale;
|
|
1416
|
+
const pixelRatio = window.devicePixelRatio || 1;
|
|
1417
|
+
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
1418
|
+
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1419
|
+
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1420
|
+
canvas.style.width = `${Math.floor(viewport.width)}px`;
|
|
1421
|
+
canvas.style.height = `${Math.floor(viewport.height)}px`;
|
|
1422
|
+
const canvasCtx = canvas.getContext("2d");
|
|
1423
|
+
if (!canvasCtx) return;
|
|
1424
|
+
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
1425
|
+
currentRenderTask = page.render({
|
|
1426
|
+
canvasContext: canvasCtx,
|
|
1427
|
+
viewport
|
|
1428
|
+
});
|
|
1429
|
+
try {
|
|
1430
|
+
await currentRenderTask.promise;
|
|
1431
|
+
} catch (err) {
|
|
1432
|
+
if (err?.name !== "RenderingCancelledException") {
|
|
1433
|
+
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1434
|
+
}
|
|
1435
|
+
} finally {
|
|
1436
|
+
currentRenderTask = null;
|
|
1437
|
+
}
|
|
1438
|
+
};
|
|
1439
|
+
await renderPage(1);
|
|
1327
1440
|
const cleanup = () => {
|
|
1328
|
-
|
|
1329
|
-
|
|
1441
|
+
if (currentRenderTask) {
|
|
1442
|
+
try {
|
|
1443
|
+
currentRenderTask.cancel();
|
|
1444
|
+
} catch {
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
try {
|
|
1448
|
+
pdfDoc.destroy();
|
|
1449
|
+
} catch {
|
|
1450
|
+
}
|
|
1451
|
+
container.remove();
|
|
1330
1452
|
ctx.container.innerHTML = "";
|
|
1331
1453
|
};
|
|
1332
1454
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1333
|
-
|
|
1455
|
+
const instance = {
|
|
1334
1456
|
destroy: cleanup,
|
|
1335
1457
|
zoomIn: () => {
|
|
1336
|
-
|
|
1337
|
-
|
|
1458
|
+
zoomScale = Math.min(3.5, zoomScale + 0.2);
|
|
1459
|
+
renderPage(currentPage);
|
|
1338
1460
|
},
|
|
1339
1461
|
zoomOut: () => {
|
|
1340
|
-
|
|
1341
|
-
|
|
1462
|
+
zoomScale = Math.max(0.3, zoomScale - 0.2);
|
|
1463
|
+
renderPage(currentPage);
|
|
1342
1464
|
},
|
|
1343
|
-
getZoom: () =>
|
|
1465
|
+
getZoom: () => zoomScale,
|
|
1344
1466
|
setZoom: (level) => {
|
|
1345
|
-
|
|
1346
|
-
|
|
1467
|
+
zoomScale = Math.max(0.3, Math.min(3.5, level));
|
|
1468
|
+
renderPage(currentPage);
|
|
1347
1469
|
},
|
|
1348
1470
|
fitToPage: () => {
|
|
1349
|
-
|
|
1350
|
-
|
|
1471
|
+
zoomScale = 1;
|
|
1472
|
+
renderPage(currentPage);
|
|
1351
1473
|
},
|
|
1352
1474
|
rotateCW: () => {
|
|
1353
1475
|
rotation = (rotation + 90) % 360;
|
|
1354
|
-
|
|
1476
|
+
renderPage(currentPage);
|
|
1355
1477
|
},
|
|
1356
1478
|
rotateCCW: () => {
|
|
1357
1479
|
rotation = (rotation - 90 + 360) % 360;
|
|
1358
|
-
|
|
1480
|
+
renderPage(currentPage);
|
|
1359
1481
|
},
|
|
1360
1482
|
getRotation: () => rotation,
|
|
1483
|
+
getPageCount: () => totalPages,
|
|
1484
|
+
getCurrentPage: () => currentPage,
|
|
1361
1485
|
goToPage: (page) => {
|
|
1362
|
-
|
|
1363
|
-
iframe.src = `${url}#page=${page}`;
|
|
1486
|
+
renderPage(page);
|
|
1364
1487
|
},
|
|
1365
|
-
getCurrentPage: () => currentPage,
|
|
1366
1488
|
download: () => {
|
|
1489
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1490
|
+
const url = URL.createObjectURL(blob);
|
|
1367
1491
|
const a = document.createElement("a");
|
|
1368
1492
|
a.href = url;
|
|
1369
1493
|
a.download = ctx.metadata.name || "document.pdf";
|
|
1370
1494
|
a.click();
|
|
1495
|
+
URL.revokeObjectURL(url);
|
|
1371
1496
|
},
|
|
1372
1497
|
print: () => {
|
|
1373
|
-
|
|
1498
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1499
|
+
const url = URL.createObjectURL(blob);
|
|
1500
|
+
const hiddenIframe = document.createElement("iframe");
|
|
1501
|
+
hiddenIframe.style.position = "fixed";
|
|
1502
|
+
hiddenIframe.style.right = "0";
|
|
1503
|
+
hiddenIframe.style.bottom = "0";
|
|
1504
|
+
hiddenIframe.style.width = "0";
|
|
1505
|
+
hiddenIframe.style.height = "0";
|
|
1506
|
+
hiddenIframe.style.border = "0";
|
|
1507
|
+
document.body.appendChild(hiddenIframe);
|
|
1508
|
+
hiddenIframe.src = url;
|
|
1509
|
+
hiddenIframe.onload = () => {
|
|
1510
|
+
setTimeout(() => {
|
|
1511
|
+
hiddenIframe.contentWindow?.print();
|
|
1512
|
+
setTimeout(() => {
|
|
1513
|
+
hiddenIframe.remove();
|
|
1514
|
+
URL.revokeObjectURL(url);
|
|
1515
|
+
}, 1e3);
|
|
1516
|
+
}, 300);
|
|
1517
|
+
};
|
|
1374
1518
|
},
|
|
1375
1519
|
getThumbnails: async () => {
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1520
|
+
const thumbnails = [];
|
|
1521
|
+
const count = Math.min(totalPages, 50);
|
|
1522
|
+
for (let i = 1; i <= count; i++) {
|
|
1523
|
+
thumbnails.push({
|
|
1524
|
+
index: i,
|
|
1525
|
+
label: `Page ${i}`,
|
|
1526
|
+
render: async (thumbCanvas) => {
|
|
1527
|
+
try {
|
|
1528
|
+
const p = await pdfDoc.getPage(i);
|
|
1529
|
+
const baseVp = p.getViewport({ scale: 1 });
|
|
1530
|
+
const thumbScale = (thumbCanvas.width || 120) / baseVp.width;
|
|
1531
|
+
const thumbVp = p.getViewport({ scale: thumbScale });
|
|
1532
|
+
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1533
|
+
const tCtx = thumbCanvas.getContext("2d");
|
|
1534
|
+
if (tCtx) {
|
|
1535
|
+
await p.render({ canvasContext: tCtx, viewport: thumbVp }).promise;
|
|
1536
|
+
}
|
|
1537
|
+
} catch (e) {
|
|
1538
|
+
console.warn(`[PdfPlugin] Error generating thumbnail for page ${i}:`, e);
|
|
1388
1539
|
}
|
|
1389
1540
|
}
|
|
1390
|
-
}
|
|
1391
|
-
|
|
1541
|
+
});
|
|
1542
|
+
}
|
|
1543
|
+
return thumbnails;
|
|
1392
1544
|
}
|
|
1393
1545
|
};
|
|
1546
|
+
return instance;
|
|
1394
1547
|
}
|
|
1395
1548
|
};
|
|
1396
1549
|
function pdfPlugin() {
|
|
@@ -1717,7 +1870,31 @@ var DocxPlugin = class {
|
|
|
1717
1870
|
return this.mimeTypes.includes(mime || "");
|
|
1718
1871
|
}
|
|
1719
1872
|
getToolbarActions(instance) {
|
|
1720
|
-
|
|
1873
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1874
|
+
const actions = [];
|
|
1875
|
+
if (totalPages > 1) {
|
|
1876
|
+
actions.push({
|
|
1877
|
+
id: "page-nav",
|
|
1878
|
+
icon: "",
|
|
1879
|
+
label: "Page Navigation",
|
|
1880
|
+
type: "page-nav",
|
|
1881
|
+
group: "navigation",
|
|
1882
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
1883
|
+
max: totalPages,
|
|
1884
|
+
execute: (action, page) => {
|
|
1885
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1886
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1887
|
+
if (action === "prev") {
|
|
1888
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1889
|
+
} else if (action === "next") {
|
|
1890
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1891
|
+
} else if (typeof page === "number") {
|
|
1892
|
+
instance.goToPage?.(page);
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
});
|
|
1896
|
+
}
|
|
1897
|
+
actions.push(
|
|
1721
1898
|
{
|
|
1722
1899
|
id: "zoom-out",
|
|
1723
1900
|
icon: "zoom-out",
|
|
@@ -1758,7 +1935,8 @@ var DocxPlugin = class {
|
|
|
1758
1935
|
group: "actions",
|
|
1759
1936
|
execute: () => instance.print?.()
|
|
1760
1937
|
}
|
|
1761
|
-
|
|
1938
|
+
);
|
|
1939
|
+
return actions;
|
|
1762
1940
|
}
|
|
1763
1941
|
async render(ctx) {
|
|
1764
1942
|
const wrapper = document.createElement("div");
|
|
@@ -1834,7 +2012,51 @@ var DocxPlugin = class {
|
|
|
1834
2012
|
}
|
|
1835
2013
|
}
|
|
1836
2014
|
}
|
|
2015
|
+
const sections = wrapper.querySelectorAll("section.docx");
|
|
2016
|
+
const cards = wrapper.querySelectorAll(".fp-docx-page-card");
|
|
2017
|
+
const pageElements = sections.length > 0 ? sections : cards;
|
|
2018
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
2019
|
+
let currentPage = 1;
|
|
2020
|
+
let indicator = null;
|
|
2021
|
+
if (totalPages > 1) {
|
|
2022
|
+
indicator = document.createElement("div");
|
|
2023
|
+
indicator.className = "fp-docx-page-indicator";
|
|
2024
|
+
indicator.style.position = "sticky";
|
|
2025
|
+
indicator.style.bottom = "16px";
|
|
2026
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2027
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
2028
|
+
indicator.style.color = "#f8fafc";
|
|
2029
|
+
indicator.style.fontSize = "12px";
|
|
2030
|
+
indicator.style.fontWeight = "600";
|
|
2031
|
+
indicator.style.padding = "5px 14px";
|
|
2032
|
+
indicator.style.borderRadius = "20px";
|
|
2033
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2034
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2035
|
+
indicator.style.zIndex = "10";
|
|
2036
|
+
indicator.style.userSelect = "none";
|
|
2037
|
+
indicator.style.pointerEvents = "none";
|
|
2038
|
+
indicator.style.textAlign = "center";
|
|
2039
|
+
indicator.style.width = "fit-content";
|
|
2040
|
+
indicator.style.margin = "16px auto 0";
|
|
2041
|
+
ctx.container.appendChild(indicator);
|
|
2042
|
+
}
|
|
2043
|
+
const showPage = (pageNum) => {
|
|
2044
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2045
|
+
if (pageElements.length > 1) {
|
|
2046
|
+
pageElements.forEach((sec, idx) => {
|
|
2047
|
+
sec.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
2048
|
+
});
|
|
2049
|
+
}
|
|
2050
|
+
if (indicator) {
|
|
2051
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2052
|
+
}
|
|
2053
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2054
|
+
};
|
|
2055
|
+
if (totalPages > 1) {
|
|
2056
|
+
showPage(1);
|
|
2057
|
+
}
|
|
1837
2058
|
const cleanup = () => {
|
|
2059
|
+
indicator?.remove();
|
|
1838
2060
|
for (const url of createdBlobUrls) {
|
|
1839
2061
|
URL.revokeObjectURL(url);
|
|
1840
2062
|
}
|
|
@@ -1845,6 +2067,11 @@ var DocxPlugin = class {
|
|
|
1845
2067
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1846
2068
|
return {
|
|
1847
2069
|
destroy: cleanup,
|
|
2070
|
+
getPageCount: () => totalPages,
|
|
2071
|
+
getCurrentPage: () => currentPage,
|
|
2072
|
+
goToPage: (page) => {
|
|
2073
|
+
showPage(page);
|
|
2074
|
+
},
|
|
1848
2075
|
zoomIn: () => {
|
|
1849
2076
|
scale += 0.1;
|
|
1850
2077
|
wrapper.style.transform = `scale(${scale})`;
|
|
@@ -2109,7 +2336,31 @@ var ExcelPlugin = class {
|
|
|
2109
2336
|
return this.mimeTypes.includes(mime || "");
|
|
2110
2337
|
}
|
|
2111
2338
|
getToolbarActions(instance) {
|
|
2112
|
-
|
|
2339
|
+
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2340
|
+
const actions = [];
|
|
2341
|
+
if (totalSheets > 1) {
|
|
2342
|
+
actions.push({
|
|
2343
|
+
id: "page-nav",
|
|
2344
|
+
icon: "",
|
|
2345
|
+
label: "Sheet Navigation",
|
|
2346
|
+
type: "page-nav",
|
|
2347
|
+
group: "navigation",
|
|
2348
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2349
|
+
max: totalSheets,
|
|
2350
|
+
execute: (action, sheet) => {
|
|
2351
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2352
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2353
|
+
if (action === "prev") {
|
|
2354
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2355
|
+
} else if (action === "next") {
|
|
2356
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2357
|
+
} else if (typeof sheet === "number") {
|
|
2358
|
+
instance.goToPage?.(sheet);
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
});
|
|
2362
|
+
}
|
|
2363
|
+
actions.push(
|
|
2113
2364
|
{
|
|
2114
2365
|
id: "zoom-out",
|
|
2115
2366
|
icon: "zoom-out",
|
|
@@ -2130,16 +2381,6 @@ var ExcelPlugin = class {
|
|
|
2130
2381
|
instance.zoomIn?.();
|
|
2131
2382
|
}
|
|
2132
2383
|
},
|
|
2133
|
-
{
|
|
2134
|
-
id: "page-nav",
|
|
2135
|
-
icon: "page-nav",
|
|
2136
|
-
label: "Sheet Navigation",
|
|
2137
|
-
type: "page-nav",
|
|
2138
|
-
group: "navigation",
|
|
2139
|
-
execute: (sheet) => {
|
|
2140
|
-
if (typeof sheet === "number") instance.goToPage?.(sheet);
|
|
2141
|
-
}
|
|
2142
|
-
},
|
|
2143
2384
|
{
|
|
2144
2385
|
id: "download",
|
|
2145
2386
|
icon: "download",
|
|
@@ -2160,7 +2401,8 @@ var ExcelPlugin = class {
|
|
|
2160
2401
|
instance.print?.();
|
|
2161
2402
|
}
|
|
2162
2403
|
}
|
|
2163
|
-
|
|
2404
|
+
);
|
|
2405
|
+
return actions;
|
|
2164
2406
|
}
|
|
2165
2407
|
async render(ctx) {
|
|
2166
2408
|
const container = document.createElement("div");
|
|
@@ -2244,6 +2486,7 @@ var ExcelPlugin = class {
|
|
|
2244
2486
|
b.style.fontWeight = "normal";
|
|
2245
2487
|
}
|
|
2246
2488
|
});
|
|
2489
|
+
ctx.emit("page-change", { page: currentSheetIndex, total: sheetNames.length });
|
|
2247
2490
|
};
|
|
2248
2491
|
if (sheetNames.length > 0) {
|
|
2249
2492
|
sheetNames.forEach((name, idx) => {
|
|
@@ -2493,7 +2736,31 @@ var CodePlugin = class {
|
|
|
2493
2736
|
return false;
|
|
2494
2737
|
}
|
|
2495
2738
|
getToolbarActions(instance) {
|
|
2496
|
-
|
|
2739
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2740
|
+
const actions = [];
|
|
2741
|
+
if (totalPages > 1) {
|
|
2742
|
+
actions.push({
|
|
2743
|
+
id: "page-nav",
|
|
2744
|
+
icon: "",
|
|
2745
|
+
label: "Page Navigation",
|
|
2746
|
+
type: "page-nav",
|
|
2747
|
+
group: "navigation",
|
|
2748
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2749
|
+
max: totalPages,
|
|
2750
|
+
execute: (action, page) => {
|
|
2751
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2752
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2753
|
+
if (action === "prev") {
|
|
2754
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2755
|
+
} else if (action === "next") {
|
|
2756
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2757
|
+
} else if (typeof page === "number") {
|
|
2758
|
+
instance.goToPage?.(page);
|
|
2759
|
+
}
|
|
2760
|
+
}
|
|
2761
|
+
});
|
|
2762
|
+
}
|
|
2763
|
+
actions.push(
|
|
2497
2764
|
{
|
|
2498
2765
|
id: "zoom-out",
|
|
2499
2766
|
icon: "zoom-out",
|
|
@@ -2544,11 +2811,16 @@ var CodePlugin = class {
|
|
|
2544
2811
|
instance.print?.();
|
|
2545
2812
|
}
|
|
2546
2813
|
}
|
|
2547
|
-
|
|
2814
|
+
);
|
|
2815
|
+
return actions;
|
|
2548
2816
|
}
|
|
2549
2817
|
async render(ctx) {
|
|
2550
2818
|
const decoder = new TextDecoder("utf-8");
|
|
2551
|
-
const
|
|
2819
|
+
const fullText = decoder.decode(ctx.buffer);
|
|
2820
|
+
const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
|
|
2821
|
+
const rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
2822
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
2823
|
+
let currentPage = 1;
|
|
2552
2824
|
const container = document.createElement("div");
|
|
2553
2825
|
container.style.width = "100%";
|
|
2554
2826
|
container.style.height = "100%";
|
|
@@ -2567,25 +2839,66 @@ var CodePlugin = class {
|
|
|
2567
2839
|
pre.style.wordBreak = "break-all";
|
|
2568
2840
|
const code = document.createElement("code");
|
|
2569
2841
|
const ext = (ctx.metadata.extension || "").replace(".", "");
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2842
|
+
const renderCodePage = (text) => {
|
|
2843
|
+
try {
|
|
2844
|
+
if (ext && hljs.getLanguage(ext)) {
|
|
2845
|
+
code.innerHTML = hljs.highlight(text, { language: ext }).value;
|
|
2846
|
+
} else {
|
|
2847
|
+
code.innerHTML = hljs.highlightAuto(text).value;
|
|
2848
|
+
}
|
|
2849
|
+
} catch {
|
|
2850
|
+
code.textContent = text;
|
|
2575
2851
|
}
|
|
2576
|
-
}
|
|
2577
|
-
|
|
2578
|
-
}
|
|
2852
|
+
};
|
|
2853
|
+
renderCodePage(rawPages[0] || fullText);
|
|
2579
2854
|
pre.appendChild(code);
|
|
2580
2855
|
container.appendChild(pre);
|
|
2856
|
+
let indicator = null;
|
|
2857
|
+
if (totalPages > 1) {
|
|
2858
|
+
indicator = document.createElement("div");
|
|
2859
|
+
indicator.className = "fp-code-page-indicator";
|
|
2860
|
+
indicator.style.position = "sticky";
|
|
2861
|
+
indicator.style.bottom = "16px";
|
|
2862
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2863
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
2864
|
+
indicator.style.color = "#f8fafc";
|
|
2865
|
+
indicator.style.fontSize = "12px";
|
|
2866
|
+
indicator.style.fontWeight = "600";
|
|
2867
|
+
indicator.style.padding = "5px 14px";
|
|
2868
|
+
indicator.style.borderRadius = "20px";
|
|
2869
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2870
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2871
|
+
indicator.style.zIndex = "10";
|
|
2872
|
+
indicator.style.userSelect = "none";
|
|
2873
|
+
indicator.style.pointerEvents = "none";
|
|
2874
|
+
indicator.style.textAlign = "center";
|
|
2875
|
+
indicator.style.width = "fit-content";
|
|
2876
|
+
indicator.style.margin = "16px auto 0";
|
|
2877
|
+
container.appendChild(indicator);
|
|
2878
|
+
}
|
|
2879
|
+
const showPage = (pageNum) => {
|
|
2880
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2881
|
+
renderCodePage(rawPages[currentPage - 1] || fullText);
|
|
2882
|
+
if (indicator) {
|
|
2883
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2884
|
+
}
|
|
2885
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2886
|
+
};
|
|
2887
|
+
if (totalPages > 1) {
|
|
2888
|
+
showPage(1);
|
|
2889
|
+
}
|
|
2581
2890
|
ctx.container.appendChild(container);
|
|
2582
2891
|
const cleanup = () => {
|
|
2892
|
+
indicator?.remove();
|
|
2583
2893
|
container.remove();
|
|
2584
2894
|
ctx.container.innerHTML = "";
|
|
2585
2895
|
};
|
|
2586
2896
|
ctx.signal.addEventListener("abort", cleanup);
|
|
2587
2897
|
return {
|
|
2588
2898
|
destroy: cleanup,
|
|
2899
|
+
getPageCount: () => totalPages,
|
|
2900
|
+
getCurrentPage: () => currentPage,
|
|
2901
|
+
goToPage: (page) => showPage(page),
|
|
2589
2902
|
zoomIn: () => {
|
|
2590
2903
|
fontSize = Math.min(32, fontSize + 2);
|
|
2591
2904
|
pre.style.fontSize = `${fontSize}px`;
|
|
@@ -2613,7 +2926,7 @@ var CodePlugin = class {
|
|
|
2613
2926
|
window.print();
|
|
2614
2927
|
},
|
|
2615
2928
|
copy: () => {
|
|
2616
|
-
navigator.clipboard?.writeText(
|
|
2929
|
+
navigator.clipboard?.writeText(fullText);
|
|
2617
2930
|
}
|
|
2618
2931
|
};
|
|
2619
2932
|
}
|
|
@@ -3435,7 +3748,31 @@ var RtfPlugin = class {
|
|
|
3435
3748
|
return this.extensions.includes(ext || "") || this.mimeTypes.includes(mime || "");
|
|
3436
3749
|
}
|
|
3437
3750
|
getToolbarActions(instance) {
|
|
3438
|
-
|
|
3751
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3752
|
+
const actions = [];
|
|
3753
|
+
if (totalPages > 1) {
|
|
3754
|
+
actions.push({
|
|
3755
|
+
id: "page-nav",
|
|
3756
|
+
icon: "",
|
|
3757
|
+
label: "Page Navigation",
|
|
3758
|
+
type: "page-nav",
|
|
3759
|
+
group: "navigation",
|
|
3760
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
3761
|
+
max: totalPages,
|
|
3762
|
+
execute: (action, page) => {
|
|
3763
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3764
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
3765
|
+
if (action === "prev") {
|
|
3766
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
3767
|
+
} else if (action === "next") {
|
|
3768
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
3769
|
+
} else if (typeof page === "number") {
|
|
3770
|
+
instance.goToPage?.(page);
|
|
3771
|
+
}
|
|
3772
|
+
}
|
|
3773
|
+
});
|
|
3774
|
+
}
|
|
3775
|
+
actions.push(
|
|
3439
3776
|
{
|
|
3440
3777
|
id: "zoom-out",
|
|
3441
3778
|
icon: "zoom-out",
|
|
@@ -3476,7 +3813,8 @@ var RtfPlugin = class {
|
|
|
3476
3813
|
group: "actions",
|
|
3477
3814
|
execute: () => instance.print?.()
|
|
3478
3815
|
}
|
|
3479
|
-
|
|
3816
|
+
);
|
|
3817
|
+
return actions;
|
|
3480
3818
|
}
|
|
3481
3819
|
async render(ctx) {
|
|
3482
3820
|
const wrapper = document.createElement("div");
|
|
@@ -3495,28 +3833,82 @@ var RtfPlugin = class {
|
|
|
3495
3833
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
3496
3834
|
ctx.container.appendChild(wrapper);
|
|
3497
3835
|
let scale = 1;
|
|
3836
|
+
let pageElements = [];
|
|
3498
3837
|
try {
|
|
3499
3838
|
if (typeof RTFJS.loggingEnabled === "function") {
|
|
3500
3839
|
RTFJS.loggingEnabled(false);
|
|
3501
3840
|
}
|
|
3502
3841
|
const doc = new RTFJS.Document(ctx.buffer, {});
|
|
3503
3842
|
const htmlElements = await doc.render();
|
|
3504
|
-
|
|
3843
|
+
pageElements = htmlElements;
|
|
3844
|
+
for (let i = 0; i < htmlElements.length; i++) {
|
|
3845
|
+
const el = htmlElements[i];
|
|
3846
|
+
el.style.display = i === 0 ? "block" : "none";
|
|
3505
3847
|
wrapper.appendChild(el);
|
|
3506
3848
|
}
|
|
3507
3849
|
} catch (err) {
|
|
3508
3850
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
3509
3851
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
3510
3852
|
const clean = text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "");
|
|
3511
|
-
|
|
3853
|
+
const pre = document.createElement("pre");
|
|
3854
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3855
|
+
pre.style.fontFamily = "serif";
|
|
3856
|
+
pre.style.color = "#333";
|
|
3857
|
+
pre.textContent = clean;
|
|
3858
|
+
wrapper.appendChild(pre);
|
|
3859
|
+
pageElements = [pre];
|
|
3860
|
+
}
|
|
3861
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
3862
|
+
let currentPage = 1;
|
|
3863
|
+
let indicator = null;
|
|
3864
|
+
if (totalPages > 1) {
|
|
3865
|
+
indicator = document.createElement("div");
|
|
3866
|
+
indicator.className = "fp-rtf-page-indicator";
|
|
3867
|
+
indicator.style.position = "sticky";
|
|
3868
|
+
indicator.style.bottom = "16px";
|
|
3869
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3870
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
3871
|
+
indicator.style.color = "#f8fafc";
|
|
3872
|
+
indicator.style.fontSize = "12px";
|
|
3873
|
+
indicator.style.fontWeight = "600";
|
|
3874
|
+
indicator.style.padding = "5px 14px";
|
|
3875
|
+
indicator.style.borderRadius = "20px";
|
|
3876
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3877
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3878
|
+
indicator.style.zIndex = "10";
|
|
3879
|
+
indicator.style.userSelect = "none";
|
|
3880
|
+
indicator.style.pointerEvents = "none";
|
|
3881
|
+
indicator.style.textAlign = "center";
|
|
3882
|
+
indicator.style.width = "fit-content";
|
|
3883
|
+
indicator.style.margin = "16px auto 0";
|
|
3884
|
+
ctx.container.appendChild(indicator);
|
|
3885
|
+
}
|
|
3886
|
+
const showPage = (pageNum) => {
|
|
3887
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3888
|
+
if (totalPages > 1) {
|
|
3889
|
+
pageElements.forEach((el, idx) => {
|
|
3890
|
+
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
3891
|
+
});
|
|
3892
|
+
}
|
|
3893
|
+
if (indicator) {
|
|
3894
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3895
|
+
}
|
|
3896
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3897
|
+
};
|
|
3898
|
+
if (totalPages > 1) {
|
|
3899
|
+
showPage(1);
|
|
3512
3900
|
}
|
|
3513
3901
|
const cleanup = () => {
|
|
3902
|
+
indicator?.remove();
|
|
3514
3903
|
wrapper.remove();
|
|
3515
3904
|
ctx.container.innerHTML = "";
|
|
3516
3905
|
};
|
|
3517
3906
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3518
3907
|
return {
|
|
3519
3908
|
destroy: cleanup,
|
|
3909
|
+
getPageCount: () => totalPages,
|
|
3910
|
+
getCurrentPage: () => currentPage,
|
|
3911
|
+
goToPage: (page) => showPage(page),
|
|
3520
3912
|
zoomIn: () => {
|
|
3521
3913
|
scale += 0.1;
|
|
3522
3914
|
wrapper.style.transform = `scale(${scale})`;
|
|
@@ -3704,41 +4096,41 @@ var OpenDocumentPlugin = class {
|
|
|
3704
4096
|
}
|
|
3705
4097
|
getToolbarActions(instance) {
|
|
3706
4098
|
const isPresentation = instance.isPresentation;
|
|
4099
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3707
4100
|
const actions = [];
|
|
3708
|
-
if (isPresentation) {
|
|
3709
|
-
|
|
3710
|
-
{
|
|
4101
|
+
if (isPresentation || totalPages > 1) {
|
|
4102
|
+
if (isPresentation) {
|
|
4103
|
+
actions.push({
|
|
3711
4104
|
id: "thumbnails",
|
|
3712
4105
|
icon: "thumbnails",
|
|
3713
4106
|
label: "Slide Thumbnails",
|
|
3714
4107
|
type: "button",
|
|
3715
4108
|
group: "navigation",
|
|
3716
4109
|
execute: () => instance.toggleThumbnails?.()
|
|
3717
|
-
}
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
}
|
|
4110
|
+
});
|
|
4111
|
+
}
|
|
4112
|
+
actions.push({
|
|
4113
|
+
id: "page-nav",
|
|
4114
|
+
icon: "",
|
|
4115
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
4116
|
+
type: "page-nav",
|
|
4117
|
+
group: "navigation",
|
|
4118
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4119
|
+
max: totalPages,
|
|
4120
|
+
execute: (action, page) => {
|
|
4121
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4122
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4123
|
+
if (action === "prev") {
|
|
4124
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4125
|
+
} else if (action === "next") {
|
|
4126
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4127
|
+
} else if (typeof page === "number") {
|
|
4128
|
+
instance.goToPage?.(page);
|
|
4129
|
+
} else if (typeof action === "number") {
|
|
4130
|
+
instance.goToPage?.(action);
|
|
3739
4131
|
}
|
|
3740
4132
|
}
|
|
3741
|
-
);
|
|
4133
|
+
});
|
|
3742
4134
|
}
|
|
3743
4135
|
actions.push(
|
|
3744
4136
|
{
|
|
@@ -4121,7 +4513,31 @@ var DocPlugin = class {
|
|
|
4121
4513
|
return this.mimeTypes.includes(mime || "");
|
|
4122
4514
|
}
|
|
4123
4515
|
getToolbarActions(instance) {
|
|
4124
|
-
|
|
4516
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4517
|
+
const actions = [];
|
|
4518
|
+
if (totalPages > 1) {
|
|
4519
|
+
actions.push({
|
|
4520
|
+
id: "page-nav",
|
|
4521
|
+
icon: "",
|
|
4522
|
+
label: "Page Navigation",
|
|
4523
|
+
type: "page-nav",
|
|
4524
|
+
group: "navigation",
|
|
4525
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4526
|
+
max: totalPages,
|
|
4527
|
+
execute: (action, page) => {
|
|
4528
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4529
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4530
|
+
if (action === "prev") {
|
|
4531
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4532
|
+
} else if (action === "next") {
|
|
4533
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4534
|
+
} else if (typeof page === "number") {
|
|
4535
|
+
instance.goToPage?.(page);
|
|
4536
|
+
}
|
|
4537
|
+
}
|
|
4538
|
+
});
|
|
4539
|
+
}
|
|
4540
|
+
actions.push(
|
|
4125
4541
|
{
|
|
4126
4542
|
id: "zoom-out",
|
|
4127
4543
|
icon: "zoom-out",
|
|
@@ -4170,7 +4586,8 @@ var DocPlugin = class {
|
|
|
4170
4586
|
group: "actions",
|
|
4171
4587
|
execute: () => instance.print?.()
|
|
4172
4588
|
}
|
|
4173
|
-
|
|
4589
|
+
);
|
|
4590
|
+
return actions;
|
|
4174
4591
|
}
|
|
4175
4592
|
async render(ctx) {
|
|
4176
4593
|
const container = document.createElement("div");
|
|
@@ -4197,6 +4614,7 @@ var DocPlugin = class {
|
|
|
4197
4614
|
ctx.container.appendChild(container);
|
|
4198
4615
|
let scale = 1;
|
|
4199
4616
|
let extractedRawText = "";
|
|
4617
|
+
let isFallback = false;
|
|
4200
4618
|
try {
|
|
4201
4619
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4202
4620
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
@@ -4210,26 +4628,89 @@ var DocPlugin = class {
|
|
|
4210
4628
|
const tableStream = cfbf.readStream(tableName);
|
|
4211
4629
|
const text = this.extractDocText(wordDocStream, tableStream);
|
|
4212
4630
|
extractedRawText = text;
|
|
4213
|
-
wrapper.innerHTML = this.formatDocToHtml(text, ctx.metadata.name || "Document");
|
|
4214
4631
|
} catch (err) {
|
|
4215
4632
|
console.warn("[DocPlugin] Binary parsing error, fallback text:", err);
|
|
4216
4633
|
const fallback = this.heuristicTextExtraction(ctx.buffer);
|
|
4217
4634
|
extractedRawText = fallback;
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4635
|
+
isFallback = true;
|
|
4636
|
+
}
|
|
4637
|
+
const rawPages = this.splitIntoPages(extractedRawText);
|
|
4638
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
4639
|
+
let currentPage = 1;
|
|
4640
|
+
wrapper.innerHTML = "";
|
|
4641
|
+
const pageCards = [];
|
|
4642
|
+
for (let i = 0; i < totalPages; i++) {
|
|
4643
|
+
const pageCard = document.createElement("div");
|
|
4644
|
+
pageCard.className = "fp-doc-page-card";
|
|
4645
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
4646
|
+
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4647
|
+
pageCard.style.borderRadius = "4px";
|
|
4648
|
+
pageCard.style.padding = "56px 48px";
|
|
4649
|
+
pageCard.style.minHeight = "100%";
|
|
4650
|
+
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4651
|
+
if (isFallback && i === 0) {
|
|
4652
|
+
pageCard.innerHTML = `
|
|
4653
|
+
<div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
|
|
4654
|
+
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify2.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
|
|
4655
|
+
<span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
|
|
4656
|
+
</div>
|
|
4657
|
+
${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
|
|
4658
|
+
`;
|
|
4659
|
+
} else {
|
|
4660
|
+
pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
|
|
4661
|
+
}
|
|
4662
|
+
wrapper.appendChild(pageCard);
|
|
4663
|
+
pageCards.push(pageCard);
|
|
4664
|
+
}
|
|
4665
|
+
let indicator = null;
|
|
4666
|
+
if (totalPages > 1) {
|
|
4667
|
+
indicator = document.createElement("div");
|
|
4668
|
+
indicator.className = "fp-doc-page-indicator";
|
|
4669
|
+
indicator.style.position = "sticky";
|
|
4670
|
+
indicator.style.bottom = "16px";
|
|
4671
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4672
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
4673
|
+
indicator.style.color = "#f8fafc";
|
|
4674
|
+
indicator.style.fontSize = "12px";
|
|
4675
|
+
indicator.style.fontWeight = "600";
|
|
4676
|
+
indicator.style.padding = "5px 14px";
|
|
4677
|
+
indicator.style.borderRadius = "20px";
|
|
4678
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4679
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4680
|
+
indicator.style.zIndex = "10";
|
|
4681
|
+
indicator.style.userSelect = "none";
|
|
4682
|
+
indicator.style.pointerEvents = "none";
|
|
4683
|
+
indicator.style.textAlign = "center";
|
|
4684
|
+
indicator.style.width = "fit-content";
|
|
4685
|
+
indicator.style.margin = "16px auto 0";
|
|
4686
|
+
container.appendChild(indicator);
|
|
4687
|
+
}
|
|
4688
|
+
const showPage = (pageNum) => {
|
|
4689
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4690
|
+
if (totalPages > 1) {
|
|
4691
|
+
pageCards.forEach((card, idx) => {
|
|
4692
|
+
card.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4693
|
+
});
|
|
4694
|
+
}
|
|
4695
|
+
if (indicator) {
|
|
4696
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4697
|
+
}
|
|
4698
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4699
|
+
};
|
|
4700
|
+
if (totalPages > 1) {
|
|
4701
|
+
showPage(1);
|
|
4225
4702
|
}
|
|
4226
4703
|
const cleanup = () => {
|
|
4704
|
+
indicator?.remove();
|
|
4227
4705
|
container.remove();
|
|
4228
4706
|
ctx.container.innerHTML = "";
|
|
4229
4707
|
};
|
|
4230
4708
|
ctx.signal.addEventListener("abort", cleanup);
|
|
4231
4709
|
return {
|
|
4232
4710
|
destroy: cleanup,
|
|
4711
|
+
getPageCount: () => totalPages,
|
|
4712
|
+
getCurrentPage: () => currentPage,
|
|
4713
|
+
goToPage: (page) => showPage(page),
|
|
4233
4714
|
zoomIn: () => {
|
|
4234
4715
|
scale += 0.1;
|
|
4235
4716
|
wrapper.style.transform = `scale(${scale})`;
|
|
@@ -4361,11 +4842,16 @@ var DocPlugin = class {
|
|
|
4361
4842
|
heuristicTextExtraction(buffer) {
|
|
4362
4843
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
4363
4844
|
}
|
|
4845
|
+
splitIntoPages(text) {
|
|
4846
|
+
if (!text) return [""];
|
|
4847
|
+
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);
|
|
4848
|
+
return parts.length > 0 ? parts : [text];
|
|
4849
|
+
}
|
|
4364
4850
|
/**
|
|
4365
4851
|
* Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
|
|
4366
4852
|
*/
|
|
4367
4853
|
formatDocToHtml(text, filename) {
|
|
4368
|
-
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").
|
|
4854
|
+
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
|
|
4369
4855
|
let html = "";
|
|
4370
4856
|
let inList = false;
|
|
4371
4857
|
for (const rawLine of lines) {
|