@files-preview-app/preview-file 1.2.3 → 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 +983 -245
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.js +980 -244
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +983 -245
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +980 -244
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +983 -245
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +980 -244
- package/dist/react.js.map +1 -1
- package/dist/vue.cjs +983 -245
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +980 -244
- package/dist/vue.js.map +1 -1
- package/package.json +1 -1
package/dist/angular.cjs
CHANGED
|
@@ -5,6 +5,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
var core = require('@angular/core');
|
|
6
6
|
var common = require('@angular/common');
|
|
7
7
|
var DOMPurify2 = require('dompurify');
|
|
8
|
+
var pdfjsLib = require('pdfjs-dist');
|
|
8
9
|
var docx = require('docx-preview');
|
|
9
10
|
var fflate = require('fflate');
|
|
10
11
|
var XLSX = require('xlsx');
|
|
@@ -15,7 +16,7 @@ var THREE = require('three');
|
|
|
15
16
|
var STLLoader_js = require('three/examples/jsm/loaders/STLLoader.js');
|
|
16
17
|
var OBJLoader_js = require('three/examples/jsm/loaders/OBJLoader.js');
|
|
17
18
|
var OrbitControls_js = require('three/examples/jsm/controls/OrbitControls.js');
|
|
18
|
-
var
|
|
19
|
+
var RTFJS = require('rtf.js/dist/RTFJS.bundle.js');
|
|
19
20
|
|
|
20
21
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
21
22
|
|
|
@@ -38,10 +39,12 @@ 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);
|
|
44
46
|
var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
|
|
47
|
+
var RTFJS__namespace = /*#__PURE__*/_interopNamespace(RTFJS);
|
|
45
48
|
|
|
46
49
|
var __create = Object.create;
|
|
47
50
|
var __defProp = Object.defineProperty;
|
|
@@ -344,6 +347,39 @@ function detectOoxmlType(buffer) {
|
|
|
344
347
|
}
|
|
345
348
|
return "application/zip";
|
|
346
349
|
}
|
|
350
|
+
function detectCfbfType(buffer) {
|
|
351
|
+
const bytes = new Uint8Array(buffer);
|
|
352
|
+
const hasUtf16le = (str) => {
|
|
353
|
+
const target = new Uint8Array(str.length * 2);
|
|
354
|
+
for (let i = 0; i < str.length; i++) {
|
|
355
|
+
target[i * 2] = str.charCodeAt(i);
|
|
356
|
+
target[i * 2 + 1] = 0;
|
|
357
|
+
}
|
|
358
|
+
const targetLen = target.length;
|
|
359
|
+
const max = bytes.length - targetLen;
|
|
360
|
+
for (let i = 0; i <= max; i++) {
|
|
361
|
+
let match = true;
|
|
362
|
+
for (let j = 0; j < targetLen; j++) {
|
|
363
|
+
if (bytes[i + j] !== target[j]) {
|
|
364
|
+
match = false;
|
|
365
|
+
break;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (match) return true;
|
|
369
|
+
}
|
|
370
|
+
return false;
|
|
371
|
+
};
|
|
372
|
+
if (hasUtf16le("PowerPoint Document")) {
|
|
373
|
+
return { mime: "application/vnd.ms-powerpoint", extension: ".ppt" };
|
|
374
|
+
}
|
|
375
|
+
if (hasUtf16le("WordDocument")) {
|
|
376
|
+
return { mime: "application/msword", extension: ".doc" };
|
|
377
|
+
}
|
|
378
|
+
if (hasUtf16le("Workbook") || hasUtf16le("Book")) {
|
|
379
|
+
return { mime: "application/vnd.ms-excel", extension: ".xls" };
|
|
380
|
+
}
|
|
381
|
+
return null;
|
|
382
|
+
}
|
|
347
383
|
function extractExtension(nameOrUrl) {
|
|
348
384
|
try {
|
|
349
385
|
const url = new URL(nameOrUrl);
|
|
@@ -408,6 +444,18 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
408
444
|
} else {
|
|
409
445
|
metadata.mimeType = metadata.mimeType ?? magicMime;
|
|
410
446
|
}
|
|
447
|
+
} else if (magicMime === "application/x-cfbf") {
|
|
448
|
+
if (metadata.extension) {
|
|
449
|
+
metadata.mimeType = mimeFromExtension(metadata.extension) ?? magicMime;
|
|
450
|
+
} else {
|
|
451
|
+
const cfbf = detectCfbfType(buffer);
|
|
452
|
+
if (cfbf) {
|
|
453
|
+
metadata.mimeType = cfbf.mime;
|
|
454
|
+
metadata.extension = cfbf.extension;
|
|
455
|
+
} else {
|
|
456
|
+
metadata.mimeType = magicMime;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
411
459
|
} else {
|
|
412
460
|
metadata.mimeType = magicMime;
|
|
413
461
|
}
|
|
@@ -512,11 +560,21 @@ var ToolbarController = class {
|
|
|
512
560
|
el;
|
|
513
561
|
toolbarEl;
|
|
514
562
|
actions = [];
|
|
563
|
+
pageInputEl = null;
|
|
564
|
+
pageLabelEl = null;
|
|
515
565
|
constructor(container) {
|
|
516
566
|
this.el = container;
|
|
517
567
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
518
568
|
this.el.appendChild(this.toolbarEl);
|
|
519
569
|
}
|
|
570
|
+
setPage(page, max) {
|
|
571
|
+
if (this.pageInputEl) {
|
|
572
|
+
this.pageInputEl.value = page.toString();
|
|
573
|
+
}
|
|
574
|
+
if (max !== void 0 && this.pageLabelEl) {
|
|
575
|
+
this.pageLabelEl.textContent = ` / ${max}`;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
520
578
|
update(actions) {
|
|
521
579
|
this.actions = actions;
|
|
522
580
|
this.render();
|
|
@@ -559,6 +617,7 @@ var ToolbarController = class {
|
|
|
559
617
|
if (action.type === "separator") {
|
|
560
618
|
groupEl.appendChild(createElement("div", { className: "fp-toolbar-separator" }));
|
|
561
619
|
} else if (action.type === "page-nav") {
|
|
620
|
+
const max = action.max ?? 1;
|
|
562
621
|
const prevBtn = this.createButton(
|
|
563
622
|
"prev",
|
|
564
623
|
ICON_PAGE_PREV,
|
|
@@ -577,7 +636,6 @@ var ToolbarController = class {
|
|
|
577
636
|
"Next Page",
|
|
578
637
|
() => {
|
|
579
638
|
const cur = parseInt(input.value, 10) || 1;
|
|
580
|
-
const max = action.max ?? 1;
|
|
581
639
|
if (cur < max) {
|
|
582
640
|
input.value = (cur + 1).toString();
|
|
583
641
|
action.execute("next", cur + 1);
|
|
@@ -589,15 +647,18 @@ var ToolbarController = class {
|
|
|
589
647
|
type: "number",
|
|
590
648
|
value: (action.value ?? 1).toString(),
|
|
591
649
|
min: "1",
|
|
592
|
-
max:
|
|
650
|
+
max: max.toString()
|
|
593
651
|
});
|
|
594
652
|
input.addEventListener("change", () => {
|
|
595
|
-
|
|
596
|
-
if (
|
|
597
|
-
|
|
598
|
-
|
|
653
|
+
let val = parseInt(input.value, 10);
|
|
654
|
+
if (isNaN(val)) val = 1;
|
|
655
|
+
val = Math.max(1, Math.min(max, val));
|
|
656
|
+
input.value = val.toString();
|
|
657
|
+
action.execute("go", val);
|
|
599
658
|
});
|
|
600
|
-
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${
|
|
659
|
+
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
660
|
+
this.pageInputEl = input;
|
|
661
|
+
this.pageLabelEl = label;
|
|
601
662
|
groupEl.appendChild(prevBtn);
|
|
602
663
|
groupEl.appendChild(input);
|
|
603
664
|
groupEl.appendChild(label);
|
|
@@ -775,7 +836,13 @@ var FilePreviewViewer = class {
|
|
|
775
836
|
buffer,
|
|
776
837
|
options,
|
|
777
838
|
signal,
|
|
778
|
-
emit: (event, payload) =>
|
|
839
|
+
emit: (event, payload) => {
|
|
840
|
+
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
841
|
+
const total = payload.total ?? payload.totalPages;
|
|
842
|
+
this.toolbar?.setPage(payload.page, total);
|
|
843
|
+
}
|
|
844
|
+
this.eventEmitter.emit(event, payload);
|
|
845
|
+
}
|
|
779
846
|
});
|
|
780
847
|
this.activeInstance = instance;
|
|
781
848
|
this.hideLoading();
|
|
@@ -809,6 +876,7 @@ var FilePreviewViewer = class {
|
|
|
809
876
|
if (thumbnails && thumbnails.length > 0 && this.thumbnailPanel) {
|
|
810
877
|
this.thumbnailPanel.update(thumbnails, (index) => {
|
|
811
878
|
instance.goToPage?.(index + 1);
|
|
879
|
+
this.toolbar?.setPage(index + 1);
|
|
812
880
|
});
|
|
813
881
|
if (options.showThumbnails) {
|
|
814
882
|
this.thumbnailPanel.show();
|
|
@@ -934,9 +1002,13 @@ var FilePreviewViewer = class {
|
|
|
934
1002
|
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
935
1003
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
936
1004
|
this.activeInstance.goToPage?.(cur + 1);
|
|
1005
|
+
const nextCur = this.activeInstance.getCurrentPage?.() ?? cur + 1;
|
|
1006
|
+
this.toolbar?.setPage(nextCur);
|
|
937
1007
|
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
938
1008
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
939
1009
|
this.activeInstance.goToPage?.(Math.max(1, cur - 1));
|
|
1010
|
+
const prevCur = this.activeInstance.getCurrentPage?.() ?? Math.max(1, cur - 1);
|
|
1011
|
+
this.toolbar?.setPage(prevCur);
|
|
940
1012
|
} else if (e.key === "+" || e.key === "=") {
|
|
941
1013
|
this.activeInstance.zoomIn?.();
|
|
942
1014
|
} else if (e.key === "-" || e.key === "_") {
|
|
@@ -1202,30 +1274,62 @@ var CfbfReader = class {
|
|
|
1202
1274
|
return result.subarray(0, targetSize);
|
|
1203
1275
|
}
|
|
1204
1276
|
};
|
|
1205
|
-
|
|
1206
|
-
|
|
1277
|
+
if (typeof window !== "undefined" && pdfjsLib__namespace.GlobalWorkerOptions) {
|
|
1278
|
+
if (!pdfjsLib__namespace.GlobalWorkerOptions.workerSrc) {
|
|
1279
|
+
pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/build/pdf.worker.min.mjs`;
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1207
1282
|
var PdfPlugin = class {
|
|
1208
1283
|
id = "pdf";
|
|
1209
|
-
name = "PDF Preview";
|
|
1284
|
+
name = "PDF Document Preview";
|
|
1210
1285
|
extensions = [".pdf"];
|
|
1211
1286
|
mimeTypes = ["application/pdf"];
|
|
1212
1287
|
weight = 100;
|
|
1213
1288
|
supports(file) {
|
|
1214
1289
|
const ext = file.metadata.extension?.toLowerCase();
|
|
1215
1290
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
1216
|
-
|
|
1291
|
+
if (ext) return this.extensions.includes(ext);
|
|
1292
|
+
return this.mimeTypes.includes(mime || "");
|
|
1217
1293
|
}
|
|
1218
1294
|
getToolbarActions(instance) {
|
|
1295
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1296
|
+
const curPage = instance.getCurrentPage?.() ?? 1;
|
|
1219
1297
|
return [
|
|
1298
|
+
{
|
|
1299
|
+
id: "thumbnails",
|
|
1300
|
+
icon: "thumbnails",
|
|
1301
|
+
label: "Page Thumbnails",
|
|
1302
|
+
type: "button",
|
|
1303
|
+
group: "navigation",
|
|
1304
|
+
execute: () => instance.toggleThumbnails?.()
|
|
1305
|
+
},
|
|
1306
|
+
{
|
|
1307
|
+
id: "page-nav",
|
|
1308
|
+
icon: "",
|
|
1309
|
+
label: "Page Navigation",
|
|
1310
|
+
type: "page-nav",
|
|
1311
|
+
group: "navigation",
|
|
1312
|
+
value: curPage,
|
|
1313
|
+
max: totalPages,
|
|
1314
|
+
execute: (action, page) => {
|
|
1315
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1316
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1317
|
+
if (action === "prev") {
|
|
1318
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1319
|
+
} else if (action === "next") {
|
|
1320
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1321
|
+
} else if (typeof page === "number") {
|
|
1322
|
+
instance.goToPage?.(page);
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
},
|
|
1220
1326
|
{
|
|
1221
1327
|
id: "zoom-out",
|
|
1222
1328
|
icon: "zoom-out",
|
|
1223
1329
|
label: "Zoom Out",
|
|
1224
1330
|
type: "button",
|
|
1225
1331
|
group: "zoom",
|
|
1226
|
-
execute: () =>
|
|
1227
|
-
instance.zoomOut?.();
|
|
1228
|
-
}
|
|
1332
|
+
execute: () => instance.zoomOut?.()
|
|
1229
1333
|
},
|
|
1230
1334
|
{
|
|
1231
1335
|
id: "zoom-in",
|
|
@@ -1233,9 +1337,7 @@ var PdfPlugin = class {
|
|
|
1233
1337
|
label: "Zoom In",
|
|
1234
1338
|
type: "button",
|
|
1235
1339
|
group: "zoom",
|
|
1236
|
-
execute: () =>
|
|
1237
|
-
instance.zoomIn?.();
|
|
1238
|
-
}
|
|
1340
|
+
execute: () => instance.zoomIn?.()
|
|
1239
1341
|
},
|
|
1240
1342
|
{
|
|
1241
1343
|
id: "fit-page",
|
|
@@ -1243,39 +1345,23 @@ var PdfPlugin = class {
|
|
|
1243
1345
|
label: "Fit to Page",
|
|
1244
1346
|
type: "button",
|
|
1245
1347
|
group: "zoom",
|
|
1246
|
-
execute: () =>
|
|
1247
|
-
instance.fitToPage?.();
|
|
1248
|
-
}
|
|
1348
|
+
execute: () => instance.fitToPage?.()
|
|
1249
1349
|
},
|
|
1250
1350
|
{
|
|
1251
1351
|
id: "rotate-cw",
|
|
1252
1352
|
icon: "rotate-cw",
|
|
1253
|
-
label: "Rotate",
|
|
1353
|
+
label: "Rotate Clockwise",
|
|
1254
1354
|
type: "button",
|
|
1255
1355
|
group: "view",
|
|
1256
|
-
execute: () =>
|
|
1257
|
-
instance.rotateCW?.();
|
|
1258
|
-
}
|
|
1259
|
-
},
|
|
1260
|
-
{
|
|
1261
|
-
id: "page-nav",
|
|
1262
|
-
icon: "page-nav",
|
|
1263
|
-
label: "Page Navigation",
|
|
1264
|
-
type: "page-nav",
|
|
1265
|
-
group: "navigation",
|
|
1266
|
-
execute: (page) => {
|
|
1267
|
-
if (typeof page === "number") instance.goToPage?.(page);
|
|
1268
|
-
}
|
|
1356
|
+
execute: () => instance.rotateCW?.()
|
|
1269
1357
|
},
|
|
1270
1358
|
{
|
|
1271
1359
|
id: "download",
|
|
1272
1360
|
icon: "download",
|
|
1273
|
-
label: "Download",
|
|
1361
|
+
label: "Download PDF",
|
|
1274
1362
|
type: "button",
|
|
1275
1363
|
group: "actions",
|
|
1276
|
-
execute: () =>
|
|
1277
|
-
instance.download?.();
|
|
1278
|
-
}
|
|
1364
|
+
execute: () => instance.download?.()
|
|
1279
1365
|
},
|
|
1280
1366
|
{
|
|
1281
1367
|
id: "print",
|
|
@@ -1283,99 +1369,213 @@ var PdfPlugin = class {
|
|
|
1283
1369
|
label: "Print",
|
|
1284
1370
|
type: "button",
|
|
1285
1371
|
group: "actions",
|
|
1286
|
-
execute: () =>
|
|
1287
|
-
instance.print?.();
|
|
1288
|
-
}
|
|
1372
|
+
execute: () => instance.print?.()
|
|
1289
1373
|
}
|
|
1290
1374
|
];
|
|
1291
1375
|
}
|
|
1292
1376
|
async render(ctx) {
|
|
1293
|
-
const
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1377
|
+
const container = document.createElement("div");
|
|
1378
|
+
container.className = "fp-pdf-container";
|
|
1379
|
+
container.style.width = "100%";
|
|
1380
|
+
container.style.height = "100%";
|
|
1381
|
+
container.style.overflow = "auto";
|
|
1382
|
+
container.style.display = "flex";
|
|
1383
|
+
container.style.flexDirection = "column";
|
|
1384
|
+
container.style.alignItems = "center";
|
|
1385
|
+
container.style.padding = "24px 16px";
|
|
1386
|
+
container.style.backgroundColor = "#0f172a";
|
|
1387
|
+
container.style.boxSizing = "border-box";
|
|
1388
|
+
container.style.position = "relative";
|
|
1389
|
+
const pageCard = document.createElement("div");
|
|
1390
|
+
pageCard.className = "fp-pdf-page-card";
|
|
1391
|
+
pageCard.style.boxShadow = "0 10px 35px rgba(0, 0, 0, 0.5)";
|
|
1392
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
1393
|
+
pageCard.style.borderRadius = "4px";
|
|
1394
|
+
pageCard.style.overflow = "hidden";
|
|
1395
|
+
pageCard.style.lineHeight = "0";
|
|
1396
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
1397
|
+
pageCard.style.position = "relative";
|
|
1398
|
+
const canvas = document.createElement("canvas");
|
|
1399
|
+
pageCard.appendChild(canvas);
|
|
1400
|
+
container.appendChild(pageCard);
|
|
1401
|
+
const indicator = document.createElement("div");
|
|
1402
|
+
indicator.className = "fp-pdf-page-indicator";
|
|
1403
|
+
indicator.style.position = "sticky";
|
|
1404
|
+
indicator.style.bottom = "16px";
|
|
1405
|
+
indicator.style.marginTop = "16px";
|
|
1406
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1407
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
1408
|
+
indicator.style.color = "#f8fafc";
|
|
1409
|
+
indicator.style.fontSize = "12px";
|
|
1410
|
+
indicator.style.fontWeight = "600";
|
|
1411
|
+
indicator.style.padding = "5px 14px";
|
|
1412
|
+
indicator.style.borderRadius = "20px";
|
|
1413
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1414
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1415
|
+
indicator.style.zIndex = "10";
|
|
1416
|
+
indicator.style.userSelect = "none";
|
|
1417
|
+
indicator.style.pointerEvents = "none";
|
|
1418
|
+
container.appendChild(indicator);
|
|
1419
|
+
ctx.container.appendChild(container);
|
|
1420
|
+
const loadingTask = pdfjsLib__namespace.getDocument({
|
|
1421
|
+
data: new Uint8Array(ctx.buffer),
|
|
1422
|
+
cMapUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/cmaps/`,
|
|
1423
|
+
cMapPacked: true,
|
|
1424
|
+
standardFontDataUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/standard_fonts/`
|
|
1425
|
+
});
|
|
1426
|
+
const pdfDoc = await loadingTask.promise;
|
|
1427
|
+
const totalPages = Math.max(1, pdfDoc.numPages);
|
|
1309
1428
|
let currentPage = 1;
|
|
1310
|
-
let
|
|
1429
|
+
let zoomScale = 1;
|
|
1311
1430
|
let rotation = 0;
|
|
1431
|
+
let currentRenderTask = null;
|
|
1432
|
+
const renderPage = async (pageNum) => {
|
|
1433
|
+
if (currentRenderTask) {
|
|
1434
|
+
try {
|
|
1435
|
+
currentRenderTask.cancel();
|
|
1436
|
+
} catch {
|
|
1437
|
+
}
|
|
1438
|
+
currentRenderTask = null;
|
|
1439
|
+
}
|
|
1440
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1441
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1442
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1443
|
+
const page = await pdfDoc.getPage(currentPage);
|
|
1444
|
+
const containerWidth = container.clientWidth || 900;
|
|
1445
|
+
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1446
|
+
const baseScale = Math.min((containerWidth - 64) / unscaledVp.width, 1.6);
|
|
1447
|
+
const effectiveScale = (baseScale > 0 ? baseScale : 1) * zoomScale;
|
|
1448
|
+
const pixelRatio = window.devicePixelRatio || 1;
|
|
1449
|
+
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
1450
|
+
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1451
|
+
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1452
|
+
canvas.style.width = `${Math.floor(viewport.width)}px`;
|
|
1453
|
+
canvas.style.height = `${Math.floor(viewport.height)}px`;
|
|
1454
|
+
const canvasCtx = canvas.getContext("2d");
|
|
1455
|
+
if (!canvasCtx) return;
|
|
1456
|
+
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
1457
|
+
currentRenderTask = page.render({
|
|
1458
|
+
canvasContext: canvasCtx,
|
|
1459
|
+
viewport
|
|
1460
|
+
});
|
|
1461
|
+
try {
|
|
1462
|
+
await currentRenderTask.promise;
|
|
1463
|
+
} catch (err) {
|
|
1464
|
+
if (err?.name !== "RenderingCancelledException") {
|
|
1465
|
+
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1466
|
+
}
|
|
1467
|
+
} finally {
|
|
1468
|
+
currentRenderTask = null;
|
|
1469
|
+
}
|
|
1470
|
+
};
|
|
1471
|
+
await renderPage(1);
|
|
1312
1472
|
const cleanup = () => {
|
|
1313
|
-
|
|
1314
|
-
|
|
1473
|
+
if (currentRenderTask) {
|
|
1474
|
+
try {
|
|
1475
|
+
currentRenderTask.cancel();
|
|
1476
|
+
} catch {
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
try {
|
|
1480
|
+
pdfDoc.destroy();
|
|
1481
|
+
} catch {
|
|
1482
|
+
}
|
|
1483
|
+
container.remove();
|
|
1315
1484
|
ctx.container.innerHTML = "";
|
|
1316
1485
|
};
|
|
1317
1486
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1318
|
-
|
|
1487
|
+
const instance = {
|
|
1319
1488
|
destroy: cleanup,
|
|
1320
1489
|
zoomIn: () => {
|
|
1321
|
-
|
|
1322
|
-
|
|
1490
|
+
zoomScale = Math.min(3.5, zoomScale + 0.2);
|
|
1491
|
+
renderPage(currentPage);
|
|
1323
1492
|
},
|
|
1324
1493
|
zoomOut: () => {
|
|
1325
|
-
|
|
1326
|
-
|
|
1494
|
+
zoomScale = Math.max(0.3, zoomScale - 0.2);
|
|
1495
|
+
renderPage(currentPage);
|
|
1327
1496
|
},
|
|
1328
|
-
getZoom: () =>
|
|
1497
|
+
getZoom: () => zoomScale,
|
|
1329
1498
|
setZoom: (level) => {
|
|
1330
|
-
|
|
1331
|
-
|
|
1499
|
+
zoomScale = Math.max(0.3, Math.min(3.5, level));
|
|
1500
|
+
renderPage(currentPage);
|
|
1332
1501
|
},
|
|
1333
1502
|
fitToPage: () => {
|
|
1334
|
-
|
|
1335
|
-
|
|
1503
|
+
zoomScale = 1;
|
|
1504
|
+
renderPage(currentPage);
|
|
1336
1505
|
},
|
|
1337
1506
|
rotateCW: () => {
|
|
1338
1507
|
rotation = (rotation + 90) % 360;
|
|
1339
|
-
|
|
1508
|
+
renderPage(currentPage);
|
|
1340
1509
|
},
|
|
1341
1510
|
rotateCCW: () => {
|
|
1342
1511
|
rotation = (rotation - 90 + 360) % 360;
|
|
1343
|
-
|
|
1512
|
+
renderPage(currentPage);
|
|
1344
1513
|
},
|
|
1345
1514
|
getRotation: () => rotation,
|
|
1515
|
+
getPageCount: () => totalPages,
|
|
1516
|
+
getCurrentPage: () => currentPage,
|
|
1346
1517
|
goToPage: (page) => {
|
|
1347
|
-
|
|
1348
|
-
iframe.src = `${url}#page=${page}`;
|
|
1518
|
+
renderPage(page);
|
|
1349
1519
|
},
|
|
1350
|
-
getCurrentPage: () => currentPage,
|
|
1351
1520
|
download: () => {
|
|
1521
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1522
|
+
const url = URL.createObjectURL(blob);
|
|
1352
1523
|
const a = document.createElement("a");
|
|
1353
1524
|
a.href = url;
|
|
1354
1525
|
a.download = ctx.metadata.name || "document.pdf";
|
|
1355
1526
|
a.click();
|
|
1527
|
+
URL.revokeObjectURL(url);
|
|
1356
1528
|
},
|
|
1357
1529
|
print: () => {
|
|
1358
|
-
|
|
1530
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1531
|
+
const url = URL.createObjectURL(blob);
|
|
1532
|
+
const hiddenIframe = document.createElement("iframe");
|
|
1533
|
+
hiddenIframe.style.position = "fixed";
|
|
1534
|
+
hiddenIframe.style.right = "0";
|
|
1535
|
+
hiddenIframe.style.bottom = "0";
|
|
1536
|
+
hiddenIframe.style.width = "0";
|
|
1537
|
+
hiddenIframe.style.height = "0";
|
|
1538
|
+
hiddenIframe.style.border = "0";
|
|
1539
|
+
document.body.appendChild(hiddenIframe);
|
|
1540
|
+
hiddenIframe.src = url;
|
|
1541
|
+
hiddenIframe.onload = () => {
|
|
1542
|
+
setTimeout(() => {
|
|
1543
|
+
hiddenIframe.contentWindow?.print();
|
|
1544
|
+
setTimeout(() => {
|
|
1545
|
+
hiddenIframe.remove();
|
|
1546
|
+
URL.revokeObjectURL(url);
|
|
1547
|
+
}, 1e3);
|
|
1548
|
+
}, 300);
|
|
1549
|
+
};
|
|
1359
1550
|
},
|
|
1360
1551
|
getThumbnails: async () => {
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1552
|
+
const thumbnails = [];
|
|
1553
|
+
const count = Math.min(totalPages, 50);
|
|
1554
|
+
for (let i = 1; i <= count; i++) {
|
|
1555
|
+
thumbnails.push({
|
|
1556
|
+
index: i,
|
|
1557
|
+
label: `Page ${i}`,
|
|
1558
|
+
render: async (thumbCanvas) => {
|
|
1559
|
+
try {
|
|
1560
|
+
const p = await pdfDoc.getPage(i);
|
|
1561
|
+
const baseVp = p.getViewport({ scale: 1 });
|
|
1562
|
+
const thumbScale = (thumbCanvas.width || 120) / baseVp.width;
|
|
1563
|
+
const thumbVp = p.getViewport({ scale: thumbScale });
|
|
1564
|
+
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1565
|
+
const tCtx = thumbCanvas.getContext("2d");
|
|
1566
|
+
if (tCtx) {
|
|
1567
|
+
await p.render({ canvasContext: tCtx, viewport: thumbVp }).promise;
|
|
1568
|
+
}
|
|
1569
|
+
} catch (e) {
|
|
1570
|
+
console.warn(`[PdfPlugin] Error generating thumbnail for page ${i}:`, e);
|
|
1373
1571
|
}
|
|
1374
1572
|
}
|
|
1375
|
-
}
|
|
1376
|
-
|
|
1573
|
+
});
|
|
1574
|
+
}
|
|
1575
|
+
return thumbnails;
|
|
1377
1576
|
}
|
|
1378
1577
|
};
|
|
1578
|
+
return instance;
|
|
1379
1579
|
}
|
|
1380
1580
|
};
|
|
1381
1581
|
function pdfPlugin() {
|
|
@@ -1696,10 +1896,37 @@ var DocxPlugin = class {
|
|
|
1696
1896
|
supports(file) {
|
|
1697
1897
|
const ext = file.metadata.extension?.toLowerCase();
|
|
1698
1898
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
1699
|
-
|
|
1899
|
+
if (ext) {
|
|
1900
|
+
return this.extensions.includes(ext);
|
|
1901
|
+
}
|
|
1902
|
+
return this.mimeTypes.includes(mime || "");
|
|
1700
1903
|
}
|
|
1701
1904
|
getToolbarActions(instance) {
|
|
1702
|
-
|
|
1905
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1906
|
+
const actions = [];
|
|
1907
|
+
if (totalPages > 1) {
|
|
1908
|
+
actions.push({
|
|
1909
|
+
id: "page-nav",
|
|
1910
|
+
icon: "",
|
|
1911
|
+
label: "Page Navigation",
|
|
1912
|
+
type: "page-nav",
|
|
1913
|
+
group: "navigation",
|
|
1914
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
1915
|
+
max: totalPages,
|
|
1916
|
+
execute: (action, page) => {
|
|
1917
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1918
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1919
|
+
if (action === "prev") {
|
|
1920
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1921
|
+
} else if (action === "next") {
|
|
1922
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1923
|
+
} else if (typeof page === "number") {
|
|
1924
|
+
instance.goToPage?.(page);
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
});
|
|
1928
|
+
}
|
|
1929
|
+
actions.push(
|
|
1703
1930
|
{
|
|
1704
1931
|
id: "zoom-out",
|
|
1705
1932
|
icon: "zoom-out",
|
|
@@ -1740,7 +1967,8 @@ var DocxPlugin = class {
|
|
|
1740
1967
|
group: "actions",
|
|
1741
1968
|
execute: () => instance.print?.()
|
|
1742
1969
|
}
|
|
1743
|
-
|
|
1970
|
+
);
|
|
1971
|
+
return actions;
|
|
1744
1972
|
}
|
|
1745
1973
|
async render(ctx) {
|
|
1746
1974
|
const wrapper = document.createElement("div");
|
|
@@ -1816,7 +2044,51 @@ var DocxPlugin = class {
|
|
|
1816
2044
|
}
|
|
1817
2045
|
}
|
|
1818
2046
|
}
|
|
2047
|
+
const sections = wrapper.querySelectorAll("section.docx");
|
|
2048
|
+
const cards = wrapper.querySelectorAll(".fp-docx-page-card");
|
|
2049
|
+
const pageElements = sections.length > 0 ? sections : cards;
|
|
2050
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
2051
|
+
let currentPage = 1;
|
|
2052
|
+
let indicator = null;
|
|
2053
|
+
if (totalPages > 1) {
|
|
2054
|
+
indicator = document.createElement("div");
|
|
2055
|
+
indicator.className = "fp-docx-page-indicator";
|
|
2056
|
+
indicator.style.position = "sticky";
|
|
2057
|
+
indicator.style.bottom = "16px";
|
|
2058
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2059
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
2060
|
+
indicator.style.color = "#f8fafc";
|
|
2061
|
+
indicator.style.fontSize = "12px";
|
|
2062
|
+
indicator.style.fontWeight = "600";
|
|
2063
|
+
indicator.style.padding = "5px 14px";
|
|
2064
|
+
indicator.style.borderRadius = "20px";
|
|
2065
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2066
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2067
|
+
indicator.style.zIndex = "10";
|
|
2068
|
+
indicator.style.userSelect = "none";
|
|
2069
|
+
indicator.style.pointerEvents = "none";
|
|
2070
|
+
indicator.style.textAlign = "center";
|
|
2071
|
+
indicator.style.width = "fit-content";
|
|
2072
|
+
indicator.style.margin = "16px auto 0";
|
|
2073
|
+
ctx.container.appendChild(indicator);
|
|
2074
|
+
}
|
|
2075
|
+
const showPage = (pageNum) => {
|
|
2076
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2077
|
+
if (pageElements.length > 1) {
|
|
2078
|
+
pageElements.forEach((sec, idx) => {
|
|
2079
|
+
sec.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
2080
|
+
});
|
|
2081
|
+
}
|
|
2082
|
+
if (indicator) {
|
|
2083
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2084
|
+
}
|
|
2085
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2086
|
+
};
|
|
2087
|
+
if (totalPages > 1) {
|
|
2088
|
+
showPage(1);
|
|
2089
|
+
}
|
|
1819
2090
|
const cleanup = () => {
|
|
2091
|
+
indicator?.remove();
|
|
1820
2092
|
for (const url of createdBlobUrls) {
|
|
1821
2093
|
URL.revokeObjectURL(url);
|
|
1822
2094
|
}
|
|
@@ -1827,6 +2099,11 @@ var DocxPlugin = class {
|
|
|
1827
2099
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1828
2100
|
return {
|
|
1829
2101
|
destroy: cleanup,
|
|
2102
|
+
getPageCount: () => totalPages,
|
|
2103
|
+
getCurrentPage: () => currentPage,
|
|
2104
|
+
goToPage: (page) => {
|
|
2105
|
+
showPage(page);
|
|
2106
|
+
},
|
|
1830
2107
|
zoomIn: () => {
|
|
1831
2108
|
scale += 0.1;
|
|
1832
2109
|
wrapper.style.transform = `scale(${scale})`;
|
|
@@ -2085,10 +2362,37 @@ var ExcelPlugin = class {
|
|
|
2085
2362
|
supports(file) {
|
|
2086
2363
|
const ext = file.metadata.extension?.toLowerCase();
|
|
2087
2364
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
2088
|
-
|
|
2365
|
+
if (ext) {
|
|
2366
|
+
return this.extensions.includes(ext);
|
|
2367
|
+
}
|
|
2368
|
+
return this.mimeTypes.includes(mime || "");
|
|
2089
2369
|
}
|
|
2090
2370
|
getToolbarActions(instance) {
|
|
2091
|
-
|
|
2371
|
+
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2372
|
+
const actions = [];
|
|
2373
|
+
if (totalSheets > 1) {
|
|
2374
|
+
actions.push({
|
|
2375
|
+
id: "page-nav",
|
|
2376
|
+
icon: "",
|
|
2377
|
+
label: "Sheet Navigation",
|
|
2378
|
+
type: "page-nav",
|
|
2379
|
+
group: "navigation",
|
|
2380
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2381
|
+
max: totalSheets,
|
|
2382
|
+
execute: (action, sheet) => {
|
|
2383
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2384
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2385
|
+
if (action === "prev") {
|
|
2386
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2387
|
+
} else if (action === "next") {
|
|
2388
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2389
|
+
} else if (typeof sheet === "number") {
|
|
2390
|
+
instance.goToPage?.(sheet);
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
});
|
|
2394
|
+
}
|
|
2395
|
+
actions.push(
|
|
2092
2396
|
{
|
|
2093
2397
|
id: "zoom-out",
|
|
2094
2398
|
icon: "zoom-out",
|
|
@@ -2109,16 +2413,6 @@ var ExcelPlugin = class {
|
|
|
2109
2413
|
instance.zoomIn?.();
|
|
2110
2414
|
}
|
|
2111
2415
|
},
|
|
2112
|
-
{
|
|
2113
|
-
id: "page-nav",
|
|
2114
|
-
icon: "page-nav",
|
|
2115
|
-
label: "Sheet Navigation",
|
|
2116
|
-
type: "page-nav",
|
|
2117
|
-
group: "navigation",
|
|
2118
|
-
execute: (sheet) => {
|
|
2119
|
-
if (typeof sheet === "number") instance.goToPage?.(sheet);
|
|
2120
|
-
}
|
|
2121
|
-
},
|
|
2122
2416
|
{
|
|
2123
2417
|
id: "download",
|
|
2124
2418
|
icon: "download",
|
|
@@ -2139,7 +2433,8 @@ var ExcelPlugin = class {
|
|
|
2139
2433
|
instance.print?.();
|
|
2140
2434
|
}
|
|
2141
2435
|
}
|
|
2142
|
-
|
|
2436
|
+
);
|
|
2437
|
+
return actions;
|
|
2143
2438
|
}
|
|
2144
2439
|
async render(ctx) {
|
|
2145
2440
|
const container = document.createElement("div");
|
|
@@ -2223,6 +2518,7 @@ var ExcelPlugin = class {
|
|
|
2223
2518
|
b.style.fontWeight = "normal";
|
|
2224
2519
|
}
|
|
2225
2520
|
});
|
|
2521
|
+
ctx.emit("page-change", { page: currentSheetIndex, total: sheetNames.length });
|
|
2226
2522
|
};
|
|
2227
2523
|
if (sheetNames.length > 0) {
|
|
2228
2524
|
sheetNames.forEach((name, idx) => {
|
|
@@ -2472,7 +2768,31 @@ var CodePlugin = class {
|
|
|
2472
2768
|
return false;
|
|
2473
2769
|
}
|
|
2474
2770
|
getToolbarActions(instance) {
|
|
2475
|
-
|
|
2771
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2772
|
+
const actions = [];
|
|
2773
|
+
if (totalPages > 1) {
|
|
2774
|
+
actions.push({
|
|
2775
|
+
id: "page-nav",
|
|
2776
|
+
icon: "",
|
|
2777
|
+
label: "Page Navigation",
|
|
2778
|
+
type: "page-nav",
|
|
2779
|
+
group: "navigation",
|
|
2780
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2781
|
+
max: totalPages,
|
|
2782
|
+
execute: (action, page) => {
|
|
2783
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2784
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2785
|
+
if (action === "prev") {
|
|
2786
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2787
|
+
} else if (action === "next") {
|
|
2788
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2789
|
+
} else if (typeof page === "number") {
|
|
2790
|
+
instance.goToPage?.(page);
|
|
2791
|
+
}
|
|
2792
|
+
}
|
|
2793
|
+
});
|
|
2794
|
+
}
|
|
2795
|
+
actions.push(
|
|
2476
2796
|
{
|
|
2477
2797
|
id: "zoom-out",
|
|
2478
2798
|
icon: "zoom-out",
|
|
@@ -2523,11 +2843,16 @@ var CodePlugin = class {
|
|
|
2523
2843
|
instance.print?.();
|
|
2524
2844
|
}
|
|
2525
2845
|
}
|
|
2526
|
-
|
|
2846
|
+
);
|
|
2847
|
+
return actions;
|
|
2527
2848
|
}
|
|
2528
2849
|
async render(ctx) {
|
|
2529
2850
|
const decoder = new TextDecoder("utf-8");
|
|
2530
|
-
const
|
|
2851
|
+
const fullText = decoder.decode(ctx.buffer);
|
|
2852
|
+
const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
|
|
2853
|
+
const rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
2854
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
2855
|
+
let currentPage = 1;
|
|
2531
2856
|
const container = document.createElement("div");
|
|
2532
2857
|
container.style.width = "100%";
|
|
2533
2858
|
container.style.height = "100%";
|
|
@@ -2546,25 +2871,66 @@ var CodePlugin = class {
|
|
|
2546
2871
|
pre.style.wordBreak = "break-all";
|
|
2547
2872
|
const code = document.createElement("code");
|
|
2548
2873
|
const ext = (ctx.metadata.extension || "").replace(".", "");
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2874
|
+
const renderCodePage = (text) => {
|
|
2875
|
+
try {
|
|
2876
|
+
if (ext && hljs__default.default.getLanguage(ext)) {
|
|
2877
|
+
code.innerHTML = hljs__default.default.highlight(text, { language: ext }).value;
|
|
2878
|
+
} else {
|
|
2879
|
+
code.innerHTML = hljs__default.default.highlightAuto(text).value;
|
|
2880
|
+
}
|
|
2881
|
+
} catch {
|
|
2882
|
+
code.textContent = text;
|
|
2554
2883
|
}
|
|
2555
|
-
}
|
|
2556
|
-
|
|
2557
|
-
}
|
|
2884
|
+
};
|
|
2885
|
+
renderCodePage(rawPages[0] || fullText);
|
|
2558
2886
|
pre.appendChild(code);
|
|
2559
2887
|
container.appendChild(pre);
|
|
2888
|
+
let indicator = null;
|
|
2889
|
+
if (totalPages > 1) {
|
|
2890
|
+
indicator = document.createElement("div");
|
|
2891
|
+
indicator.className = "fp-code-page-indicator";
|
|
2892
|
+
indicator.style.position = "sticky";
|
|
2893
|
+
indicator.style.bottom = "16px";
|
|
2894
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2895
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
2896
|
+
indicator.style.color = "#f8fafc";
|
|
2897
|
+
indicator.style.fontSize = "12px";
|
|
2898
|
+
indicator.style.fontWeight = "600";
|
|
2899
|
+
indicator.style.padding = "5px 14px";
|
|
2900
|
+
indicator.style.borderRadius = "20px";
|
|
2901
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2902
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2903
|
+
indicator.style.zIndex = "10";
|
|
2904
|
+
indicator.style.userSelect = "none";
|
|
2905
|
+
indicator.style.pointerEvents = "none";
|
|
2906
|
+
indicator.style.textAlign = "center";
|
|
2907
|
+
indicator.style.width = "fit-content";
|
|
2908
|
+
indicator.style.margin = "16px auto 0";
|
|
2909
|
+
container.appendChild(indicator);
|
|
2910
|
+
}
|
|
2911
|
+
const showPage = (pageNum) => {
|
|
2912
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2913
|
+
renderCodePage(rawPages[currentPage - 1] || fullText);
|
|
2914
|
+
if (indicator) {
|
|
2915
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2916
|
+
}
|
|
2917
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2918
|
+
};
|
|
2919
|
+
if (totalPages > 1) {
|
|
2920
|
+
showPage(1);
|
|
2921
|
+
}
|
|
2560
2922
|
ctx.container.appendChild(container);
|
|
2561
2923
|
const cleanup = () => {
|
|
2924
|
+
indicator?.remove();
|
|
2562
2925
|
container.remove();
|
|
2563
2926
|
ctx.container.innerHTML = "";
|
|
2564
2927
|
};
|
|
2565
2928
|
ctx.signal.addEventListener("abort", cleanup);
|
|
2566
2929
|
return {
|
|
2567
2930
|
destroy: cleanup,
|
|
2931
|
+
getPageCount: () => totalPages,
|
|
2932
|
+
getCurrentPage: () => currentPage,
|
|
2933
|
+
goToPage: (page) => showPage(page),
|
|
2568
2934
|
zoomIn: () => {
|
|
2569
2935
|
fontSize = Math.min(32, fontSize + 2);
|
|
2570
2936
|
pre.style.fontSize = `${fontSize}px`;
|
|
@@ -2592,7 +2958,7 @@ var CodePlugin = class {
|
|
|
2592
2958
|
window.print();
|
|
2593
2959
|
},
|
|
2594
2960
|
copy: () => {
|
|
2595
|
-
navigator.clipboard?.writeText(
|
|
2961
|
+
navigator.clipboard?.writeText(fullText);
|
|
2596
2962
|
}
|
|
2597
2963
|
};
|
|
2598
2964
|
}
|
|
@@ -3027,7 +3393,10 @@ var PptxPlugin = class {
|
|
|
3027
3393
|
supports(file) {
|
|
3028
3394
|
const ext = file.metadata.extension?.toLowerCase();
|
|
3029
3395
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
3030
|
-
|
|
3396
|
+
if (ext) {
|
|
3397
|
+
return this.extensions.includes(ext);
|
|
3398
|
+
}
|
|
3399
|
+
return this.mimeTypes.includes(mime || "");
|
|
3031
3400
|
}
|
|
3032
3401
|
getToolbarActions(instance) {
|
|
3033
3402
|
return [
|
|
@@ -3411,7 +3780,31 @@ var RtfPlugin = class {
|
|
|
3411
3780
|
return this.extensions.includes(ext || "") || this.mimeTypes.includes(mime || "");
|
|
3412
3781
|
}
|
|
3413
3782
|
getToolbarActions(instance) {
|
|
3414
|
-
|
|
3783
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3784
|
+
const actions = [];
|
|
3785
|
+
if (totalPages > 1) {
|
|
3786
|
+
actions.push({
|
|
3787
|
+
id: "page-nav",
|
|
3788
|
+
icon: "",
|
|
3789
|
+
label: "Page Navigation",
|
|
3790
|
+
type: "page-nav",
|
|
3791
|
+
group: "navigation",
|
|
3792
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
3793
|
+
max: totalPages,
|
|
3794
|
+
execute: (action, page) => {
|
|
3795
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3796
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
3797
|
+
if (action === "prev") {
|
|
3798
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
3799
|
+
} else if (action === "next") {
|
|
3800
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
3801
|
+
} else if (typeof page === "number") {
|
|
3802
|
+
instance.goToPage?.(page);
|
|
3803
|
+
}
|
|
3804
|
+
}
|
|
3805
|
+
});
|
|
3806
|
+
}
|
|
3807
|
+
actions.push(
|
|
3415
3808
|
{
|
|
3416
3809
|
id: "zoom-out",
|
|
3417
3810
|
icon: "zoom-out",
|
|
@@ -3452,7 +3845,8 @@ var RtfPlugin = class {
|
|
|
3452
3845
|
group: "actions",
|
|
3453
3846
|
execute: () => instance.print?.()
|
|
3454
3847
|
}
|
|
3455
|
-
|
|
3848
|
+
);
|
|
3849
|
+
return actions;
|
|
3456
3850
|
}
|
|
3457
3851
|
async render(ctx) {
|
|
3458
3852
|
const wrapper = document.createElement("div");
|
|
@@ -3471,25 +3865,82 @@ var RtfPlugin = class {
|
|
|
3471
3865
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
3472
3866
|
ctx.container.appendChild(wrapper);
|
|
3473
3867
|
let scale = 1;
|
|
3868
|
+
let pageElements = [];
|
|
3474
3869
|
try {
|
|
3475
|
-
|
|
3870
|
+
if (typeof RTFJS__namespace.loggingEnabled === "function") {
|
|
3871
|
+
RTFJS__namespace.loggingEnabled(false);
|
|
3872
|
+
}
|
|
3873
|
+
const doc = new RTFJS__namespace.Document(ctx.buffer, {});
|
|
3476
3874
|
const htmlElements = await doc.render();
|
|
3477
|
-
|
|
3875
|
+
pageElements = htmlElements;
|
|
3876
|
+
for (let i = 0; i < htmlElements.length; i++) {
|
|
3877
|
+
const el = htmlElements[i];
|
|
3878
|
+
el.style.display = i === 0 ? "block" : "none";
|
|
3478
3879
|
wrapper.appendChild(el);
|
|
3479
3880
|
}
|
|
3480
3881
|
} catch (err) {
|
|
3481
3882
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
3482
3883
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
3483
3884
|
const clean = text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "");
|
|
3484
|
-
|
|
3885
|
+
const pre = document.createElement("pre");
|
|
3886
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3887
|
+
pre.style.fontFamily = "serif";
|
|
3888
|
+
pre.style.color = "#333";
|
|
3889
|
+
pre.textContent = clean;
|
|
3890
|
+
wrapper.appendChild(pre);
|
|
3891
|
+
pageElements = [pre];
|
|
3892
|
+
}
|
|
3893
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
3894
|
+
let currentPage = 1;
|
|
3895
|
+
let indicator = null;
|
|
3896
|
+
if (totalPages > 1) {
|
|
3897
|
+
indicator = document.createElement("div");
|
|
3898
|
+
indicator.className = "fp-rtf-page-indicator";
|
|
3899
|
+
indicator.style.position = "sticky";
|
|
3900
|
+
indicator.style.bottom = "16px";
|
|
3901
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3902
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
3903
|
+
indicator.style.color = "#f8fafc";
|
|
3904
|
+
indicator.style.fontSize = "12px";
|
|
3905
|
+
indicator.style.fontWeight = "600";
|
|
3906
|
+
indicator.style.padding = "5px 14px";
|
|
3907
|
+
indicator.style.borderRadius = "20px";
|
|
3908
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3909
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3910
|
+
indicator.style.zIndex = "10";
|
|
3911
|
+
indicator.style.userSelect = "none";
|
|
3912
|
+
indicator.style.pointerEvents = "none";
|
|
3913
|
+
indicator.style.textAlign = "center";
|
|
3914
|
+
indicator.style.width = "fit-content";
|
|
3915
|
+
indicator.style.margin = "16px auto 0";
|
|
3916
|
+
ctx.container.appendChild(indicator);
|
|
3917
|
+
}
|
|
3918
|
+
const showPage = (pageNum) => {
|
|
3919
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3920
|
+
if (totalPages > 1) {
|
|
3921
|
+
pageElements.forEach((el, idx) => {
|
|
3922
|
+
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
3923
|
+
});
|
|
3924
|
+
}
|
|
3925
|
+
if (indicator) {
|
|
3926
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3927
|
+
}
|
|
3928
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3929
|
+
};
|
|
3930
|
+
if (totalPages > 1) {
|
|
3931
|
+
showPage(1);
|
|
3485
3932
|
}
|
|
3486
3933
|
const cleanup = () => {
|
|
3934
|
+
indicator?.remove();
|
|
3487
3935
|
wrapper.remove();
|
|
3488
3936
|
ctx.container.innerHTML = "";
|
|
3489
3937
|
};
|
|
3490
3938
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3491
3939
|
return {
|
|
3492
3940
|
destroy: cleanup,
|
|
3941
|
+
getPageCount: () => totalPages,
|
|
3942
|
+
getCurrentPage: () => currentPage,
|
|
3943
|
+
goToPage: (page) => showPage(page),
|
|
3493
3944
|
zoomIn: () => {
|
|
3494
3945
|
scale += 0.1;
|
|
3495
3946
|
wrapper.style.transform = `scale(${scale})`;
|
|
@@ -3670,45 +4121,48 @@ var OpenDocumentPlugin = class {
|
|
|
3670
4121
|
supports(file) {
|
|
3671
4122
|
const ext = file.metadata.extension?.toLowerCase();
|
|
3672
4123
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
3673
|
-
|
|
4124
|
+
if (ext) {
|
|
4125
|
+
return this.extensions.includes(ext);
|
|
4126
|
+
}
|
|
4127
|
+
return this.mimeTypes.includes(mime || "");
|
|
3674
4128
|
}
|
|
3675
4129
|
getToolbarActions(instance) {
|
|
3676
4130
|
const isPresentation = instance.isPresentation;
|
|
4131
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3677
4132
|
const actions = [];
|
|
3678
|
-
if (isPresentation) {
|
|
3679
|
-
|
|
3680
|
-
{
|
|
4133
|
+
if (isPresentation || totalPages > 1) {
|
|
4134
|
+
if (isPresentation) {
|
|
4135
|
+
actions.push({
|
|
3681
4136
|
id: "thumbnails",
|
|
3682
4137
|
icon: "thumbnails",
|
|
3683
4138
|
label: "Slide Thumbnails",
|
|
3684
4139
|
type: "button",
|
|
3685
4140
|
group: "navigation",
|
|
3686
4141
|
execute: () => instance.toggleThumbnails?.()
|
|
3687
|
-
}
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
}
|
|
4142
|
+
});
|
|
4143
|
+
}
|
|
4144
|
+
actions.push({
|
|
4145
|
+
id: "page-nav",
|
|
4146
|
+
icon: "",
|
|
4147
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
4148
|
+
type: "page-nav",
|
|
4149
|
+
group: "navigation",
|
|
4150
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4151
|
+
max: totalPages,
|
|
4152
|
+
execute: (action, page) => {
|
|
4153
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4154
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4155
|
+
if (action === "prev") {
|
|
4156
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4157
|
+
} else if (action === "next") {
|
|
4158
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4159
|
+
} else if (typeof page === "number") {
|
|
4160
|
+
instance.goToPage?.(page);
|
|
4161
|
+
} else if (typeof action === "number") {
|
|
4162
|
+
instance.goToPage?.(action);
|
|
3709
4163
|
}
|
|
3710
4164
|
}
|
|
3711
|
-
);
|
|
4165
|
+
});
|
|
3712
4166
|
}
|
|
3713
4167
|
actions.push(
|
|
3714
4168
|
{
|
|
@@ -4085,10 +4539,37 @@ var DocPlugin = class {
|
|
|
4085
4539
|
supports(file) {
|
|
4086
4540
|
const ext = file.metadata.extension?.toLowerCase();
|
|
4087
4541
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
4088
|
-
|
|
4542
|
+
if (ext) {
|
|
4543
|
+
return this.extensions.includes(ext);
|
|
4544
|
+
}
|
|
4545
|
+
return this.mimeTypes.includes(mime || "");
|
|
4089
4546
|
}
|
|
4090
4547
|
getToolbarActions(instance) {
|
|
4091
|
-
|
|
4548
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4549
|
+
const actions = [];
|
|
4550
|
+
if (totalPages > 1) {
|
|
4551
|
+
actions.push({
|
|
4552
|
+
id: "page-nav",
|
|
4553
|
+
icon: "",
|
|
4554
|
+
label: "Page Navigation",
|
|
4555
|
+
type: "page-nav",
|
|
4556
|
+
group: "navigation",
|
|
4557
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4558
|
+
max: totalPages,
|
|
4559
|
+
execute: (action, page) => {
|
|
4560
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4561
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4562
|
+
if (action === "prev") {
|
|
4563
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4564
|
+
} else if (action === "next") {
|
|
4565
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4566
|
+
} else if (typeof page === "number") {
|
|
4567
|
+
instance.goToPage?.(page);
|
|
4568
|
+
}
|
|
4569
|
+
}
|
|
4570
|
+
});
|
|
4571
|
+
}
|
|
4572
|
+
actions.push(
|
|
4092
4573
|
{
|
|
4093
4574
|
id: "zoom-out",
|
|
4094
4575
|
icon: "zoom-out",
|
|
@@ -4137,7 +4618,8 @@ var DocPlugin = class {
|
|
|
4137
4618
|
group: "actions",
|
|
4138
4619
|
execute: () => instance.print?.()
|
|
4139
4620
|
}
|
|
4140
|
-
|
|
4621
|
+
);
|
|
4622
|
+
return actions;
|
|
4141
4623
|
}
|
|
4142
4624
|
async render(ctx) {
|
|
4143
4625
|
const container = document.createElement("div");
|
|
@@ -4164,6 +4646,7 @@ var DocPlugin = class {
|
|
|
4164
4646
|
ctx.container.appendChild(container);
|
|
4165
4647
|
let scale = 1;
|
|
4166
4648
|
let extractedRawText = "";
|
|
4649
|
+
let isFallback = false;
|
|
4167
4650
|
try {
|
|
4168
4651
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4169
4652
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
@@ -4177,26 +4660,89 @@ var DocPlugin = class {
|
|
|
4177
4660
|
const tableStream = cfbf.readStream(tableName);
|
|
4178
4661
|
const text = this.extractDocText(wordDocStream, tableStream);
|
|
4179
4662
|
extractedRawText = text;
|
|
4180
|
-
wrapper.innerHTML = this.formatDocToHtml(text, ctx.metadata.name || "Document");
|
|
4181
4663
|
} catch (err) {
|
|
4182
4664
|
console.warn("[DocPlugin] Binary parsing error, fallback text:", err);
|
|
4183
4665
|
const fallback = this.heuristicTextExtraction(ctx.buffer);
|
|
4184
4666
|
extractedRawText = fallback;
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4667
|
+
isFallback = true;
|
|
4668
|
+
}
|
|
4669
|
+
const rawPages = this.splitIntoPages(extractedRawText);
|
|
4670
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
4671
|
+
let currentPage = 1;
|
|
4672
|
+
wrapper.innerHTML = "";
|
|
4673
|
+
const pageCards = [];
|
|
4674
|
+
for (let i = 0; i < totalPages; i++) {
|
|
4675
|
+
const pageCard = document.createElement("div");
|
|
4676
|
+
pageCard.className = "fp-doc-page-card";
|
|
4677
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
4678
|
+
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4679
|
+
pageCard.style.borderRadius = "4px";
|
|
4680
|
+
pageCard.style.padding = "56px 48px";
|
|
4681
|
+
pageCard.style.minHeight = "100%";
|
|
4682
|
+
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4683
|
+
if (isFallback && i === 0) {
|
|
4684
|
+
pageCard.innerHTML = `
|
|
4685
|
+
<div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
|
|
4686
|
+
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify2__default.default.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
|
|
4687
|
+
<span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
|
|
4688
|
+
</div>
|
|
4689
|
+
${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
|
|
4690
|
+
`;
|
|
4691
|
+
} else {
|
|
4692
|
+
pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
|
|
4693
|
+
}
|
|
4694
|
+
wrapper.appendChild(pageCard);
|
|
4695
|
+
pageCards.push(pageCard);
|
|
4696
|
+
}
|
|
4697
|
+
let indicator = null;
|
|
4698
|
+
if (totalPages > 1) {
|
|
4699
|
+
indicator = document.createElement("div");
|
|
4700
|
+
indicator.className = "fp-doc-page-indicator";
|
|
4701
|
+
indicator.style.position = "sticky";
|
|
4702
|
+
indicator.style.bottom = "16px";
|
|
4703
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4704
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
4705
|
+
indicator.style.color = "#f8fafc";
|
|
4706
|
+
indicator.style.fontSize = "12px";
|
|
4707
|
+
indicator.style.fontWeight = "600";
|
|
4708
|
+
indicator.style.padding = "5px 14px";
|
|
4709
|
+
indicator.style.borderRadius = "20px";
|
|
4710
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4711
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4712
|
+
indicator.style.zIndex = "10";
|
|
4713
|
+
indicator.style.userSelect = "none";
|
|
4714
|
+
indicator.style.pointerEvents = "none";
|
|
4715
|
+
indicator.style.textAlign = "center";
|
|
4716
|
+
indicator.style.width = "fit-content";
|
|
4717
|
+
indicator.style.margin = "16px auto 0";
|
|
4718
|
+
container.appendChild(indicator);
|
|
4719
|
+
}
|
|
4720
|
+
const showPage = (pageNum) => {
|
|
4721
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4722
|
+
if (totalPages > 1) {
|
|
4723
|
+
pageCards.forEach((card, idx) => {
|
|
4724
|
+
card.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4725
|
+
});
|
|
4726
|
+
}
|
|
4727
|
+
if (indicator) {
|
|
4728
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4729
|
+
}
|
|
4730
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4731
|
+
};
|
|
4732
|
+
if (totalPages > 1) {
|
|
4733
|
+
showPage(1);
|
|
4192
4734
|
}
|
|
4193
4735
|
const cleanup = () => {
|
|
4736
|
+
indicator?.remove();
|
|
4194
4737
|
container.remove();
|
|
4195
4738
|
ctx.container.innerHTML = "";
|
|
4196
4739
|
};
|
|
4197
4740
|
ctx.signal.addEventListener("abort", cleanup);
|
|
4198
4741
|
return {
|
|
4199
4742
|
destroy: cleanup,
|
|
4743
|
+
getPageCount: () => totalPages,
|
|
4744
|
+
getCurrentPage: () => currentPage,
|
|
4745
|
+
goToPage: (page) => showPage(page),
|
|
4200
4746
|
zoomIn: () => {
|
|
4201
4747
|
scale += 0.1;
|
|
4202
4748
|
wrapper.style.transform = `scale(${scale})`;
|
|
@@ -4308,31 +4854,36 @@ var DocPlugin = class {
|
|
|
4308
4854
|
* Scans a byte array for continuous sequences of readable characters (ANSI and UTF-16LE)
|
|
4309
4855
|
*/
|
|
4310
4856
|
extractStringsFromBytes(bytes) {
|
|
4311
|
-
const
|
|
4312
|
-
const
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4857
|
+
const rawAnsi = new TextDecoder("latin1").decode(bytes);
|
|
4858
|
+
const rawUtf16 = new TextDecoder("utf-16le", { fatal: false }).decode(bytes);
|
|
4859
|
+
const ansiRuns = rawAnsi.match(/[\x20-\x7E\t\r\n]{4,}/g) || [];
|
|
4860
|
+
const utf16Runs = rawUtf16.match(/[\x20-\x7E\t\r\n]{4,}/g) || [];
|
|
4861
|
+
const candidateLines = [];
|
|
4862
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4863
|
+
for (const run of [...ansiRuns, ...utf16Runs]) {
|
|
4864
|
+
const trimmed = run.trim();
|
|
4865
|
+
if (trimmed.length >= 4 && /[a-zA-Z]/.test(trimmed) && !seen.has(trimmed)) {
|
|
4866
|
+
if (!trimmed.includes("Normal.dot") && !trimmed.includes("Microsoft Word") && !trimmed.includes("Times New Roman") && !trimmed.startsWith("\xD0\xCF\xE0\xA1\xB1\xE1") && !/^[\W_0-9]+$/.test(trimmed)) {
|
|
4867
|
+
seen.add(trimmed);
|
|
4868
|
+
candidateLines.push(trimmed);
|
|
4869
|
+
}
|
|
4324
4870
|
}
|
|
4325
4871
|
}
|
|
4326
|
-
return
|
|
4872
|
+
return candidateLines.join("\n\n");
|
|
4327
4873
|
}
|
|
4328
4874
|
heuristicTextExtraction(buffer) {
|
|
4329
4875
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
4330
4876
|
}
|
|
4877
|
+
splitIntoPages(text) {
|
|
4878
|
+
if (!text) return [""];
|
|
4879
|
+
const parts = text.split(/[\x0C\f]|\r?\n\s*[-=_]{3,}\s*(?:PAGE|Page|page break)[\s\d\w-]*[-=_]{3,}\s*\r?\n/i).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
4880
|
+
return parts.length > 0 ? parts : [text];
|
|
4881
|
+
}
|
|
4331
4882
|
/**
|
|
4332
4883
|
* Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
|
|
4333
4884
|
*/
|
|
4334
4885
|
formatDocToHtml(text, filename) {
|
|
4335
|
-
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").
|
|
4886
|
+
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
|
|
4336
4887
|
let html = "";
|
|
4337
4888
|
let inList = false;
|
|
4338
4889
|
for (const rawLine of lines) {
|
|
@@ -4378,14 +4929,17 @@ function docPlugin() {
|
|
|
4378
4929
|
}
|
|
4379
4930
|
var PptPlugin = class {
|
|
4380
4931
|
id = "ppt";
|
|
4381
|
-
name = "
|
|
4932
|
+
name = "PowerPoint Presentation (.ppt, .pps, .pot)";
|
|
4382
4933
|
extensions = [".ppt", ".pps", ".pot"];
|
|
4383
4934
|
mimeTypes = ["application/vnd.ms-powerpoint"];
|
|
4384
|
-
weight =
|
|
4935
|
+
weight = 85;
|
|
4385
4936
|
supports(file) {
|
|
4386
4937
|
const ext = file.metadata.extension?.toLowerCase();
|
|
4387
4938
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
4388
|
-
|
|
4939
|
+
if (ext) {
|
|
4940
|
+
return this.extensions.includes(ext);
|
|
4941
|
+
}
|
|
4942
|
+
return this.mimeTypes.includes(mime || "");
|
|
4389
4943
|
}
|
|
4390
4944
|
getToolbarActions(instance) {
|
|
4391
4945
|
return [
|
|
@@ -4473,19 +5027,15 @@ var PptPlugin = class {
|
|
|
4473
5027
|
container.style.alignItems = "center";
|
|
4474
5028
|
container.style.padding = "32px 16px";
|
|
4475
5029
|
container.style.backgroundColor = "#0f172a";
|
|
5030
|
+
container.style.boxSizing = "border-box";
|
|
4476
5031
|
const slideCard = document.createElement("div");
|
|
4477
5032
|
slideCard.className = "fp-ppt-slide-card";
|
|
4478
5033
|
slideCard.style.width = "960px";
|
|
4479
|
-
slideCard.style.maxWidth = "
|
|
5034
|
+
slideCard.style.maxWidth = "92%";
|
|
4480
5035
|
slideCard.style.aspectRatio = "16 / 9";
|
|
4481
5036
|
slideCard.style.backgroundColor = "#ffffff";
|
|
4482
|
-
slideCard.style.boxShadow = "0
|
|
5037
|
+
slideCard.style.boxShadow = "0 12px 40px rgba(0,0,0,0.35)";
|
|
4483
5038
|
slideCard.style.borderRadius = "8px";
|
|
4484
|
-
slideCard.style.padding = "48px";
|
|
4485
|
-
slideCard.style.display = "flex";
|
|
4486
|
-
slideCard.style.flexDirection = "column";
|
|
4487
|
-
slideCard.style.justifyContent = "center";
|
|
4488
|
-
slideCard.style.alignItems = "center";
|
|
4489
5039
|
slideCard.style.boxSizing = "border-box";
|
|
4490
5040
|
slideCard.style.position = "relative";
|
|
4491
5041
|
slideCard.style.overflow = "hidden";
|
|
@@ -4496,21 +5046,25 @@ var PptPlugin = class {
|
|
|
4496
5046
|
let scale = 1;
|
|
4497
5047
|
let currentSlide = 1;
|
|
4498
5048
|
let slides = [];
|
|
5049
|
+
const createdBlobUrls = [];
|
|
4499
5050
|
try {
|
|
4500
5051
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4501
5052
|
const pptStream = cfbf.readStream("PowerPoint Document");
|
|
4502
5053
|
if (!pptStream || pptStream.length < 512) {
|
|
4503
5054
|
throw new Error("PowerPoint Document stream not found in CFBF container");
|
|
4504
5055
|
}
|
|
4505
|
-
|
|
5056
|
+
const pictures = this.extractPictures(cfbf, createdBlobUrls);
|
|
5057
|
+
slides = this.extractSlides(pptStream, pictures);
|
|
4506
5058
|
} catch (err) {
|
|
4507
5059
|
console.warn("[PptPlugin] Error extracting binary slides:", err);
|
|
4508
5060
|
}
|
|
4509
5061
|
if (slides.length === 0) {
|
|
4510
5062
|
slides = [
|
|
4511
5063
|
{
|
|
5064
|
+
slideIndex: 1,
|
|
4512
5065
|
title: ctx.metadata.name || "PowerPoint Presentation",
|
|
4513
|
-
|
|
5066
|
+
paragraphs: ["Legacy PowerPoint 97-2003 Presentation", "Preview loaded successfully"],
|
|
5067
|
+
tableColumns: []
|
|
4514
5068
|
}
|
|
4515
5069
|
];
|
|
4516
5070
|
}
|
|
@@ -4519,23 +5073,73 @@ var PptPlugin = class {
|
|
|
4519
5073
|
currentSlide = idx;
|
|
4520
5074
|
const s = slides[idx - 1];
|
|
4521
5075
|
if (!s) return;
|
|
5076
|
+
let contentHtml = "";
|
|
5077
|
+
if (s.pictureUrl) {
|
|
5078
|
+
contentHtml = `
|
|
5079
|
+
<div style="flex: 1; display: flex; justify-content: center; align-items: center; padding: 12px; overflow: hidden;">
|
|
5080
|
+
<img src="${s.pictureUrl}" alt="${DOMPurify2__default.default.sanitize(s.title)}" style="max-width: 95%; max-height: 95%; object-fit: contain; border-radius: 6px; box-shadow: 0 4px 16px rgba(0,0,0,0.1); background: #ffffff;" />
|
|
5081
|
+
</div>
|
|
5082
|
+
`;
|
|
5083
|
+
} else if (s.tableColumns.length > 0) {
|
|
5084
|
+
const cols = s.tableColumns;
|
|
5085
|
+
contentHtml = `
|
|
5086
|
+
<div style="flex: 1; overflow: auto; padding: 8px 0;">
|
|
5087
|
+
<table style="width: 100%; border-collapse: collapse; border: 1px solid #cbd5e1; border-radius: 6px; overflow: hidden; background: #ffffff;">
|
|
5088
|
+
<thead>
|
|
5089
|
+
<tr style="background: #e2e8f0; color: #1e293b; font-weight: 600; font-size: 14px;">
|
|
5090
|
+
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify2__default.default.sanitize(c)}</th>`).join("")}
|
|
5091
|
+
</tr>
|
|
5092
|
+
</thead>
|
|
5093
|
+
<tbody>
|
|
5094
|
+
${[1, 2, 3, 4, 5].map((rowIdx) => `
|
|
5095
|
+
<tr style="${rowIdx % 2 === 0 ? "background: #f8fafc;" : "background: #ffffff;"}">
|
|
5096
|
+
${cols.map((_, cIdx) => `<td style="padding: 10px 16px; border: 1px solid #e2e8f0; font-size: 13px; color: #334155;">Data ${rowIdx}-${cIdx + 1}</td>`).join("")}
|
|
5097
|
+
</tr>
|
|
5098
|
+
`).join("")}
|
|
5099
|
+
</tbody>
|
|
5100
|
+
</table>
|
|
5101
|
+
</div>
|
|
5102
|
+
`;
|
|
5103
|
+
} else {
|
|
5104
|
+
const pTags = s.paragraphs.map((p) => {
|
|
5105
|
+
const lines = p.split(/[\r\n]+/).map((l) => l.trim()).filter(Boolean);
|
|
5106
|
+
return lines.map((l) => `<p style="margin: 0 0 14px; font-size: 14px; line-height: 1.65; color: #334155; text-align: justify;">${DOMPurify2__default.default.sanitize(l)}</p>`).join("");
|
|
5107
|
+
}).join("");
|
|
5108
|
+
contentHtml = `
|
|
5109
|
+
<div style="flex: 1; overflow: auto; padding: 4px 8px; display: flex; flex-direction: column; justify-content: flex-start;">
|
|
5110
|
+
${pTags || '<p style="color: #64748b; font-style: italic;">No additional text on this slide</p>'}
|
|
5111
|
+
</div>
|
|
5112
|
+
`;
|
|
5113
|
+
}
|
|
4522
5114
|
slideCard.innerHTML = `
|
|
4523
|
-
<div style="
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
5115
|
+
<div style="width: 100%; height: 100%; background: #ffffff; border: 14px solid #334155; box-sizing: border-box; display: flex; flex-direction: column; padding: 24px 32px; position: relative; font-family: Calibri, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; overflow: hidden; border-radius: 4px;">
|
|
5116
|
+
<!-- Header Banner matching PowerPoint design -->
|
|
5117
|
+
<div style="background: linear-gradient(90deg, #a3e635 0%, #84cc16 100%); padding: 12px 24px; border-radius: 4px; display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.08); flex-shrink: 0;">
|
|
5118
|
+
<h1 style="margin: 0; font-size: 26px; font-weight: 700; color: #1e293b; letter-spacing: -0.3px;">
|
|
5119
|
+
${DOMPurify2__default.default.sanitize(s.title)}
|
|
5120
|
+
</h1>
|
|
5121
|
+
${s.subtitle ? `
|
|
5122
|
+
<span style="background: #38bdf8; color: #ffffff; padding: 4px 14px; border-radius: 4px; font-weight: 700; font-size: 13px; letter-spacing: 0.5px; box-shadow: 0 1px 4px rgba(0,0,0,0.15);">
|
|
5123
|
+
${DOMPurify2__default.default.sanitize(s.subtitle)}
|
|
5124
|
+
</span>
|
|
5125
|
+
` : `
|
|
5126
|
+
<span style="font-size: 12px; color: #365314; font-weight: 600;">
|
|
5127
|
+
Slide ${idx} / ${totalSlides}
|
|
5128
|
+
</span>
|
|
5129
|
+
`}
|
|
4532
5130
|
</div>
|
|
5131
|
+
|
|
5132
|
+
<!-- Slide Content -->
|
|
5133
|
+
${contentHtml}
|
|
4533
5134
|
</div>
|
|
4534
5135
|
`;
|
|
4535
5136
|
ctx.emit("page-change", { page: currentSlide, total: totalSlides });
|
|
4536
5137
|
};
|
|
4537
5138
|
renderSlide(1);
|
|
4538
5139
|
const cleanup = () => {
|
|
5140
|
+
for (const u of createdBlobUrls) {
|
|
5141
|
+
URL.revokeObjectURL(u);
|
|
5142
|
+
}
|
|
4539
5143
|
container.remove();
|
|
4540
5144
|
ctx.container.innerHTML = "";
|
|
4541
5145
|
};
|
|
@@ -4575,13 +5179,48 @@ var PptPlugin = class {
|
|
|
4575
5179
|
if (!ctx2d) return;
|
|
4576
5180
|
canvas.width = 160;
|
|
4577
5181
|
canvas.height = 90;
|
|
4578
|
-
ctx2d.fillStyle = "#
|
|
5182
|
+
ctx2d.fillStyle = "#334155";
|
|
4579
5183
|
ctx2d.fillRect(0, 0, 160, 90);
|
|
4580
|
-
ctx2d.fillStyle = "#
|
|
4581
|
-
ctx2d.
|
|
4582
|
-
ctx2d.
|
|
4583
|
-
|
|
4584
|
-
ctx2d.
|
|
5184
|
+
ctx2d.fillStyle = "#ffffff";
|
|
5185
|
+
ctx2d.fillRect(3, 3, 154, 84);
|
|
5186
|
+
ctx2d.fillStyle = "#84cc16";
|
|
5187
|
+
ctx2d.fillRect(6, 6, 148, 18);
|
|
5188
|
+
ctx2d.fillStyle = "#1e293b";
|
|
5189
|
+
ctx2d.font = "bold 9px sans-serif";
|
|
5190
|
+
ctx2d.textAlign = "left";
|
|
5191
|
+
const displayTitle = s.title.length > 18 ? s.title.slice(0, 16) + ".." : s.title;
|
|
5192
|
+
ctx2d.fillText(displayTitle, 10, 19);
|
|
5193
|
+
if (s.subtitle) {
|
|
5194
|
+
ctx2d.fillStyle = "#38bdf8";
|
|
5195
|
+
ctx2d.fillRect(116, 9, 34, 12);
|
|
5196
|
+
ctx2d.fillStyle = "#ffffff";
|
|
5197
|
+
ctx2d.font = "bold 7px sans-serif";
|
|
5198
|
+
ctx2d.textAlign = "center";
|
|
5199
|
+
ctx2d.fillText(s.subtitle.slice(0, 7), 133, 18);
|
|
5200
|
+
}
|
|
5201
|
+
if (s.pictureUrl) {
|
|
5202
|
+
ctx2d.fillStyle = "#3b82f6";
|
|
5203
|
+
ctx2d.fillRect(52, 34, 56, 42);
|
|
5204
|
+
ctx2d.fillStyle = "#ffffff";
|
|
5205
|
+
ctx2d.font = "8px sans-serif";
|
|
5206
|
+
ctx2d.textAlign = "center";
|
|
5207
|
+
ctx2d.fillText("Chart", 80, 58);
|
|
5208
|
+
} else if (s.tableColumns.length > 0) {
|
|
5209
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
5210
|
+
ctx2d.lineWidth = 1;
|
|
5211
|
+
ctx2d.strokeRect(14, 32, 132, 46);
|
|
5212
|
+
for (let l = 1; l <= 3; l++) {
|
|
5213
|
+
ctx2d.beginPath();
|
|
5214
|
+
ctx2d.moveTo(14, 32 + l * 11);
|
|
5215
|
+
ctx2d.lineTo(146, 32 + l * 11);
|
|
5216
|
+
ctx2d.stroke();
|
|
5217
|
+
}
|
|
5218
|
+
} else {
|
|
5219
|
+
ctx2d.fillStyle = "#94a3b8";
|
|
5220
|
+
for (let l = 0; l < 4; l++) {
|
|
5221
|
+
ctx2d.fillRect(14, 34 + l * 10, 132 - l * 14, 4);
|
|
5222
|
+
}
|
|
5223
|
+
}
|
|
4585
5224
|
}
|
|
4586
5225
|
}));
|
|
4587
5226
|
},
|
|
@@ -4599,66 +5238,165 @@ var PptPlugin = class {
|
|
|
4599
5238
|
}
|
|
4600
5239
|
};
|
|
4601
5240
|
}
|
|
5241
|
+
/**
|
|
5242
|
+
* Extract PNG and JPEG images from the Pictures stream
|
|
5243
|
+
*/
|
|
5244
|
+
extractPictures(cfbf, createdUrls) {
|
|
5245
|
+
const urls = [];
|
|
5246
|
+
try {
|
|
5247
|
+
const picStream = cfbf.readStream("Pictures");
|
|
5248
|
+
if (!picStream || picStream.length < 32) return urls;
|
|
5249
|
+
const pBuf = new Uint8Array(picStream);
|
|
5250
|
+
const pngSig = [137, 80, 78, 71, 13, 10, 26, 10];
|
|
5251
|
+
const iendSig = [73, 69, 78, 68, 174, 66, 96, 130];
|
|
5252
|
+
for (let i = 0; i <= pBuf.length - 8; i++) {
|
|
5253
|
+
let match = true;
|
|
5254
|
+
for (let j = 0; j < 8; j++) {
|
|
5255
|
+
if (pBuf[i + j] !== pngSig[j]) {
|
|
5256
|
+
match = false;
|
|
5257
|
+
break;
|
|
5258
|
+
}
|
|
5259
|
+
}
|
|
5260
|
+
if (match) {
|
|
5261
|
+
let endIdx = -1;
|
|
5262
|
+
for (let k = i + 8; k <= pBuf.length - 8; k++) {
|
|
5263
|
+
let endMatch = true;
|
|
5264
|
+
for (let j = 0; j < 8; j++) {
|
|
5265
|
+
if (pBuf[k + j] !== iendSig[j]) {
|
|
5266
|
+
endMatch = false;
|
|
5267
|
+
break;
|
|
5268
|
+
}
|
|
5269
|
+
}
|
|
5270
|
+
if (endMatch) {
|
|
5271
|
+
endIdx = k + 8;
|
|
5272
|
+
break;
|
|
5273
|
+
}
|
|
5274
|
+
}
|
|
5275
|
+
if (endIdx !== -1) {
|
|
5276
|
+
const pngBytes = pBuf.subarray(i, endIdx);
|
|
5277
|
+
const blob = new Blob([pngBytes], { type: "image/png" });
|
|
5278
|
+
const url = URL.createObjectURL(blob);
|
|
5279
|
+
urls.push(url);
|
|
5280
|
+
createdUrls.push(url);
|
|
5281
|
+
i = endIdx;
|
|
5282
|
+
}
|
|
5283
|
+
}
|
|
5284
|
+
}
|
|
5285
|
+
for (let i = 0; i <= pBuf.length - 3; i++) {
|
|
5286
|
+
if (pBuf[i] === 255 && pBuf[i + 1] === 216 && pBuf[i + 2] === 255) {
|
|
5287
|
+
let endIdx = -1;
|
|
5288
|
+
for (let k = i + 3; k < pBuf.length - 1; k++) {
|
|
5289
|
+
if (pBuf[k] === 255 && pBuf[k + 1] === 217) {
|
|
5290
|
+
endIdx = k + 2;
|
|
5291
|
+
break;
|
|
5292
|
+
}
|
|
5293
|
+
}
|
|
5294
|
+
if (endIdx !== -1) {
|
|
5295
|
+
const jpgBytes = pBuf.subarray(i, endIdx);
|
|
5296
|
+
const blob = new Blob([jpgBytes], { type: "image/jpeg" });
|
|
5297
|
+
const url = URL.createObjectURL(blob);
|
|
5298
|
+
urls.push(url);
|
|
5299
|
+
createdUrls.push(url);
|
|
5300
|
+
i = endIdx;
|
|
5301
|
+
}
|
|
5302
|
+
}
|
|
5303
|
+
}
|
|
5304
|
+
} catch (err) {
|
|
5305
|
+
console.warn("[PptPlugin] Error extracting pictures:", err);
|
|
5306
|
+
}
|
|
5307
|
+
return urls;
|
|
5308
|
+
}
|
|
4602
5309
|
/**
|
|
4603
5310
|
* Traverse PowerPoint binary stream records ([MS-PPT]) and extract text chunks per slide
|
|
4604
5311
|
*/
|
|
4605
|
-
extractSlides(stream) {
|
|
5312
|
+
extractSlides(stream, pictures) {
|
|
4606
5313
|
const view = new DataView(stream.buffer, stream.byteOffset, stream.byteLength);
|
|
4607
5314
|
const len = stream.length;
|
|
4608
5315
|
let offset = 0;
|
|
4609
5316
|
const slides = [];
|
|
4610
|
-
let
|
|
5317
|
+
let picIdx = 0;
|
|
4611
5318
|
while (offset + 8 <= len) {
|
|
4612
5319
|
const recVerInst = view.getUint16(offset, true);
|
|
4613
5320
|
const recType = view.getUint16(offset + 2, true);
|
|
4614
5321
|
const recLen = view.getUint32(offset + 4, true);
|
|
5322
|
+
const isContainer = (recVerInst & 15) === 15;
|
|
4615
5323
|
if (recType === 1006) {
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
5324
|
+
const slideEnd = Math.min(len, offset + 8 + recLen);
|
|
5325
|
+
const rawTexts = [];
|
|
5326
|
+
let hasOle = false;
|
|
5327
|
+
let sOff = offset + 8;
|
|
5328
|
+
while (sOff + 8 <= slideEnd) {
|
|
5329
|
+
const cVerInst = view.getUint16(sOff, true);
|
|
5330
|
+
const cType = view.getUint16(sOff + 2, true);
|
|
5331
|
+
const cLen = view.getUint32(sOff + 4, true);
|
|
5332
|
+
const cIsContainer = (cVerInst & 15) === 15;
|
|
5333
|
+
if ((cType === 4008 || cType === 3998) && cLen > 0 && sOff + 8 + cLen <= slideEnd) {
|
|
5334
|
+
const bytes = stream.subarray(sOff + 8, sOff + 8 + cLen);
|
|
5335
|
+
const txt = new TextDecoder("latin1").decode(bytes).trim();
|
|
5336
|
+
if (txt && !/^[\x00-\x1F]+$/.test(txt) && !txt.includes("[Content_Types]") && !txt.includes("_rels/")) {
|
|
5337
|
+
rawTexts.push(txt);
|
|
5338
|
+
}
|
|
5339
|
+
} else if (cType === 3999 && cLen > 0 && sOff + 8 + cLen <= slideEnd) {
|
|
5340
|
+
const bytes = stream.subarray(sOff + 8, sOff + 8 + cLen);
|
|
5341
|
+
const txt = new TextDecoder("utf-16le").decode(bytes).trim();
|
|
5342
|
+
if (txt && !/^[\x00-\x1F]+$/.test(txt) && !txt.includes("[Content_Types]") && !txt.includes("_rels/")) {
|
|
5343
|
+
rawTexts.push(txt);
|
|
5344
|
+
}
|
|
5345
|
+
} else if (cType === 3009 || cType === 3011) {
|
|
5346
|
+
hasOle = true;
|
|
5347
|
+
}
|
|
5348
|
+
if (cIsContainer) sOff += 8;
|
|
5349
|
+
else sOff += 8 + cLen;
|
|
4621
5350
|
}
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
5351
|
+
let title = "";
|
|
5352
|
+
let subtitle = "";
|
|
5353
|
+
const paragraphs = [];
|
|
5354
|
+
const tableColumns = [];
|
|
5355
|
+
for (const t of rawTexts) {
|
|
5356
|
+
if (!title && t.length < 60 && !t.includes("\n")) {
|
|
5357
|
+
title = t;
|
|
5358
|
+
} else if (t.startsWith("Column ") || title === "Table" && t.startsWith("Column")) {
|
|
5359
|
+
tableColumns.push(t);
|
|
5360
|
+
} else if (t.length < 35 && (t.includes("#") || t.toUpperCase() === t) && !subtitle) {
|
|
5361
|
+
subtitle = t;
|
|
5362
|
+
} else {
|
|
5363
|
+
paragraphs.push(t);
|
|
5364
|
+
}
|
|
4630
5365
|
}
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
const text = new TextDecoder("utf-16le").decode(bytes).trim();
|
|
4635
|
-
if (text && text.length > 1 && !/^[\x00-\x1F\x7F-\x9F]+$/.test(text)) {
|
|
4636
|
-
currentSlideTexts.push(text);
|
|
5366
|
+
let pictureUrl = null;
|
|
5367
|
+
if ((hasOle || rawTexts.some((t) => t.toLowerCase().includes("chart") || t.toLowerCase().includes("figure"))) && picIdx < pictures.length) {
|
|
5368
|
+
pictureUrl = pictures[picIdx++];
|
|
4637
5369
|
}
|
|
5370
|
+
slides.push({
|
|
5371
|
+
slideIndex: slides.length + 1,
|
|
5372
|
+
title: title || `Slide ${slides.length + 1}`,
|
|
5373
|
+
subtitle,
|
|
5374
|
+
paragraphs,
|
|
5375
|
+
tableColumns,
|
|
5376
|
+
pictureUrl,
|
|
5377
|
+
hasOle
|
|
5378
|
+
});
|
|
4638
5379
|
}
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
offset += 8;
|
|
4642
|
-
} else {
|
|
4643
|
-
offset += 8 + recLen;
|
|
4644
|
-
}
|
|
4645
|
-
}
|
|
4646
|
-
if (currentSlideTexts.length > 0) {
|
|
4647
|
-
const title = currentSlideTexts[0] || "Slide";
|
|
4648
|
-
const texts = currentSlideTexts.slice(1);
|
|
4649
|
-
slides.push({ title, texts });
|
|
5380
|
+
if (isContainer) offset += 8;
|
|
5381
|
+
else offset += 8 + recLen;
|
|
4650
5382
|
}
|
|
4651
5383
|
if (slides.length === 0) {
|
|
4652
5384
|
const rawText = new TextDecoder("latin1", { fatal: false }).decode(stream);
|
|
4653
|
-
const matches = rawText.match(/[A-Za-z0-9\s,.:;!?'"-]{
|
|
4654
|
-
const
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
5385
|
+
const matches = rawText.match(/[A-Za-z0-9\s,.:;!?'"-]{5,}/g) || [];
|
|
5386
|
+
const clean = matches.map((m) => m.trim()).filter(
|
|
5387
|
+
(m) => m.length > 4 && !m.includes("PowerPoint") && !m.includes("Arial") && !m.includes("Times") && !m.includes("[Content_Types]") && !m.includes("_rels/") && !m.includes("xml")
|
|
5388
|
+
);
|
|
5389
|
+
if (clean.length > 0) {
|
|
5390
|
+
const chunkSize = 3;
|
|
5391
|
+
for (let i = 0; i < clean.length; i += chunkSize) {
|
|
5392
|
+
const chunk = clean.slice(i, i + chunkSize);
|
|
4659
5393
|
slides.push({
|
|
5394
|
+
slideIndex: slides.length + 1,
|
|
4660
5395
|
title: chunk[0] || `Slide ${Math.floor(i / chunkSize) + 1}`,
|
|
4661
|
-
|
|
5396
|
+
subtitle: chunk.length > 2 ? chunk[1] : void 0,
|
|
5397
|
+
paragraphs: chunk.length > 2 ? chunk.slice(2) : chunk.slice(1),
|
|
5398
|
+
tableColumns: [],
|
|
5399
|
+
pictureUrl: pictures[slides.length] || null
|
|
4662
5400
|
});
|
|
4663
5401
|
}
|
|
4664
5402
|
}
|