@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/react.cjs
CHANGED
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var react = require('react');
|
|
6
6
|
var DOMPurify2 = require('dompurify');
|
|
7
|
+
var pdfjsLib = require('pdfjs-dist');
|
|
7
8
|
var docx = require('docx-preview');
|
|
8
9
|
var fflate = require('fflate');
|
|
9
10
|
var XLSX = require('xlsx');
|
|
@@ -38,6 +39,7 @@ function _interopNamespace(e) {
|
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
var DOMPurify2__default = /*#__PURE__*/_interopDefault(DOMPurify2);
|
|
42
|
+
var pdfjsLib__namespace = /*#__PURE__*/_interopNamespace(pdfjsLib);
|
|
41
43
|
var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
|
|
42
44
|
var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
|
|
43
45
|
var hljs__default = /*#__PURE__*/_interopDefault(hljs);
|
|
@@ -511,11 +513,21 @@ var ToolbarController = class {
|
|
|
511
513
|
el;
|
|
512
514
|
toolbarEl;
|
|
513
515
|
actions = [];
|
|
516
|
+
pageInputEl = null;
|
|
517
|
+
pageLabelEl = null;
|
|
514
518
|
constructor(container) {
|
|
515
519
|
this.el = container;
|
|
516
520
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
517
521
|
this.el.appendChild(this.toolbarEl);
|
|
518
522
|
}
|
|
523
|
+
setPage(page, max) {
|
|
524
|
+
if (this.pageInputEl) {
|
|
525
|
+
this.pageInputEl.value = page.toString();
|
|
526
|
+
}
|
|
527
|
+
if (max !== void 0 && this.pageLabelEl) {
|
|
528
|
+
this.pageLabelEl.textContent = ` / ${max}`;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
519
531
|
update(actions) {
|
|
520
532
|
this.actions = actions;
|
|
521
533
|
this.render();
|
|
@@ -558,6 +570,7 @@ var ToolbarController = class {
|
|
|
558
570
|
if (action.type === "separator") {
|
|
559
571
|
groupEl.appendChild(createElement("div", { className: "fp-toolbar-separator" }));
|
|
560
572
|
} else if (action.type === "page-nav") {
|
|
573
|
+
const max = action.max ?? 1;
|
|
561
574
|
const prevBtn = this.createButton(
|
|
562
575
|
"prev",
|
|
563
576
|
ICON_PAGE_PREV,
|
|
@@ -576,7 +589,6 @@ var ToolbarController = class {
|
|
|
576
589
|
"Next Page",
|
|
577
590
|
() => {
|
|
578
591
|
const cur = parseInt(input.value, 10) || 1;
|
|
579
|
-
const max = action.max ?? 1;
|
|
580
592
|
if (cur < max) {
|
|
581
593
|
input.value = (cur + 1).toString();
|
|
582
594
|
action.execute("next", cur + 1);
|
|
@@ -588,15 +600,18 @@ var ToolbarController = class {
|
|
|
588
600
|
type: "number",
|
|
589
601
|
value: (action.value ?? 1).toString(),
|
|
590
602
|
min: "1",
|
|
591
|
-
max:
|
|
603
|
+
max: max.toString()
|
|
592
604
|
});
|
|
593
605
|
input.addEventListener("change", () => {
|
|
594
|
-
|
|
595
|
-
if (
|
|
596
|
-
|
|
597
|
-
|
|
606
|
+
let val = parseInt(input.value, 10);
|
|
607
|
+
if (isNaN(val)) val = 1;
|
|
608
|
+
val = Math.max(1, Math.min(max, val));
|
|
609
|
+
input.value = val.toString();
|
|
610
|
+
action.execute("go", val);
|
|
598
611
|
});
|
|
599
|
-
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${
|
|
612
|
+
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
613
|
+
this.pageInputEl = input;
|
|
614
|
+
this.pageLabelEl = label;
|
|
600
615
|
groupEl.appendChild(prevBtn);
|
|
601
616
|
groupEl.appendChild(input);
|
|
602
617
|
groupEl.appendChild(label);
|
|
@@ -774,7 +789,13 @@ var FilePreviewViewer = class {
|
|
|
774
789
|
buffer,
|
|
775
790
|
options,
|
|
776
791
|
signal,
|
|
777
|
-
emit: (event, payload) =>
|
|
792
|
+
emit: (event, payload) => {
|
|
793
|
+
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
794
|
+
const total = payload.total ?? payload.totalPages;
|
|
795
|
+
this.toolbar?.setPage(payload.page, total);
|
|
796
|
+
}
|
|
797
|
+
this.eventEmitter.emit(event, payload);
|
|
798
|
+
}
|
|
778
799
|
});
|
|
779
800
|
this.activeInstance = instance;
|
|
780
801
|
this.hideLoading();
|
|
@@ -808,6 +829,7 @@ var FilePreviewViewer = class {
|
|
|
808
829
|
if (thumbnails && thumbnails.length > 0 && this.thumbnailPanel) {
|
|
809
830
|
this.thumbnailPanel.update(thumbnails, (index) => {
|
|
810
831
|
instance.goToPage?.(index + 1);
|
|
832
|
+
this.toolbar?.setPage(index + 1);
|
|
811
833
|
});
|
|
812
834
|
if (options.showThumbnails) {
|
|
813
835
|
this.thumbnailPanel.show();
|
|
@@ -933,9 +955,13 @@ var FilePreviewViewer = class {
|
|
|
933
955
|
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
934
956
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
935
957
|
this.activeInstance.goToPage?.(cur + 1);
|
|
958
|
+
const nextCur = this.activeInstance.getCurrentPage?.() ?? cur + 1;
|
|
959
|
+
this.toolbar?.setPage(nextCur);
|
|
936
960
|
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
937
961
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
938
962
|
this.activeInstance.goToPage?.(Math.max(1, cur - 1));
|
|
963
|
+
const prevCur = this.activeInstance.getCurrentPage?.() ?? Math.max(1, cur - 1);
|
|
964
|
+
this.toolbar?.setPage(prevCur);
|
|
939
965
|
} else if (e.key === "+" || e.key === "=") {
|
|
940
966
|
this.activeInstance.zoomIn?.();
|
|
941
967
|
} else if (e.key === "-" || e.key === "_") {
|
|
@@ -1201,30 +1227,62 @@ var CfbfReader = class {
|
|
|
1201
1227
|
return result.subarray(0, targetSize);
|
|
1202
1228
|
}
|
|
1203
1229
|
};
|
|
1204
|
-
|
|
1205
|
-
|
|
1230
|
+
if (typeof window !== "undefined" && pdfjsLib__namespace.GlobalWorkerOptions) {
|
|
1231
|
+
if (!pdfjsLib__namespace.GlobalWorkerOptions.workerSrc) {
|
|
1232
|
+
pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/build/pdf.worker.min.mjs`;
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1206
1235
|
var PdfPlugin = class {
|
|
1207
1236
|
id = "pdf";
|
|
1208
|
-
name = "PDF Preview";
|
|
1237
|
+
name = "PDF Document Preview";
|
|
1209
1238
|
extensions = [".pdf"];
|
|
1210
1239
|
mimeTypes = ["application/pdf"];
|
|
1211
1240
|
weight = 100;
|
|
1212
1241
|
supports(file) {
|
|
1213
1242
|
const ext = file.metadata.extension?.toLowerCase();
|
|
1214
1243
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
1215
|
-
|
|
1244
|
+
if (ext) return this.extensions.includes(ext);
|
|
1245
|
+
return this.mimeTypes.includes(mime || "");
|
|
1216
1246
|
}
|
|
1217
1247
|
getToolbarActions(instance) {
|
|
1248
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1249
|
+
const curPage = instance.getCurrentPage?.() ?? 1;
|
|
1218
1250
|
return [
|
|
1251
|
+
{
|
|
1252
|
+
id: "thumbnails",
|
|
1253
|
+
icon: "thumbnails",
|
|
1254
|
+
label: "Page Thumbnails",
|
|
1255
|
+
type: "button",
|
|
1256
|
+
group: "navigation",
|
|
1257
|
+
execute: () => instance.toggleThumbnails?.()
|
|
1258
|
+
},
|
|
1259
|
+
{
|
|
1260
|
+
id: "page-nav",
|
|
1261
|
+
icon: "",
|
|
1262
|
+
label: "Page Navigation",
|
|
1263
|
+
type: "page-nav",
|
|
1264
|
+
group: "navigation",
|
|
1265
|
+
value: curPage,
|
|
1266
|
+
max: totalPages,
|
|
1267
|
+
execute: (action, page) => {
|
|
1268
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1269
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1270
|
+
if (action === "prev") {
|
|
1271
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1272
|
+
} else if (action === "next") {
|
|
1273
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1274
|
+
} else if (typeof page === "number") {
|
|
1275
|
+
instance.goToPage?.(page);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
},
|
|
1219
1279
|
{
|
|
1220
1280
|
id: "zoom-out",
|
|
1221
1281
|
icon: "zoom-out",
|
|
1222
1282
|
label: "Zoom Out",
|
|
1223
1283
|
type: "button",
|
|
1224
1284
|
group: "zoom",
|
|
1225
|
-
execute: () =>
|
|
1226
|
-
instance.zoomOut?.();
|
|
1227
|
-
}
|
|
1285
|
+
execute: () => instance.zoomOut?.()
|
|
1228
1286
|
},
|
|
1229
1287
|
{
|
|
1230
1288
|
id: "zoom-in",
|
|
@@ -1232,9 +1290,7 @@ var PdfPlugin = class {
|
|
|
1232
1290
|
label: "Zoom In",
|
|
1233
1291
|
type: "button",
|
|
1234
1292
|
group: "zoom",
|
|
1235
|
-
execute: () =>
|
|
1236
|
-
instance.zoomIn?.();
|
|
1237
|
-
}
|
|
1293
|
+
execute: () => instance.zoomIn?.()
|
|
1238
1294
|
},
|
|
1239
1295
|
{
|
|
1240
1296
|
id: "fit-page",
|
|
@@ -1242,39 +1298,23 @@ var PdfPlugin = class {
|
|
|
1242
1298
|
label: "Fit to Page",
|
|
1243
1299
|
type: "button",
|
|
1244
1300
|
group: "zoom",
|
|
1245
|
-
execute: () =>
|
|
1246
|
-
instance.fitToPage?.();
|
|
1247
|
-
}
|
|
1301
|
+
execute: () => instance.fitToPage?.()
|
|
1248
1302
|
},
|
|
1249
1303
|
{
|
|
1250
1304
|
id: "rotate-cw",
|
|
1251
1305
|
icon: "rotate-cw",
|
|
1252
|
-
label: "Rotate",
|
|
1306
|
+
label: "Rotate Clockwise",
|
|
1253
1307
|
type: "button",
|
|
1254
1308
|
group: "view",
|
|
1255
|
-
execute: () =>
|
|
1256
|
-
instance.rotateCW?.();
|
|
1257
|
-
}
|
|
1258
|
-
},
|
|
1259
|
-
{
|
|
1260
|
-
id: "page-nav",
|
|
1261
|
-
icon: "page-nav",
|
|
1262
|
-
label: "Page Navigation",
|
|
1263
|
-
type: "page-nav",
|
|
1264
|
-
group: "navigation",
|
|
1265
|
-
execute: (page) => {
|
|
1266
|
-
if (typeof page === "number") instance.goToPage?.(page);
|
|
1267
|
-
}
|
|
1309
|
+
execute: () => instance.rotateCW?.()
|
|
1268
1310
|
},
|
|
1269
1311
|
{
|
|
1270
1312
|
id: "download",
|
|
1271
1313
|
icon: "download",
|
|
1272
|
-
label: "Download",
|
|
1314
|
+
label: "Download PDF",
|
|
1273
1315
|
type: "button",
|
|
1274
1316
|
group: "actions",
|
|
1275
|
-
execute: () =>
|
|
1276
|
-
instance.download?.();
|
|
1277
|
-
}
|
|
1317
|
+
execute: () => instance.download?.()
|
|
1278
1318
|
},
|
|
1279
1319
|
{
|
|
1280
1320
|
id: "print",
|
|
@@ -1282,99 +1322,213 @@ var PdfPlugin = class {
|
|
|
1282
1322
|
label: "Print",
|
|
1283
1323
|
type: "button",
|
|
1284
1324
|
group: "actions",
|
|
1285
|
-
execute: () =>
|
|
1286
|
-
instance.print?.();
|
|
1287
|
-
}
|
|
1325
|
+
execute: () => instance.print?.()
|
|
1288
1326
|
}
|
|
1289
1327
|
];
|
|
1290
1328
|
}
|
|
1291
1329
|
async render(ctx) {
|
|
1292
|
-
const
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1330
|
+
const container = document.createElement("div");
|
|
1331
|
+
container.className = "fp-pdf-container";
|
|
1332
|
+
container.style.width = "100%";
|
|
1333
|
+
container.style.height = "100%";
|
|
1334
|
+
container.style.overflow = "auto";
|
|
1335
|
+
container.style.display = "flex";
|
|
1336
|
+
container.style.flexDirection = "column";
|
|
1337
|
+
container.style.alignItems = "center";
|
|
1338
|
+
container.style.padding = "24px 16px";
|
|
1339
|
+
container.style.backgroundColor = "#0f172a";
|
|
1340
|
+
container.style.boxSizing = "border-box";
|
|
1341
|
+
container.style.position = "relative";
|
|
1342
|
+
const pageCard = document.createElement("div");
|
|
1343
|
+
pageCard.className = "fp-pdf-page-card";
|
|
1344
|
+
pageCard.style.boxShadow = "0 10px 35px rgba(0, 0, 0, 0.5)";
|
|
1345
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
1346
|
+
pageCard.style.borderRadius = "4px";
|
|
1347
|
+
pageCard.style.overflow = "hidden";
|
|
1348
|
+
pageCard.style.lineHeight = "0";
|
|
1349
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
1350
|
+
pageCard.style.position = "relative";
|
|
1351
|
+
const canvas = document.createElement("canvas");
|
|
1352
|
+
pageCard.appendChild(canvas);
|
|
1353
|
+
container.appendChild(pageCard);
|
|
1354
|
+
const indicator = document.createElement("div");
|
|
1355
|
+
indicator.className = "fp-pdf-page-indicator";
|
|
1356
|
+
indicator.style.position = "sticky";
|
|
1357
|
+
indicator.style.bottom = "16px";
|
|
1358
|
+
indicator.style.marginTop = "16px";
|
|
1359
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1360
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
1361
|
+
indicator.style.color = "#f8fafc";
|
|
1362
|
+
indicator.style.fontSize = "12px";
|
|
1363
|
+
indicator.style.fontWeight = "600";
|
|
1364
|
+
indicator.style.padding = "5px 14px";
|
|
1365
|
+
indicator.style.borderRadius = "20px";
|
|
1366
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1367
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1368
|
+
indicator.style.zIndex = "10";
|
|
1369
|
+
indicator.style.userSelect = "none";
|
|
1370
|
+
indicator.style.pointerEvents = "none";
|
|
1371
|
+
container.appendChild(indicator);
|
|
1372
|
+
ctx.container.appendChild(container);
|
|
1373
|
+
const loadingTask = pdfjsLib__namespace.getDocument({
|
|
1374
|
+
data: new Uint8Array(ctx.buffer),
|
|
1375
|
+
cMapUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/cmaps/`,
|
|
1376
|
+
cMapPacked: true,
|
|
1377
|
+
standardFontDataUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/standard_fonts/`
|
|
1378
|
+
});
|
|
1379
|
+
const pdfDoc = await loadingTask.promise;
|
|
1380
|
+
const totalPages = Math.max(1, pdfDoc.numPages);
|
|
1308
1381
|
let currentPage = 1;
|
|
1309
|
-
let
|
|
1382
|
+
let zoomScale = 1;
|
|
1310
1383
|
let rotation = 0;
|
|
1384
|
+
let currentRenderTask = null;
|
|
1385
|
+
const renderPage = async (pageNum) => {
|
|
1386
|
+
if (currentRenderTask) {
|
|
1387
|
+
try {
|
|
1388
|
+
currentRenderTask.cancel();
|
|
1389
|
+
} catch {
|
|
1390
|
+
}
|
|
1391
|
+
currentRenderTask = null;
|
|
1392
|
+
}
|
|
1393
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1394
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1395
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1396
|
+
const page = await pdfDoc.getPage(currentPage);
|
|
1397
|
+
const containerWidth = container.clientWidth || 900;
|
|
1398
|
+
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1399
|
+
const baseScale = Math.min((containerWidth - 64) / unscaledVp.width, 1.6);
|
|
1400
|
+
const effectiveScale = (baseScale > 0 ? baseScale : 1) * zoomScale;
|
|
1401
|
+
const pixelRatio = window.devicePixelRatio || 1;
|
|
1402
|
+
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
1403
|
+
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1404
|
+
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1405
|
+
canvas.style.width = `${Math.floor(viewport.width)}px`;
|
|
1406
|
+
canvas.style.height = `${Math.floor(viewport.height)}px`;
|
|
1407
|
+
const canvasCtx = canvas.getContext("2d");
|
|
1408
|
+
if (!canvasCtx) return;
|
|
1409
|
+
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
1410
|
+
currentRenderTask = page.render({
|
|
1411
|
+
canvasContext: canvasCtx,
|
|
1412
|
+
viewport
|
|
1413
|
+
});
|
|
1414
|
+
try {
|
|
1415
|
+
await currentRenderTask.promise;
|
|
1416
|
+
} catch (err) {
|
|
1417
|
+
if (err?.name !== "RenderingCancelledException") {
|
|
1418
|
+
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1419
|
+
}
|
|
1420
|
+
} finally {
|
|
1421
|
+
currentRenderTask = null;
|
|
1422
|
+
}
|
|
1423
|
+
};
|
|
1424
|
+
await renderPage(1);
|
|
1311
1425
|
const cleanup = () => {
|
|
1312
|
-
|
|
1313
|
-
|
|
1426
|
+
if (currentRenderTask) {
|
|
1427
|
+
try {
|
|
1428
|
+
currentRenderTask.cancel();
|
|
1429
|
+
} catch {
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
try {
|
|
1433
|
+
pdfDoc.destroy();
|
|
1434
|
+
} catch {
|
|
1435
|
+
}
|
|
1436
|
+
container.remove();
|
|
1314
1437
|
ctx.container.innerHTML = "";
|
|
1315
1438
|
};
|
|
1316
1439
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1317
|
-
|
|
1440
|
+
const instance = {
|
|
1318
1441
|
destroy: cleanup,
|
|
1319
1442
|
zoomIn: () => {
|
|
1320
|
-
|
|
1321
|
-
|
|
1443
|
+
zoomScale = Math.min(3.5, zoomScale + 0.2);
|
|
1444
|
+
renderPage(currentPage);
|
|
1322
1445
|
},
|
|
1323
1446
|
zoomOut: () => {
|
|
1324
|
-
|
|
1325
|
-
|
|
1447
|
+
zoomScale = Math.max(0.3, zoomScale - 0.2);
|
|
1448
|
+
renderPage(currentPage);
|
|
1326
1449
|
},
|
|
1327
|
-
getZoom: () =>
|
|
1450
|
+
getZoom: () => zoomScale,
|
|
1328
1451
|
setZoom: (level) => {
|
|
1329
|
-
|
|
1330
|
-
|
|
1452
|
+
zoomScale = Math.max(0.3, Math.min(3.5, level));
|
|
1453
|
+
renderPage(currentPage);
|
|
1331
1454
|
},
|
|
1332
1455
|
fitToPage: () => {
|
|
1333
|
-
|
|
1334
|
-
|
|
1456
|
+
zoomScale = 1;
|
|
1457
|
+
renderPage(currentPage);
|
|
1335
1458
|
},
|
|
1336
1459
|
rotateCW: () => {
|
|
1337
1460
|
rotation = (rotation + 90) % 360;
|
|
1338
|
-
|
|
1461
|
+
renderPage(currentPage);
|
|
1339
1462
|
},
|
|
1340
1463
|
rotateCCW: () => {
|
|
1341
1464
|
rotation = (rotation - 90 + 360) % 360;
|
|
1342
|
-
|
|
1465
|
+
renderPage(currentPage);
|
|
1343
1466
|
},
|
|
1344
1467
|
getRotation: () => rotation,
|
|
1468
|
+
getPageCount: () => totalPages,
|
|
1469
|
+
getCurrentPage: () => currentPage,
|
|
1345
1470
|
goToPage: (page) => {
|
|
1346
|
-
|
|
1347
|
-
iframe.src = `${url}#page=${page}`;
|
|
1471
|
+
renderPage(page);
|
|
1348
1472
|
},
|
|
1349
|
-
getCurrentPage: () => currentPage,
|
|
1350
1473
|
download: () => {
|
|
1474
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1475
|
+
const url = URL.createObjectURL(blob);
|
|
1351
1476
|
const a = document.createElement("a");
|
|
1352
1477
|
a.href = url;
|
|
1353
1478
|
a.download = ctx.metadata.name || "document.pdf";
|
|
1354
1479
|
a.click();
|
|
1480
|
+
URL.revokeObjectURL(url);
|
|
1355
1481
|
},
|
|
1356
1482
|
print: () => {
|
|
1357
|
-
|
|
1483
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1484
|
+
const url = URL.createObjectURL(blob);
|
|
1485
|
+
const hiddenIframe = document.createElement("iframe");
|
|
1486
|
+
hiddenIframe.style.position = "fixed";
|
|
1487
|
+
hiddenIframe.style.right = "0";
|
|
1488
|
+
hiddenIframe.style.bottom = "0";
|
|
1489
|
+
hiddenIframe.style.width = "0";
|
|
1490
|
+
hiddenIframe.style.height = "0";
|
|
1491
|
+
hiddenIframe.style.border = "0";
|
|
1492
|
+
document.body.appendChild(hiddenIframe);
|
|
1493
|
+
hiddenIframe.src = url;
|
|
1494
|
+
hiddenIframe.onload = () => {
|
|
1495
|
+
setTimeout(() => {
|
|
1496
|
+
hiddenIframe.contentWindow?.print();
|
|
1497
|
+
setTimeout(() => {
|
|
1498
|
+
hiddenIframe.remove();
|
|
1499
|
+
URL.revokeObjectURL(url);
|
|
1500
|
+
}, 1e3);
|
|
1501
|
+
}, 300);
|
|
1502
|
+
};
|
|
1358
1503
|
},
|
|
1359
1504
|
getThumbnails: async () => {
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1505
|
+
const thumbnails = [];
|
|
1506
|
+
const count = Math.min(totalPages, 50);
|
|
1507
|
+
for (let i = 1; i <= count; i++) {
|
|
1508
|
+
thumbnails.push({
|
|
1509
|
+
index: i,
|
|
1510
|
+
label: `Page ${i}`,
|
|
1511
|
+
render: async (thumbCanvas) => {
|
|
1512
|
+
try {
|
|
1513
|
+
const p = await pdfDoc.getPage(i);
|
|
1514
|
+
const baseVp = p.getViewport({ scale: 1 });
|
|
1515
|
+
const thumbScale = (thumbCanvas.width || 120) / baseVp.width;
|
|
1516
|
+
const thumbVp = p.getViewport({ scale: thumbScale });
|
|
1517
|
+
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1518
|
+
const tCtx = thumbCanvas.getContext("2d");
|
|
1519
|
+
if (tCtx) {
|
|
1520
|
+
await p.render({ canvasContext: tCtx, viewport: thumbVp }).promise;
|
|
1521
|
+
}
|
|
1522
|
+
} catch (e) {
|
|
1523
|
+
console.warn(`[PdfPlugin] Error generating thumbnail for page ${i}:`, e);
|
|
1372
1524
|
}
|
|
1373
1525
|
}
|
|
1374
|
-
}
|
|
1375
|
-
|
|
1526
|
+
});
|
|
1527
|
+
}
|
|
1528
|
+
return thumbnails;
|
|
1376
1529
|
}
|
|
1377
1530
|
};
|
|
1531
|
+
return instance;
|
|
1378
1532
|
}
|
|
1379
1533
|
};
|
|
1380
1534
|
function pdfPlugin() {
|
|
@@ -1701,7 +1855,31 @@ var DocxPlugin = class {
|
|
|
1701
1855
|
return this.mimeTypes.includes(mime || "");
|
|
1702
1856
|
}
|
|
1703
1857
|
getToolbarActions(instance) {
|
|
1704
|
-
|
|
1858
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1859
|
+
const actions = [];
|
|
1860
|
+
if (totalPages > 1) {
|
|
1861
|
+
actions.push({
|
|
1862
|
+
id: "page-nav",
|
|
1863
|
+
icon: "",
|
|
1864
|
+
label: "Page Navigation",
|
|
1865
|
+
type: "page-nav",
|
|
1866
|
+
group: "navigation",
|
|
1867
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
1868
|
+
max: totalPages,
|
|
1869
|
+
execute: (action, page) => {
|
|
1870
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1871
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1872
|
+
if (action === "prev") {
|
|
1873
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1874
|
+
} else if (action === "next") {
|
|
1875
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1876
|
+
} else if (typeof page === "number") {
|
|
1877
|
+
instance.goToPage?.(page);
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
});
|
|
1881
|
+
}
|
|
1882
|
+
actions.push(
|
|
1705
1883
|
{
|
|
1706
1884
|
id: "zoom-out",
|
|
1707
1885
|
icon: "zoom-out",
|
|
@@ -1742,7 +1920,8 @@ var DocxPlugin = class {
|
|
|
1742
1920
|
group: "actions",
|
|
1743
1921
|
execute: () => instance.print?.()
|
|
1744
1922
|
}
|
|
1745
|
-
|
|
1923
|
+
);
|
|
1924
|
+
return actions;
|
|
1746
1925
|
}
|
|
1747
1926
|
async render(ctx) {
|
|
1748
1927
|
const wrapper = document.createElement("div");
|
|
@@ -1818,7 +1997,51 @@ var DocxPlugin = class {
|
|
|
1818
1997
|
}
|
|
1819
1998
|
}
|
|
1820
1999
|
}
|
|
2000
|
+
const sections = wrapper.querySelectorAll("section.docx");
|
|
2001
|
+
const cards = wrapper.querySelectorAll(".fp-docx-page-card");
|
|
2002
|
+
const pageElements = sections.length > 0 ? sections : cards;
|
|
2003
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
2004
|
+
let currentPage = 1;
|
|
2005
|
+
let indicator = null;
|
|
2006
|
+
if (totalPages > 1) {
|
|
2007
|
+
indicator = document.createElement("div");
|
|
2008
|
+
indicator.className = "fp-docx-page-indicator";
|
|
2009
|
+
indicator.style.position = "sticky";
|
|
2010
|
+
indicator.style.bottom = "16px";
|
|
2011
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2012
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
2013
|
+
indicator.style.color = "#f8fafc";
|
|
2014
|
+
indicator.style.fontSize = "12px";
|
|
2015
|
+
indicator.style.fontWeight = "600";
|
|
2016
|
+
indicator.style.padding = "5px 14px";
|
|
2017
|
+
indicator.style.borderRadius = "20px";
|
|
2018
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2019
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2020
|
+
indicator.style.zIndex = "10";
|
|
2021
|
+
indicator.style.userSelect = "none";
|
|
2022
|
+
indicator.style.pointerEvents = "none";
|
|
2023
|
+
indicator.style.textAlign = "center";
|
|
2024
|
+
indicator.style.width = "fit-content";
|
|
2025
|
+
indicator.style.margin = "16px auto 0";
|
|
2026
|
+
ctx.container.appendChild(indicator);
|
|
2027
|
+
}
|
|
2028
|
+
const showPage = (pageNum) => {
|
|
2029
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2030
|
+
if (pageElements.length > 1) {
|
|
2031
|
+
pageElements.forEach((sec, idx) => {
|
|
2032
|
+
sec.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
2033
|
+
});
|
|
2034
|
+
}
|
|
2035
|
+
if (indicator) {
|
|
2036
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2037
|
+
}
|
|
2038
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2039
|
+
};
|
|
2040
|
+
if (totalPages > 1) {
|
|
2041
|
+
showPage(1);
|
|
2042
|
+
}
|
|
1821
2043
|
const cleanup = () => {
|
|
2044
|
+
indicator?.remove();
|
|
1822
2045
|
for (const url of createdBlobUrls) {
|
|
1823
2046
|
URL.revokeObjectURL(url);
|
|
1824
2047
|
}
|
|
@@ -1829,6 +2052,11 @@ var DocxPlugin = class {
|
|
|
1829
2052
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1830
2053
|
return {
|
|
1831
2054
|
destroy: cleanup,
|
|
2055
|
+
getPageCount: () => totalPages,
|
|
2056
|
+
getCurrentPage: () => currentPage,
|
|
2057
|
+
goToPage: (page) => {
|
|
2058
|
+
showPage(page);
|
|
2059
|
+
},
|
|
1832
2060
|
zoomIn: () => {
|
|
1833
2061
|
scale += 0.1;
|
|
1834
2062
|
wrapper.style.transform = `scale(${scale})`;
|
|
@@ -2093,7 +2321,31 @@ var ExcelPlugin = class {
|
|
|
2093
2321
|
return this.mimeTypes.includes(mime || "");
|
|
2094
2322
|
}
|
|
2095
2323
|
getToolbarActions(instance) {
|
|
2096
|
-
|
|
2324
|
+
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2325
|
+
const actions = [];
|
|
2326
|
+
if (totalSheets > 1) {
|
|
2327
|
+
actions.push({
|
|
2328
|
+
id: "page-nav",
|
|
2329
|
+
icon: "",
|
|
2330
|
+
label: "Sheet Navigation",
|
|
2331
|
+
type: "page-nav",
|
|
2332
|
+
group: "navigation",
|
|
2333
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2334
|
+
max: totalSheets,
|
|
2335
|
+
execute: (action, sheet) => {
|
|
2336
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2337
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2338
|
+
if (action === "prev") {
|
|
2339
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2340
|
+
} else if (action === "next") {
|
|
2341
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2342
|
+
} else if (typeof sheet === "number") {
|
|
2343
|
+
instance.goToPage?.(sheet);
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
});
|
|
2347
|
+
}
|
|
2348
|
+
actions.push(
|
|
2097
2349
|
{
|
|
2098
2350
|
id: "zoom-out",
|
|
2099
2351
|
icon: "zoom-out",
|
|
@@ -2114,16 +2366,6 @@ var ExcelPlugin = class {
|
|
|
2114
2366
|
instance.zoomIn?.();
|
|
2115
2367
|
}
|
|
2116
2368
|
},
|
|
2117
|
-
{
|
|
2118
|
-
id: "page-nav",
|
|
2119
|
-
icon: "page-nav",
|
|
2120
|
-
label: "Sheet Navigation",
|
|
2121
|
-
type: "page-nav",
|
|
2122
|
-
group: "navigation",
|
|
2123
|
-
execute: (sheet) => {
|
|
2124
|
-
if (typeof sheet === "number") instance.goToPage?.(sheet);
|
|
2125
|
-
}
|
|
2126
|
-
},
|
|
2127
2369
|
{
|
|
2128
2370
|
id: "download",
|
|
2129
2371
|
icon: "download",
|
|
@@ -2144,7 +2386,8 @@ var ExcelPlugin = class {
|
|
|
2144
2386
|
instance.print?.();
|
|
2145
2387
|
}
|
|
2146
2388
|
}
|
|
2147
|
-
|
|
2389
|
+
);
|
|
2390
|
+
return actions;
|
|
2148
2391
|
}
|
|
2149
2392
|
async render(ctx) {
|
|
2150
2393
|
const container = document.createElement("div");
|
|
@@ -2228,6 +2471,7 @@ var ExcelPlugin = class {
|
|
|
2228
2471
|
b.style.fontWeight = "normal";
|
|
2229
2472
|
}
|
|
2230
2473
|
});
|
|
2474
|
+
ctx.emit("page-change", { page: currentSheetIndex, total: sheetNames.length });
|
|
2231
2475
|
};
|
|
2232
2476
|
if (sheetNames.length > 0) {
|
|
2233
2477
|
sheetNames.forEach((name, idx) => {
|
|
@@ -2477,7 +2721,31 @@ var CodePlugin = class {
|
|
|
2477
2721
|
return false;
|
|
2478
2722
|
}
|
|
2479
2723
|
getToolbarActions(instance) {
|
|
2480
|
-
|
|
2724
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2725
|
+
const actions = [];
|
|
2726
|
+
if (totalPages > 1) {
|
|
2727
|
+
actions.push({
|
|
2728
|
+
id: "page-nav",
|
|
2729
|
+
icon: "",
|
|
2730
|
+
label: "Page Navigation",
|
|
2731
|
+
type: "page-nav",
|
|
2732
|
+
group: "navigation",
|
|
2733
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2734
|
+
max: totalPages,
|
|
2735
|
+
execute: (action, page) => {
|
|
2736
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2737
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2738
|
+
if (action === "prev") {
|
|
2739
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2740
|
+
} else if (action === "next") {
|
|
2741
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2742
|
+
} else if (typeof page === "number") {
|
|
2743
|
+
instance.goToPage?.(page);
|
|
2744
|
+
}
|
|
2745
|
+
}
|
|
2746
|
+
});
|
|
2747
|
+
}
|
|
2748
|
+
actions.push(
|
|
2481
2749
|
{
|
|
2482
2750
|
id: "zoom-out",
|
|
2483
2751
|
icon: "zoom-out",
|
|
@@ -2528,11 +2796,16 @@ var CodePlugin = class {
|
|
|
2528
2796
|
instance.print?.();
|
|
2529
2797
|
}
|
|
2530
2798
|
}
|
|
2531
|
-
|
|
2799
|
+
);
|
|
2800
|
+
return actions;
|
|
2532
2801
|
}
|
|
2533
2802
|
async render(ctx) {
|
|
2534
2803
|
const decoder = new TextDecoder("utf-8");
|
|
2535
|
-
const
|
|
2804
|
+
const fullText = decoder.decode(ctx.buffer);
|
|
2805
|
+
const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
|
|
2806
|
+
const rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
2807
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
2808
|
+
let currentPage = 1;
|
|
2536
2809
|
const container = document.createElement("div");
|
|
2537
2810
|
container.style.width = "100%";
|
|
2538
2811
|
container.style.height = "100%";
|
|
@@ -2551,25 +2824,66 @@ var CodePlugin = class {
|
|
|
2551
2824
|
pre.style.wordBreak = "break-all";
|
|
2552
2825
|
const code = document.createElement("code");
|
|
2553
2826
|
const ext = (ctx.metadata.extension || "").replace(".", "");
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2827
|
+
const renderCodePage = (text) => {
|
|
2828
|
+
try {
|
|
2829
|
+
if (ext && hljs__default.default.getLanguage(ext)) {
|
|
2830
|
+
code.innerHTML = hljs__default.default.highlight(text, { language: ext }).value;
|
|
2831
|
+
} else {
|
|
2832
|
+
code.innerHTML = hljs__default.default.highlightAuto(text).value;
|
|
2833
|
+
}
|
|
2834
|
+
} catch {
|
|
2835
|
+
code.textContent = text;
|
|
2559
2836
|
}
|
|
2560
|
-
}
|
|
2561
|
-
|
|
2562
|
-
}
|
|
2837
|
+
};
|
|
2838
|
+
renderCodePage(rawPages[0] || fullText);
|
|
2563
2839
|
pre.appendChild(code);
|
|
2564
2840
|
container.appendChild(pre);
|
|
2841
|
+
let indicator = null;
|
|
2842
|
+
if (totalPages > 1) {
|
|
2843
|
+
indicator = document.createElement("div");
|
|
2844
|
+
indicator.className = "fp-code-page-indicator";
|
|
2845
|
+
indicator.style.position = "sticky";
|
|
2846
|
+
indicator.style.bottom = "16px";
|
|
2847
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2848
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
2849
|
+
indicator.style.color = "#f8fafc";
|
|
2850
|
+
indicator.style.fontSize = "12px";
|
|
2851
|
+
indicator.style.fontWeight = "600";
|
|
2852
|
+
indicator.style.padding = "5px 14px";
|
|
2853
|
+
indicator.style.borderRadius = "20px";
|
|
2854
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2855
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2856
|
+
indicator.style.zIndex = "10";
|
|
2857
|
+
indicator.style.userSelect = "none";
|
|
2858
|
+
indicator.style.pointerEvents = "none";
|
|
2859
|
+
indicator.style.textAlign = "center";
|
|
2860
|
+
indicator.style.width = "fit-content";
|
|
2861
|
+
indicator.style.margin = "16px auto 0";
|
|
2862
|
+
container.appendChild(indicator);
|
|
2863
|
+
}
|
|
2864
|
+
const showPage = (pageNum) => {
|
|
2865
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2866
|
+
renderCodePage(rawPages[currentPage - 1] || fullText);
|
|
2867
|
+
if (indicator) {
|
|
2868
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2869
|
+
}
|
|
2870
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2871
|
+
};
|
|
2872
|
+
if (totalPages > 1) {
|
|
2873
|
+
showPage(1);
|
|
2874
|
+
}
|
|
2565
2875
|
ctx.container.appendChild(container);
|
|
2566
2876
|
const cleanup = () => {
|
|
2877
|
+
indicator?.remove();
|
|
2567
2878
|
container.remove();
|
|
2568
2879
|
ctx.container.innerHTML = "";
|
|
2569
2880
|
};
|
|
2570
2881
|
ctx.signal.addEventListener("abort", cleanup);
|
|
2571
2882
|
return {
|
|
2572
2883
|
destroy: cleanup,
|
|
2884
|
+
getPageCount: () => totalPages,
|
|
2885
|
+
getCurrentPage: () => currentPage,
|
|
2886
|
+
goToPage: (page) => showPage(page),
|
|
2573
2887
|
zoomIn: () => {
|
|
2574
2888
|
fontSize = Math.min(32, fontSize + 2);
|
|
2575
2889
|
pre.style.fontSize = `${fontSize}px`;
|
|
@@ -2597,7 +2911,7 @@ var CodePlugin = class {
|
|
|
2597
2911
|
window.print();
|
|
2598
2912
|
},
|
|
2599
2913
|
copy: () => {
|
|
2600
|
-
navigator.clipboard?.writeText(
|
|
2914
|
+
navigator.clipboard?.writeText(fullText);
|
|
2601
2915
|
}
|
|
2602
2916
|
};
|
|
2603
2917
|
}
|
|
@@ -3419,7 +3733,31 @@ var RtfPlugin = class {
|
|
|
3419
3733
|
return this.extensions.includes(ext || "") || this.mimeTypes.includes(mime || "");
|
|
3420
3734
|
}
|
|
3421
3735
|
getToolbarActions(instance) {
|
|
3422
|
-
|
|
3736
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3737
|
+
const actions = [];
|
|
3738
|
+
if (totalPages > 1) {
|
|
3739
|
+
actions.push({
|
|
3740
|
+
id: "page-nav",
|
|
3741
|
+
icon: "",
|
|
3742
|
+
label: "Page Navigation",
|
|
3743
|
+
type: "page-nav",
|
|
3744
|
+
group: "navigation",
|
|
3745
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
3746
|
+
max: totalPages,
|
|
3747
|
+
execute: (action, page) => {
|
|
3748
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3749
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
3750
|
+
if (action === "prev") {
|
|
3751
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
3752
|
+
} else if (action === "next") {
|
|
3753
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
3754
|
+
} else if (typeof page === "number") {
|
|
3755
|
+
instance.goToPage?.(page);
|
|
3756
|
+
}
|
|
3757
|
+
}
|
|
3758
|
+
});
|
|
3759
|
+
}
|
|
3760
|
+
actions.push(
|
|
3423
3761
|
{
|
|
3424
3762
|
id: "zoom-out",
|
|
3425
3763
|
icon: "zoom-out",
|
|
@@ -3460,7 +3798,8 @@ var RtfPlugin = class {
|
|
|
3460
3798
|
group: "actions",
|
|
3461
3799
|
execute: () => instance.print?.()
|
|
3462
3800
|
}
|
|
3463
|
-
|
|
3801
|
+
);
|
|
3802
|
+
return actions;
|
|
3464
3803
|
}
|
|
3465
3804
|
async render(ctx) {
|
|
3466
3805
|
const wrapper = document.createElement("div");
|
|
@@ -3479,28 +3818,82 @@ var RtfPlugin = class {
|
|
|
3479
3818
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
3480
3819
|
ctx.container.appendChild(wrapper);
|
|
3481
3820
|
let scale = 1;
|
|
3821
|
+
let pageElements = [];
|
|
3482
3822
|
try {
|
|
3483
3823
|
if (typeof RTFJS__namespace.loggingEnabled === "function") {
|
|
3484
3824
|
RTFJS__namespace.loggingEnabled(false);
|
|
3485
3825
|
}
|
|
3486
3826
|
const doc = new RTFJS__namespace.Document(ctx.buffer, {});
|
|
3487
3827
|
const htmlElements = await doc.render();
|
|
3488
|
-
|
|
3828
|
+
pageElements = htmlElements;
|
|
3829
|
+
for (let i = 0; i < htmlElements.length; i++) {
|
|
3830
|
+
const el = htmlElements[i];
|
|
3831
|
+
el.style.display = i === 0 ? "block" : "none";
|
|
3489
3832
|
wrapper.appendChild(el);
|
|
3490
3833
|
}
|
|
3491
3834
|
} catch (err) {
|
|
3492
3835
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
3493
3836
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
3494
3837
|
const clean = text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "");
|
|
3495
|
-
|
|
3838
|
+
const pre = document.createElement("pre");
|
|
3839
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3840
|
+
pre.style.fontFamily = "serif";
|
|
3841
|
+
pre.style.color = "#333";
|
|
3842
|
+
pre.textContent = clean;
|
|
3843
|
+
wrapper.appendChild(pre);
|
|
3844
|
+
pageElements = [pre];
|
|
3845
|
+
}
|
|
3846
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
3847
|
+
let currentPage = 1;
|
|
3848
|
+
let indicator = null;
|
|
3849
|
+
if (totalPages > 1) {
|
|
3850
|
+
indicator = document.createElement("div");
|
|
3851
|
+
indicator.className = "fp-rtf-page-indicator";
|
|
3852
|
+
indicator.style.position = "sticky";
|
|
3853
|
+
indicator.style.bottom = "16px";
|
|
3854
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3855
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
3856
|
+
indicator.style.color = "#f8fafc";
|
|
3857
|
+
indicator.style.fontSize = "12px";
|
|
3858
|
+
indicator.style.fontWeight = "600";
|
|
3859
|
+
indicator.style.padding = "5px 14px";
|
|
3860
|
+
indicator.style.borderRadius = "20px";
|
|
3861
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3862
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3863
|
+
indicator.style.zIndex = "10";
|
|
3864
|
+
indicator.style.userSelect = "none";
|
|
3865
|
+
indicator.style.pointerEvents = "none";
|
|
3866
|
+
indicator.style.textAlign = "center";
|
|
3867
|
+
indicator.style.width = "fit-content";
|
|
3868
|
+
indicator.style.margin = "16px auto 0";
|
|
3869
|
+
ctx.container.appendChild(indicator);
|
|
3870
|
+
}
|
|
3871
|
+
const showPage = (pageNum) => {
|
|
3872
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3873
|
+
if (totalPages > 1) {
|
|
3874
|
+
pageElements.forEach((el, idx) => {
|
|
3875
|
+
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
3876
|
+
});
|
|
3877
|
+
}
|
|
3878
|
+
if (indicator) {
|
|
3879
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3880
|
+
}
|
|
3881
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3882
|
+
};
|
|
3883
|
+
if (totalPages > 1) {
|
|
3884
|
+
showPage(1);
|
|
3496
3885
|
}
|
|
3497
3886
|
const cleanup = () => {
|
|
3887
|
+
indicator?.remove();
|
|
3498
3888
|
wrapper.remove();
|
|
3499
3889
|
ctx.container.innerHTML = "";
|
|
3500
3890
|
};
|
|
3501
3891
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3502
3892
|
return {
|
|
3503
3893
|
destroy: cleanup,
|
|
3894
|
+
getPageCount: () => totalPages,
|
|
3895
|
+
getCurrentPage: () => currentPage,
|
|
3896
|
+
goToPage: (page) => showPage(page),
|
|
3504
3897
|
zoomIn: () => {
|
|
3505
3898
|
scale += 0.1;
|
|
3506
3899
|
wrapper.style.transform = `scale(${scale})`;
|
|
@@ -3688,41 +4081,41 @@ var OpenDocumentPlugin = class {
|
|
|
3688
4081
|
}
|
|
3689
4082
|
getToolbarActions(instance) {
|
|
3690
4083
|
const isPresentation = instance.isPresentation;
|
|
4084
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3691
4085
|
const actions = [];
|
|
3692
|
-
if (isPresentation) {
|
|
3693
|
-
|
|
3694
|
-
{
|
|
4086
|
+
if (isPresentation || totalPages > 1) {
|
|
4087
|
+
if (isPresentation) {
|
|
4088
|
+
actions.push({
|
|
3695
4089
|
id: "thumbnails",
|
|
3696
4090
|
icon: "thumbnails",
|
|
3697
4091
|
label: "Slide Thumbnails",
|
|
3698
4092
|
type: "button",
|
|
3699
4093
|
group: "navigation",
|
|
3700
4094
|
execute: () => instance.toggleThumbnails?.()
|
|
3701
|
-
}
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
}
|
|
4095
|
+
});
|
|
4096
|
+
}
|
|
4097
|
+
actions.push({
|
|
4098
|
+
id: "page-nav",
|
|
4099
|
+
icon: "",
|
|
4100
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
4101
|
+
type: "page-nav",
|
|
4102
|
+
group: "navigation",
|
|
4103
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4104
|
+
max: totalPages,
|
|
4105
|
+
execute: (action, page) => {
|
|
4106
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4107
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4108
|
+
if (action === "prev") {
|
|
4109
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4110
|
+
} else if (action === "next") {
|
|
4111
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4112
|
+
} else if (typeof page === "number") {
|
|
4113
|
+
instance.goToPage?.(page);
|
|
4114
|
+
} else if (typeof action === "number") {
|
|
4115
|
+
instance.goToPage?.(action);
|
|
3723
4116
|
}
|
|
3724
4117
|
}
|
|
3725
|
-
);
|
|
4118
|
+
});
|
|
3726
4119
|
}
|
|
3727
4120
|
actions.push(
|
|
3728
4121
|
{
|
|
@@ -4105,7 +4498,31 @@ var DocPlugin = class {
|
|
|
4105
4498
|
return this.mimeTypes.includes(mime || "");
|
|
4106
4499
|
}
|
|
4107
4500
|
getToolbarActions(instance) {
|
|
4108
|
-
|
|
4501
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4502
|
+
const actions = [];
|
|
4503
|
+
if (totalPages > 1) {
|
|
4504
|
+
actions.push({
|
|
4505
|
+
id: "page-nav",
|
|
4506
|
+
icon: "",
|
|
4507
|
+
label: "Page Navigation",
|
|
4508
|
+
type: "page-nav",
|
|
4509
|
+
group: "navigation",
|
|
4510
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4511
|
+
max: totalPages,
|
|
4512
|
+
execute: (action, page) => {
|
|
4513
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4514
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4515
|
+
if (action === "prev") {
|
|
4516
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4517
|
+
} else if (action === "next") {
|
|
4518
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4519
|
+
} else if (typeof page === "number") {
|
|
4520
|
+
instance.goToPage?.(page);
|
|
4521
|
+
}
|
|
4522
|
+
}
|
|
4523
|
+
});
|
|
4524
|
+
}
|
|
4525
|
+
actions.push(
|
|
4109
4526
|
{
|
|
4110
4527
|
id: "zoom-out",
|
|
4111
4528
|
icon: "zoom-out",
|
|
@@ -4154,7 +4571,8 @@ var DocPlugin = class {
|
|
|
4154
4571
|
group: "actions",
|
|
4155
4572
|
execute: () => instance.print?.()
|
|
4156
4573
|
}
|
|
4157
|
-
|
|
4574
|
+
);
|
|
4575
|
+
return actions;
|
|
4158
4576
|
}
|
|
4159
4577
|
async render(ctx) {
|
|
4160
4578
|
const container = document.createElement("div");
|
|
@@ -4181,6 +4599,7 @@ var DocPlugin = class {
|
|
|
4181
4599
|
ctx.container.appendChild(container);
|
|
4182
4600
|
let scale = 1;
|
|
4183
4601
|
let extractedRawText = "";
|
|
4602
|
+
let isFallback = false;
|
|
4184
4603
|
try {
|
|
4185
4604
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4186
4605
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
@@ -4194,26 +4613,89 @@ var DocPlugin = class {
|
|
|
4194
4613
|
const tableStream = cfbf.readStream(tableName);
|
|
4195
4614
|
const text = this.extractDocText(wordDocStream, tableStream);
|
|
4196
4615
|
extractedRawText = text;
|
|
4197
|
-
wrapper.innerHTML = this.formatDocToHtml(text, ctx.metadata.name || "Document");
|
|
4198
4616
|
} catch (err) {
|
|
4199
4617
|
console.warn("[DocPlugin] Binary parsing error, fallback text:", err);
|
|
4200
4618
|
const fallback = this.heuristicTextExtraction(ctx.buffer);
|
|
4201
4619
|
extractedRawText = fallback;
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4620
|
+
isFallback = true;
|
|
4621
|
+
}
|
|
4622
|
+
const rawPages = this.splitIntoPages(extractedRawText);
|
|
4623
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
4624
|
+
let currentPage = 1;
|
|
4625
|
+
wrapper.innerHTML = "";
|
|
4626
|
+
const pageCards = [];
|
|
4627
|
+
for (let i = 0; i < totalPages; i++) {
|
|
4628
|
+
const pageCard = document.createElement("div");
|
|
4629
|
+
pageCard.className = "fp-doc-page-card";
|
|
4630
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
4631
|
+
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4632
|
+
pageCard.style.borderRadius = "4px";
|
|
4633
|
+
pageCard.style.padding = "56px 48px";
|
|
4634
|
+
pageCard.style.minHeight = "100%";
|
|
4635
|
+
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4636
|
+
if (isFallback && i === 0) {
|
|
4637
|
+
pageCard.innerHTML = `
|
|
4638
|
+
<div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
|
|
4639
|
+
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify2__default.default.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
|
|
4640
|
+
<span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
|
|
4641
|
+
</div>
|
|
4642
|
+
${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
|
|
4643
|
+
`;
|
|
4644
|
+
} else {
|
|
4645
|
+
pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
|
|
4646
|
+
}
|
|
4647
|
+
wrapper.appendChild(pageCard);
|
|
4648
|
+
pageCards.push(pageCard);
|
|
4649
|
+
}
|
|
4650
|
+
let indicator = null;
|
|
4651
|
+
if (totalPages > 1) {
|
|
4652
|
+
indicator = document.createElement("div");
|
|
4653
|
+
indicator.className = "fp-doc-page-indicator";
|
|
4654
|
+
indicator.style.position = "sticky";
|
|
4655
|
+
indicator.style.bottom = "16px";
|
|
4656
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4657
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
4658
|
+
indicator.style.color = "#f8fafc";
|
|
4659
|
+
indicator.style.fontSize = "12px";
|
|
4660
|
+
indicator.style.fontWeight = "600";
|
|
4661
|
+
indicator.style.padding = "5px 14px";
|
|
4662
|
+
indicator.style.borderRadius = "20px";
|
|
4663
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4664
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4665
|
+
indicator.style.zIndex = "10";
|
|
4666
|
+
indicator.style.userSelect = "none";
|
|
4667
|
+
indicator.style.pointerEvents = "none";
|
|
4668
|
+
indicator.style.textAlign = "center";
|
|
4669
|
+
indicator.style.width = "fit-content";
|
|
4670
|
+
indicator.style.margin = "16px auto 0";
|
|
4671
|
+
container.appendChild(indicator);
|
|
4672
|
+
}
|
|
4673
|
+
const showPage = (pageNum) => {
|
|
4674
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4675
|
+
if (totalPages > 1) {
|
|
4676
|
+
pageCards.forEach((card, idx) => {
|
|
4677
|
+
card.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4678
|
+
});
|
|
4679
|
+
}
|
|
4680
|
+
if (indicator) {
|
|
4681
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4682
|
+
}
|
|
4683
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4684
|
+
};
|
|
4685
|
+
if (totalPages > 1) {
|
|
4686
|
+
showPage(1);
|
|
4209
4687
|
}
|
|
4210
4688
|
const cleanup = () => {
|
|
4689
|
+
indicator?.remove();
|
|
4211
4690
|
container.remove();
|
|
4212
4691
|
ctx.container.innerHTML = "";
|
|
4213
4692
|
};
|
|
4214
4693
|
ctx.signal.addEventListener("abort", cleanup);
|
|
4215
4694
|
return {
|
|
4216
4695
|
destroy: cleanup,
|
|
4696
|
+
getPageCount: () => totalPages,
|
|
4697
|
+
getCurrentPage: () => currentPage,
|
|
4698
|
+
goToPage: (page) => showPage(page),
|
|
4217
4699
|
zoomIn: () => {
|
|
4218
4700
|
scale += 0.1;
|
|
4219
4701
|
wrapper.style.transform = `scale(${scale})`;
|
|
@@ -4345,11 +4827,16 @@ var DocPlugin = class {
|
|
|
4345
4827
|
heuristicTextExtraction(buffer) {
|
|
4346
4828
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
4347
4829
|
}
|
|
4830
|
+
splitIntoPages(text) {
|
|
4831
|
+
if (!text) return [""];
|
|
4832
|
+
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);
|
|
4833
|
+
return parts.length > 0 ? parts : [text];
|
|
4834
|
+
}
|
|
4348
4835
|
/**
|
|
4349
4836
|
* Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
|
|
4350
4837
|
*/
|
|
4351
4838
|
formatDocToHtml(text, filename) {
|
|
4352
|
-
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").
|
|
4839
|
+
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
|
|
4353
4840
|
let html = "";
|
|
4354
4841
|
let inList = false;
|
|
4355
4842
|
for (const rawLine of lines) {
|