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