@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/index.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var DOMPurify2 = require('dompurify');
|
|
4
|
+
var pdfjsLib = require('pdfjs-dist');
|
|
4
5
|
var docx = require('docx-preview');
|
|
5
6
|
var fflate = require('fflate');
|
|
6
7
|
var XLSX = require('xlsx');
|
|
@@ -11,7 +12,7 @@ var THREE = require('three');
|
|
|
11
12
|
var STLLoader_js = require('three/examples/jsm/loaders/STLLoader.js');
|
|
12
13
|
var OBJLoader_js = require('three/examples/jsm/loaders/OBJLoader.js');
|
|
13
14
|
var OrbitControls_js = require('three/examples/jsm/controls/OrbitControls.js');
|
|
14
|
-
var
|
|
15
|
+
var RTFJS = require('rtf.js/dist/RTFJS.bundle.js');
|
|
15
16
|
|
|
16
17
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
17
18
|
|
|
@@ -34,10 +35,12 @@ function _interopNamespace(e) {
|
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
var DOMPurify2__default = /*#__PURE__*/_interopDefault(DOMPurify2);
|
|
38
|
+
var pdfjsLib__namespace = /*#__PURE__*/_interopNamespace(pdfjsLib);
|
|
37
39
|
var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
|
|
38
40
|
var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
|
|
39
41
|
var hljs__default = /*#__PURE__*/_interopDefault(hljs);
|
|
40
42
|
var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
|
|
43
|
+
var RTFJS__namespace = /*#__PURE__*/_interopNamespace(RTFJS);
|
|
41
44
|
|
|
42
45
|
// ../core/dist/index.js
|
|
43
46
|
var EventEmitter = class {
|
|
@@ -293,6 +296,39 @@ function detectOoxmlType(buffer) {
|
|
|
293
296
|
}
|
|
294
297
|
return "application/zip";
|
|
295
298
|
}
|
|
299
|
+
function detectCfbfType(buffer) {
|
|
300
|
+
const bytes = new Uint8Array(buffer);
|
|
301
|
+
const hasUtf16le = (str) => {
|
|
302
|
+
const target = new Uint8Array(str.length * 2);
|
|
303
|
+
for (let i = 0; i < str.length; i++) {
|
|
304
|
+
target[i * 2] = str.charCodeAt(i);
|
|
305
|
+
target[i * 2 + 1] = 0;
|
|
306
|
+
}
|
|
307
|
+
const targetLen = target.length;
|
|
308
|
+
const max = bytes.length - targetLen;
|
|
309
|
+
for (let i = 0; i <= max; i++) {
|
|
310
|
+
let match = true;
|
|
311
|
+
for (let j = 0; j < targetLen; j++) {
|
|
312
|
+
if (bytes[i + j] !== target[j]) {
|
|
313
|
+
match = false;
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (match) return true;
|
|
318
|
+
}
|
|
319
|
+
return false;
|
|
320
|
+
};
|
|
321
|
+
if (hasUtf16le("PowerPoint Document")) {
|
|
322
|
+
return { mime: "application/vnd.ms-powerpoint", extension: ".ppt" };
|
|
323
|
+
}
|
|
324
|
+
if (hasUtf16le("WordDocument")) {
|
|
325
|
+
return { mime: "application/msword", extension: ".doc" };
|
|
326
|
+
}
|
|
327
|
+
if (hasUtf16le("Workbook") || hasUtf16le("Book")) {
|
|
328
|
+
return { mime: "application/vnd.ms-excel", extension: ".xls" };
|
|
329
|
+
}
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
296
332
|
function extractExtension(nameOrUrl) {
|
|
297
333
|
try {
|
|
298
334
|
const url = new URL(nameOrUrl);
|
|
@@ -357,6 +393,18 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
357
393
|
} else {
|
|
358
394
|
metadata.mimeType = metadata.mimeType ?? magicMime;
|
|
359
395
|
}
|
|
396
|
+
} else if (magicMime === "application/x-cfbf") {
|
|
397
|
+
if (metadata.extension) {
|
|
398
|
+
metadata.mimeType = mimeFromExtension(metadata.extension) ?? magicMime;
|
|
399
|
+
} else {
|
|
400
|
+
const cfbf = detectCfbfType(buffer);
|
|
401
|
+
if (cfbf) {
|
|
402
|
+
metadata.mimeType = cfbf.mime;
|
|
403
|
+
metadata.extension = cfbf.extension;
|
|
404
|
+
} else {
|
|
405
|
+
metadata.mimeType = magicMime;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
360
408
|
} else {
|
|
361
409
|
metadata.mimeType = magicMime;
|
|
362
410
|
}
|
|
@@ -505,11 +553,21 @@ var ToolbarController = class {
|
|
|
505
553
|
el;
|
|
506
554
|
toolbarEl;
|
|
507
555
|
actions = [];
|
|
556
|
+
pageInputEl = null;
|
|
557
|
+
pageLabelEl = null;
|
|
508
558
|
constructor(container) {
|
|
509
559
|
this.el = container;
|
|
510
560
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
511
561
|
this.el.appendChild(this.toolbarEl);
|
|
512
562
|
}
|
|
563
|
+
setPage(page, max) {
|
|
564
|
+
if (this.pageInputEl) {
|
|
565
|
+
this.pageInputEl.value = page.toString();
|
|
566
|
+
}
|
|
567
|
+
if (max !== void 0 && this.pageLabelEl) {
|
|
568
|
+
this.pageLabelEl.textContent = ` / ${max}`;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
513
571
|
update(actions) {
|
|
514
572
|
this.actions = actions;
|
|
515
573
|
this.render();
|
|
@@ -552,6 +610,7 @@ var ToolbarController = class {
|
|
|
552
610
|
if (action.type === "separator") {
|
|
553
611
|
groupEl.appendChild(createElement("div", { className: "fp-toolbar-separator" }));
|
|
554
612
|
} else if (action.type === "page-nav") {
|
|
613
|
+
const max = action.max ?? 1;
|
|
555
614
|
const prevBtn = this.createButton(
|
|
556
615
|
"prev",
|
|
557
616
|
ICON_PAGE_PREV,
|
|
@@ -570,7 +629,6 @@ var ToolbarController = class {
|
|
|
570
629
|
"Next Page",
|
|
571
630
|
() => {
|
|
572
631
|
const cur = parseInt(input.value, 10) || 1;
|
|
573
|
-
const max = action.max ?? 1;
|
|
574
632
|
if (cur < max) {
|
|
575
633
|
input.value = (cur + 1).toString();
|
|
576
634
|
action.execute("next", cur + 1);
|
|
@@ -582,15 +640,18 @@ var ToolbarController = class {
|
|
|
582
640
|
type: "number",
|
|
583
641
|
value: (action.value ?? 1).toString(),
|
|
584
642
|
min: "1",
|
|
585
|
-
max:
|
|
643
|
+
max: max.toString()
|
|
586
644
|
});
|
|
587
645
|
input.addEventListener("change", () => {
|
|
588
|
-
|
|
589
|
-
if (
|
|
590
|
-
|
|
591
|
-
|
|
646
|
+
let val = parseInt(input.value, 10);
|
|
647
|
+
if (isNaN(val)) val = 1;
|
|
648
|
+
val = Math.max(1, Math.min(max, val));
|
|
649
|
+
input.value = val.toString();
|
|
650
|
+
action.execute("go", val);
|
|
592
651
|
});
|
|
593
|
-
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${
|
|
652
|
+
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
653
|
+
this.pageInputEl = input;
|
|
654
|
+
this.pageLabelEl = label;
|
|
594
655
|
groupEl.appendChild(prevBtn);
|
|
595
656
|
groupEl.appendChild(input);
|
|
596
657
|
groupEl.appendChild(label);
|
|
@@ -768,7 +829,13 @@ var FilePreviewViewer = class {
|
|
|
768
829
|
buffer,
|
|
769
830
|
options,
|
|
770
831
|
signal,
|
|
771
|
-
emit: (event, payload) =>
|
|
832
|
+
emit: (event, payload) => {
|
|
833
|
+
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
834
|
+
const total = payload.total ?? payload.totalPages;
|
|
835
|
+
this.toolbar?.setPage(payload.page, total);
|
|
836
|
+
}
|
|
837
|
+
this.eventEmitter.emit(event, payload);
|
|
838
|
+
}
|
|
772
839
|
});
|
|
773
840
|
this.activeInstance = instance;
|
|
774
841
|
this.hideLoading();
|
|
@@ -802,6 +869,7 @@ var FilePreviewViewer = class {
|
|
|
802
869
|
if (thumbnails && thumbnails.length > 0 && this.thumbnailPanel) {
|
|
803
870
|
this.thumbnailPanel.update(thumbnails, (index) => {
|
|
804
871
|
instance.goToPage?.(index + 1);
|
|
872
|
+
this.toolbar?.setPage(index + 1);
|
|
805
873
|
});
|
|
806
874
|
if (options.showThumbnails) {
|
|
807
875
|
this.thumbnailPanel.show();
|
|
@@ -927,9 +995,13 @@ var FilePreviewViewer = class {
|
|
|
927
995
|
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
928
996
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
929
997
|
this.activeInstance.goToPage?.(cur + 1);
|
|
998
|
+
const nextCur = this.activeInstance.getCurrentPage?.() ?? cur + 1;
|
|
999
|
+
this.toolbar?.setPage(nextCur);
|
|
930
1000
|
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
931
1001
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
932
1002
|
this.activeInstance.goToPage?.(Math.max(1, cur - 1));
|
|
1003
|
+
const prevCur = this.activeInstance.getCurrentPage?.() ?? Math.max(1, cur - 1);
|
|
1004
|
+
this.toolbar?.setPage(prevCur);
|
|
933
1005
|
} else if (e.key === "+" || e.key === "=") {
|
|
934
1006
|
this.activeInstance.zoomIn?.();
|
|
935
1007
|
} else if (e.key === "-" || e.key === "_") {
|
|
@@ -1195,30 +1267,62 @@ var CfbfReader = class {
|
|
|
1195
1267
|
return result.subarray(0, targetSize);
|
|
1196
1268
|
}
|
|
1197
1269
|
};
|
|
1198
|
-
|
|
1199
|
-
|
|
1270
|
+
if (typeof window !== "undefined" && pdfjsLib__namespace.GlobalWorkerOptions) {
|
|
1271
|
+
if (!pdfjsLib__namespace.GlobalWorkerOptions.workerSrc) {
|
|
1272
|
+
pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/build/pdf.worker.min.mjs`;
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1200
1275
|
var PdfPlugin = class {
|
|
1201
1276
|
id = "pdf";
|
|
1202
|
-
name = "PDF Preview";
|
|
1277
|
+
name = "PDF Document Preview";
|
|
1203
1278
|
extensions = [".pdf"];
|
|
1204
1279
|
mimeTypes = ["application/pdf"];
|
|
1205
1280
|
weight = 100;
|
|
1206
1281
|
supports(file) {
|
|
1207
1282
|
const ext = file.metadata.extension?.toLowerCase();
|
|
1208
1283
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
1209
|
-
|
|
1284
|
+
if (ext) return this.extensions.includes(ext);
|
|
1285
|
+
return this.mimeTypes.includes(mime || "");
|
|
1210
1286
|
}
|
|
1211
1287
|
getToolbarActions(instance) {
|
|
1288
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1289
|
+
const curPage = instance.getCurrentPage?.() ?? 1;
|
|
1212
1290
|
return [
|
|
1291
|
+
{
|
|
1292
|
+
id: "thumbnails",
|
|
1293
|
+
icon: "thumbnails",
|
|
1294
|
+
label: "Page Thumbnails",
|
|
1295
|
+
type: "button",
|
|
1296
|
+
group: "navigation",
|
|
1297
|
+
execute: () => instance.toggleThumbnails?.()
|
|
1298
|
+
},
|
|
1299
|
+
{
|
|
1300
|
+
id: "page-nav",
|
|
1301
|
+
icon: "",
|
|
1302
|
+
label: "Page Navigation",
|
|
1303
|
+
type: "page-nav",
|
|
1304
|
+
group: "navigation",
|
|
1305
|
+
value: curPage,
|
|
1306
|
+
max: totalPages,
|
|
1307
|
+
execute: (action, page) => {
|
|
1308
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1309
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1310
|
+
if (action === "prev") {
|
|
1311
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1312
|
+
} else if (action === "next") {
|
|
1313
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1314
|
+
} else if (typeof page === "number") {
|
|
1315
|
+
instance.goToPage?.(page);
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
},
|
|
1213
1319
|
{
|
|
1214
1320
|
id: "zoom-out",
|
|
1215
1321
|
icon: "zoom-out",
|
|
1216
1322
|
label: "Zoom Out",
|
|
1217
1323
|
type: "button",
|
|
1218
1324
|
group: "zoom",
|
|
1219
|
-
execute: () =>
|
|
1220
|
-
instance.zoomOut?.();
|
|
1221
|
-
}
|
|
1325
|
+
execute: () => instance.zoomOut?.()
|
|
1222
1326
|
},
|
|
1223
1327
|
{
|
|
1224
1328
|
id: "zoom-in",
|
|
@@ -1226,9 +1330,7 @@ var PdfPlugin = class {
|
|
|
1226
1330
|
label: "Zoom In",
|
|
1227
1331
|
type: "button",
|
|
1228
1332
|
group: "zoom",
|
|
1229
|
-
execute: () =>
|
|
1230
|
-
instance.zoomIn?.();
|
|
1231
|
-
}
|
|
1333
|
+
execute: () => instance.zoomIn?.()
|
|
1232
1334
|
},
|
|
1233
1335
|
{
|
|
1234
1336
|
id: "fit-page",
|
|
@@ -1236,39 +1338,23 @@ var PdfPlugin = class {
|
|
|
1236
1338
|
label: "Fit to Page",
|
|
1237
1339
|
type: "button",
|
|
1238
1340
|
group: "zoom",
|
|
1239
|
-
execute: () =>
|
|
1240
|
-
instance.fitToPage?.();
|
|
1241
|
-
}
|
|
1341
|
+
execute: () => instance.fitToPage?.()
|
|
1242
1342
|
},
|
|
1243
1343
|
{
|
|
1244
1344
|
id: "rotate-cw",
|
|
1245
1345
|
icon: "rotate-cw",
|
|
1246
|
-
label: "Rotate",
|
|
1346
|
+
label: "Rotate Clockwise",
|
|
1247
1347
|
type: "button",
|
|
1248
1348
|
group: "view",
|
|
1249
|
-
execute: () =>
|
|
1250
|
-
instance.rotateCW?.();
|
|
1251
|
-
}
|
|
1252
|
-
},
|
|
1253
|
-
{
|
|
1254
|
-
id: "page-nav",
|
|
1255
|
-
icon: "page-nav",
|
|
1256
|
-
label: "Page Navigation",
|
|
1257
|
-
type: "page-nav",
|
|
1258
|
-
group: "navigation",
|
|
1259
|
-
execute: (page) => {
|
|
1260
|
-
if (typeof page === "number") instance.goToPage?.(page);
|
|
1261
|
-
}
|
|
1349
|
+
execute: () => instance.rotateCW?.()
|
|
1262
1350
|
},
|
|
1263
1351
|
{
|
|
1264
1352
|
id: "download",
|
|
1265
1353
|
icon: "download",
|
|
1266
|
-
label: "Download",
|
|
1354
|
+
label: "Download PDF",
|
|
1267
1355
|
type: "button",
|
|
1268
1356
|
group: "actions",
|
|
1269
|
-
execute: () =>
|
|
1270
|
-
instance.download?.();
|
|
1271
|
-
}
|
|
1357
|
+
execute: () => instance.download?.()
|
|
1272
1358
|
},
|
|
1273
1359
|
{
|
|
1274
1360
|
id: "print",
|
|
@@ -1276,99 +1362,213 @@ var PdfPlugin = class {
|
|
|
1276
1362
|
label: "Print",
|
|
1277
1363
|
type: "button",
|
|
1278
1364
|
group: "actions",
|
|
1279
|
-
execute: () =>
|
|
1280
|
-
instance.print?.();
|
|
1281
|
-
}
|
|
1365
|
+
execute: () => instance.print?.()
|
|
1282
1366
|
}
|
|
1283
1367
|
];
|
|
1284
1368
|
}
|
|
1285
1369
|
async render(ctx) {
|
|
1286
|
-
const
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1370
|
+
const container = document.createElement("div");
|
|
1371
|
+
container.className = "fp-pdf-container";
|
|
1372
|
+
container.style.width = "100%";
|
|
1373
|
+
container.style.height = "100%";
|
|
1374
|
+
container.style.overflow = "auto";
|
|
1375
|
+
container.style.display = "flex";
|
|
1376
|
+
container.style.flexDirection = "column";
|
|
1377
|
+
container.style.alignItems = "center";
|
|
1378
|
+
container.style.padding = "24px 16px";
|
|
1379
|
+
container.style.backgroundColor = "#0f172a";
|
|
1380
|
+
container.style.boxSizing = "border-box";
|
|
1381
|
+
container.style.position = "relative";
|
|
1382
|
+
const pageCard = document.createElement("div");
|
|
1383
|
+
pageCard.className = "fp-pdf-page-card";
|
|
1384
|
+
pageCard.style.boxShadow = "0 10px 35px rgba(0, 0, 0, 0.5)";
|
|
1385
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
1386
|
+
pageCard.style.borderRadius = "4px";
|
|
1387
|
+
pageCard.style.overflow = "hidden";
|
|
1388
|
+
pageCard.style.lineHeight = "0";
|
|
1389
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
1390
|
+
pageCard.style.position = "relative";
|
|
1391
|
+
const canvas = document.createElement("canvas");
|
|
1392
|
+
pageCard.appendChild(canvas);
|
|
1393
|
+
container.appendChild(pageCard);
|
|
1394
|
+
const indicator = document.createElement("div");
|
|
1395
|
+
indicator.className = "fp-pdf-page-indicator";
|
|
1396
|
+
indicator.style.position = "sticky";
|
|
1397
|
+
indicator.style.bottom = "16px";
|
|
1398
|
+
indicator.style.marginTop = "16px";
|
|
1399
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1400
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
1401
|
+
indicator.style.color = "#f8fafc";
|
|
1402
|
+
indicator.style.fontSize = "12px";
|
|
1403
|
+
indicator.style.fontWeight = "600";
|
|
1404
|
+
indicator.style.padding = "5px 14px";
|
|
1405
|
+
indicator.style.borderRadius = "20px";
|
|
1406
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1407
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1408
|
+
indicator.style.zIndex = "10";
|
|
1409
|
+
indicator.style.userSelect = "none";
|
|
1410
|
+
indicator.style.pointerEvents = "none";
|
|
1411
|
+
container.appendChild(indicator);
|
|
1412
|
+
ctx.container.appendChild(container);
|
|
1413
|
+
const loadingTask = pdfjsLib__namespace.getDocument({
|
|
1414
|
+
data: new Uint8Array(ctx.buffer),
|
|
1415
|
+
cMapUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/cmaps/`,
|
|
1416
|
+
cMapPacked: true,
|
|
1417
|
+
standardFontDataUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/standard_fonts/`
|
|
1418
|
+
});
|
|
1419
|
+
const pdfDoc = await loadingTask.promise;
|
|
1420
|
+
const totalPages = Math.max(1, pdfDoc.numPages);
|
|
1302
1421
|
let currentPage = 1;
|
|
1303
|
-
let
|
|
1422
|
+
let zoomScale = 1;
|
|
1304
1423
|
let rotation = 0;
|
|
1424
|
+
let currentRenderTask = null;
|
|
1425
|
+
const renderPage = async (pageNum) => {
|
|
1426
|
+
if (currentRenderTask) {
|
|
1427
|
+
try {
|
|
1428
|
+
currentRenderTask.cancel();
|
|
1429
|
+
} catch {
|
|
1430
|
+
}
|
|
1431
|
+
currentRenderTask = null;
|
|
1432
|
+
}
|
|
1433
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1434
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1435
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1436
|
+
const page = await pdfDoc.getPage(currentPage);
|
|
1437
|
+
const containerWidth = container.clientWidth || 900;
|
|
1438
|
+
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1439
|
+
const baseScale = Math.min((containerWidth - 64) / unscaledVp.width, 1.6);
|
|
1440
|
+
const effectiveScale = (baseScale > 0 ? baseScale : 1) * zoomScale;
|
|
1441
|
+
const pixelRatio = window.devicePixelRatio || 1;
|
|
1442
|
+
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
1443
|
+
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1444
|
+
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1445
|
+
canvas.style.width = `${Math.floor(viewport.width)}px`;
|
|
1446
|
+
canvas.style.height = `${Math.floor(viewport.height)}px`;
|
|
1447
|
+
const canvasCtx = canvas.getContext("2d");
|
|
1448
|
+
if (!canvasCtx) return;
|
|
1449
|
+
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
1450
|
+
currentRenderTask = page.render({
|
|
1451
|
+
canvasContext: canvasCtx,
|
|
1452
|
+
viewport
|
|
1453
|
+
});
|
|
1454
|
+
try {
|
|
1455
|
+
await currentRenderTask.promise;
|
|
1456
|
+
} catch (err) {
|
|
1457
|
+
if (err?.name !== "RenderingCancelledException") {
|
|
1458
|
+
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1459
|
+
}
|
|
1460
|
+
} finally {
|
|
1461
|
+
currentRenderTask = null;
|
|
1462
|
+
}
|
|
1463
|
+
};
|
|
1464
|
+
await renderPage(1);
|
|
1305
1465
|
const cleanup = () => {
|
|
1306
|
-
|
|
1307
|
-
|
|
1466
|
+
if (currentRenderTask) {
|
|
1467
|
+
try {
|
|
1468
|
+
currentRenderTask.cancel();
|
|
1469
|
+
} catch {
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
try {
|
|
1473
|
+
pdfDoc.destroy();
|
|
1474
|
+
} catch {
|
|
1475
|
+
}
|
|
1476
|
+
container.remove();
|
|
1308
1477
|
ctx.container.innerHTML = "";
|
|
1309
1478
|
};
|
|
1310
1479
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1311
|
-
|
|
1480
|
+
const instance = {
|
|
1312
1481
|
destroy: cleanup,
|
|
1313
1482
|
zoomIn: () => {
|
|
1314
|
-
|
|
1315
|
-
|
|
1483
|
+
zoomScale = Math.min(3.5, zoomScale + 0.2);
|
|
1484
|
+
renderPage(currentPage);
|
|
1316
1485
|
},
|
|
1317
1486
|
zoomOut: () => {
|
|
1318
|
-
|
|
1319
|
-
|
|
1487
|
+
zoomScale = Math.max(0.3, zoomScale - 0.2);
|
|
1488
|
+
renderPage(currentPage);
|
|
1320
1489
|
},
|
|
1321
|
-
getZoom: () =>
|
|
1490
|
+
getZoom: () => zoomScale,
|
|
1322
1491
|
setZoom: (level) => {
|
|
1323
|
-
|
|
1324
|
-
|
|
1492
|
+
zoomScale = Math.max(0.3, Math.min(3.5, level));
|
|
1493
|
+
renderPage(currentPage);
|
|
1325
1494
|
},
|
|
1326
1495
|
fitToPage: () => {
|
|
1327
|
-
|
|
1328
|
-
|
|
1496
|
+
zoomScale = 1;
|
|
1497
|
+
renderPage(currentPage);
|
|
1329
1498
|
},
|
|
1330
1499
|
rotateCW: () => {
|
|
1331
1500
|
rotation = (rotation + 90) % 360;
|
|
1332
|
-
|
|
1501
|
+
renderPage(currentPage);
|
|
1333
1502
|
},
|
|
1334
1503
|
rotateCCW: () => {
|
|
1335
1504
|
rotation = (rotation - 90 + 360) % 360;
|
|
1336
|
-
|
|
1505
|
+
renderPage(currentPage);
|
|
1337
1506
|
},
|
|
1338
1507
|
getRotation: () => rotation,
|
|
1508
|
+
getPageCount: () => totalPages,
|
|
1509
|
+
getCurrentPage: () => currentPage,
|
|
1339
1510
|
goToPage: (page) => {
|
|
1340
|
-
|
|
1341
|
-
iframe.src = `${url}#page=${page}`;
|
|
1511
|
+
renderPage(page);
|
|
1342
1512
|
},
|
|
1343
|
-
getCurrentPage: () => currentPage,
|
|
1344
1513
|
download: () => {
|
|
1514
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1515
|
+
const url = URL.createObjectURL(blob);
|
|
1345
1516
|
const a = document.createElement("a");
|
|
1346
1517
|
a.href = url;
|
|
1347
1518
|
a.download = ctx.metadata.name || "document.pdf";
|
|
1348
1519
|
a.click();
|
|
1520
|
+
URL.revokeObjectURL(url);
|
|
1349
1521
|
},
|
|
1350
1522
|
print: () => {
|
|
1351
|
-
|
|
1523
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1524
|
+
const url = URL.createObjectURL(blob);
|
|
1525
|
+
const hiddenIframe = document.createElement("iframe");
|
|
1526
|
+
hiddenIframe.style.position = "fixed";
|
|
1527
|
+
hiddenIframe.style.right = "0";
|
|
1528
|
+
hiddenIframe.style.bottom = "0";
|
|
1529
|
+
hiddenIframe.style.width = "0";
|
|
1530
|
+
hiddenIframe.style.height = "0";
|
|
1531
|
+
hiddenIframe.style.border = "0";
|
|
1532
|
+
document.body.appendChild(hiddenIframe);
|
|
1533
|
+
hiddenIframe.src = url;
|
|
1534
|
+
hiddenIframe.onload = () => {
|
|
1535
|
+
setTimeout(() => {
|
|
1536
|
+
hiddenIframe.contentWindow?.print();
|
|
1537
|
+
setTimeout(() => {
|
|
1538
|
+
hiddenIframe.remove();
|
|
1539
|
+
URL.revokeObjectURL(url);
|
|
1540
|
+
}, 1e3);
|
|
1541
|
+
}, 300);
|
|
1542
|
+
};
|
|
1352
1543
|
},
|
|
1353
1544
|
getThumbnails: async () => {
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1545
|
+
const thumbnails = [];
|
|
1546
|
+
const count = Math.min(totalPages, 50);
|
|
1547
|
+
for (let i = 1; i <= count; i++) {
|
|
1548
|
+
thumbnails.push({
|
|
1549
|
+
index: i,
|
|
1550
|
+
label: `Page ${i}`,
|
|
1551
|
+
render: async (thumbCanvas) => {
|
|
1552
|
+
try {
|
|
1553
|
+
const p = await pdfDoc.getPage(i);
|
|
1554
|
+
const baseVp = p.getViewport({ scale: 1 });
|
|
1555
|
+
const thumbScale = (thumbCanvas.width || 120) / baseVp.width;
|
|
1556
|
+
const thumbVp = p.getViewport({ scale: thumbScale });
|
|
1557
|
+
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1558
|
+
const tCtx = thumbCanvas.getContext("2d");
|
|
1559
|
+
if (tCtx) {
|
|
1560
|
+
await p.render({ canvasContext: tCtx, viewport: thumbVp }).promise;
|
|
1561
|
+
}
|
|
1562
|
+
} catch (e) {
|
|
1563
|
+
console.warn(`[PdfPlugin] Error generating thumbnail for page ${i}:`, e);
|
|
1366
1564
|
}
|
|
1367
1565
|
}
|
|
1368
|
-
}
|
|
1369
|
-
|
|
1566
|
+
});
|
|
1567
|
+
}
|
|
1568
|
+
return thumbnails;
|
|
1370
1569
|
}
|
|
1371
1570
|
};
|
|
1571
|
+
return instance;
|
|
1372
1572
|
}
|
|
1373
1573
|
};
|
|
1374
1574
|
function pdfPlugin() {
|
|
@@ -1689,10 +1889,37 @@ var DocxPlugin = class {
|
|
|
1689
1889
|
supports(file) {
|
|
1690
1890
|
const ext = file.metadata.extension?.toLowerCase();
|
|
1691
1891
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
1692
|
-
|
|
1892
|
+
if (ext) {
|
|
1893
|
+
return this.extensions.includes(ext);
|
|
1894
|
+
}
|
|
1895
|
+
return this.mimeTypes.includes(mime || "");
|
|
1693
1896
|
}
|
|
1694
1897
|
getToolbarActions(instance) {
|
|
1695
|
-
|
|
1898
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1899
|
+
const actions = [];
|
|
1900
|
+
if (totalPages > 1) {
|
|
1901
|
+
actions.push({
|
|
1902
|
+
id: "page-nav",
|
|
1903
|
+
icon: "",
|
|
1904
|
+
label: "Page Navigation",
|
|
1905
|
+
type: "page-nav",
|
|
1906
|
+
group: "navigation",
|
|
1907
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
1908
|
+
max: totalPages,
|
|
1909
|
+
execute: (action, page) => {
|
|
1910
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1911
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1912
|
+
if (action === "prev") {
|
|
1913
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1914
|
+
} else if (action === "next") {
|
|
1915
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1916
|
+
} else if (typeof page === "number") {
|
|
1917
|
+
instance.goToPage?.(page);
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
});
|
|
1921
|
+
}
|
|
1922
|
+
actions.push(
|
|
1696
1923
|
{
|
|
1697
1924
|
id: "zoom-out",
|
|
1698
1925
|
icon: "zoom-out",
|
|
@@ -1733,7 +1960,8 @@ var DocxPlugin = class {
|
|
|
1733
1960
|
group: "actions",
|
|
1734
1961
|
execute: () => instance.print?.()
|
|
1735
1962
|
}
|
|
1736
|
-
|
|
1963
|
+
);
|
|
1964
|
+
return actions;
|
|
1737
1965
|
}
|
|
1738
1966
|
async render(ctx) {
|
|
1739
1967
|
const wrapper = document.createElement("div");
|
|
@@ -1809,7 +2037,51 @@ var DocxPlugin = class {
|
|
|
1809
2037
|
}
|
|
1810
2038
|
}
|
|
1811
2039
|
}
|
|
2040
|
+
const sections = wrapper.querySelectorAll("section.docx");
|
|
2041
|
+
const cards = wrapper.querySelectorAll(".fp-docx-page-card");
|
|
2042
|
+
const pageElements = sections.length > 0 ? sections : cards;
|
|
2043
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
2044
|
+
let currentPage = 1;
|
|
2045
|
+
let indicator = null;
|
|
2046
|
+
if (totalPages > 1) {
|
|
2047
|
+
indicator = document.createElement("div");
|
|
2048
|
+
indicator.className = "fp-docx-page-indicator";
|
|
2049
|
+
indicator.style.position = "sticky";
|
|
2050
|
+
indicator.style.bottom = "16px";
|
|
2051
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2052
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
2053
|
+
indicator.style.color = "#f8fafc";
|
|
2054
|
+
indicator.style.fontSize = "12px";
|
|
2055
|
+
indicator.style.fontWeight = "600";
|
|
2056
|
+
indicator.style.padding = "5px 14px";
|
|
2057
|
+
indicator.style.borderRadius = "20px";
|
|
2058
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2059
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2060
|
+
indicator.style.zIndex = "10";
|
|
2061
|
+
indicator.style.userSelect = "none";
|
|
2062
|
+
indicator.style.pointerEvents = "none";
|
|
2063
|
+
indicator.style.textAlign = "center";
|
|
2064
|
+
indicator.style.width = "fit-content";
|
|
2065
|
+
indicator.style.margin = "16px auto 0";
|
|
2066
|
+
ctx.container.appendChild(indicator);
|
|
2067
|
+
}
|
|
2068
|
+
const showPage = (pageNum) => {
|
|
2069
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2070
|
+
if (pageElements.length > 1) {
|
|
2071
|
+
pageElements.forEach((sec, idx) => {
|
|
2072
|
+
sec.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
2073
|
+
});
|
|
2074
|
+
}
|
|
2075
|
+
if (indicator) {
|
|
2076
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2077
|
+
}
|
|
2078
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2079
|
+
};
|
|
2080
|
+
if (totalPages > 1) {
|
|
2081
|
+
showPage(1);
|
|
2082
|
+
}
|
|
1812
2083
|
const cleanup = () => {
|
|
2084
|
+
indicator?.remove();
|
|
1813
2085
|
for (const url of createdBlobUrls) {
|
|
1814
2086
|
URL.revokeObjectURL(url);
|
|
1815
2087
|
}
|
|
@@ -1820,6 +2092,11 @@ var DocxPlugin = class {
|
|
|
1820
2092
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1821
2093
|
return {
|
|
1822
2094
|
destroy: cleanup,
|
|
2095
|
+
getPageCount: () => totalPages,
|
|
2096
|
+
getCurrentPage: () => currentPage,
|
|
2097
|
+
goToPage: (page) => {
|
|
2098
|
+
showPage(page);
|
|
2099
|
+
},
|
|
1823
2100
|
zoomIn: () => {
|
|
1824
2101
|
scale += 0.1;
|
|
1825
2102
|
wrapper.style.transform = `scale(${scale})`;
|
|
@@ -2078,10 +2355,37 @@ var ExcelPlugin = class {
|
|
|
2078
2355
|
supports(file) {
|
|
2079
2356
|
const ext = file.metadata.extension?.toLowerCase();
|
|
2080
2357
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
2081
|
-
|
|
2358
|
+
if (ext) {
|
|
2359
|
+
return this.extensions.includes(ext);
|
|
2360
|
+
}
|
|
2361
|
+
return this.mimeTypes.includes(mime || "");
|
|
2082
2362
|
}
|
|
2083
2363
|
getToolbarActions(instance) {
|
|
2084
|
-
|
|
2364
|
+
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2365
|
+
const actions = [];
|
|
2366
|
+
if (totalSheets > 1) {
|
|
2367
|
+
actions.push({
|
|
2368
|
+
id: "page-nav",
|
|
2369
|
+
icon: "",
|
|
2370
|
+
label: "Sheet Navigation",
|
|
2371
|
+
type: "page-nav",
|
|
2372
|
+
group: "navigation",
|
|
2373
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2374
|
+
max: totalSheets,
|
|
2375
|
+
execute: (action, sheet) => {
|
|
2376
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2377
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2378
|
+
if (action === "prev") {
|
|
2379
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2380
|
+
} else if (action === "next") {
|
|
2381
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2382
|
+
} else if (typeof sheet === "number") {
|
|
2383
|
+
instance.goToPage?.(sheet);
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
});
|
|
2387
|
+
}
|
|
2388
|
+
actions.push(
|
|
2085
2389
|
{
|
|
2086
2390
|
id: "zoom-out",
|
|
2087
2391
|
icon: "zoom-out",
|
|
@@ -2102,16 +2406,6 @@ var ExcelPlugin = class {
|
|
|
2102
2406
|
instance.zoomIn?.();
|
|
2103
2407
|
}
|
|
2104
2408
|
},
|
|
2105
|
-
{
|
|
2106
|
-
id: "page-nav",
|
|
2107
|
-
icon: "page-nav",
|
|
2108
|
-
label: "Sheet Navigation",
|
|
2109
|
-
type: "page-nav",
|
|
2110
|
-
group: "navigation",
|
|
2111
|
-
execute: (sheet) => {
|
|
2112
|
-
if (typeof sheet === "number") instance.goToPage?.(sheet);
|
|
2113
|
-
}
|
|
2114
|
-
},
|
|
2115
2409
|
{
|
|
2116
2410
|
id: "download",
|
|
2117
2411
|
icon: "download",
|
|
@@ -2132,7 +2426,8 @@ var ExcelPlugin = class {
|
|
|
2132
2426
|
instance.print?.();
|
|
2133
2427
|
}
|
|
2134
2428
|
}
|
|
2135
|
-
|
|
2429
|
+
);
|
|
2430
|
+
return actions;
|
|
2136
2431
|
}
|
|
2137
2432
|
async render(ctx) {
|
|
2138
2433
|
const container = document.createElement("div");
|
|
@@ -2216,6 +2511,7 @@ var ExcelPlugin = class {
|
|
|
2216
2511
|
b.style.fontWeight = "normal";
|
|
2217
2512
|
}
|
|
2218
2513
|
});
|
|
2514
|
+
ctx.emit("page-change", { page: currentSheetIndex, total: sheetNames.length });
|
|
2219
2515
|
};
|
|
2220
2516
|
if (sheetNames.length > 0) {
|
|
2221
2517
|
sheetNames.forEach((name, idx) => {
|
|
@@ -2465,7 +2761,31 @@ var CodePlugin = class {
|
|
|
2465
2761
|
return false;
|
|
2466
2762
|
}
|
|
2467
2763
|
getToolbarActions(instance) {
|
|
2468
|
-
|
|
2764
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2765
|
+
const actions = [];
|
|
2766
|
+
if (totalPages > 1) {
|
|
2767
|
+
actions.push({
|
|
2768
|
+
id: "page-nav",
|
|
2769
|
+
icon: "",
|
|
2770
|
+
label: "Page Navigation",
|
|
2771
|
+
type: "page-nav",
|
|
2772
|
+
group: "navigation",
|
|
2773
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2774
|
+
max: totalPages,
|
|
2775
|
+
execute: (action, page) => {
|
|
2776
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2777
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2778
|
+
if (action === "prev") {
|
|
2779
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2780
|
+
} else if (action === "next") {
|
|
2781
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2782
|
+
} else if (typeof page === "number") {
|
|
2783
|
+
instance.goToPage?.(page);
|
|
2784
|
+
}
|
|
2785
|
+
}
|
|
2786
|
+
});
|
|
2787
|
+
}
|
|
2788
|
+
actions.push(
|
|
2469
2789
|
{
|
|
2470
2790
|
id: "zoom-out",
|
|
2471
2791
|
icon: "zoom-out",
|
|
@@ -2516,11 +2836,16 @@ var CodePlugin = class {
|
|
|
2516
2836
|
instance.print?.();
|
|
2517
2837
|
}
|
|
2518
2838
|
}
|
|
2519
|
-
|
|
2839
|
+
);
|
|
2840
|
+
return actions;
|
|
2520
2841
|
}
|
|
2521
2842
|
async render(ctx) {
|
|
2522
2843
|
const decoder = new TextDecoder("utf-8");
|
|
2523
|
-
const
|
|
2844
|
+
const fullText = decoder.decode(ctx.buffer);
|
|
2845
|
+
const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
|
|
2846
|
+
const rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
2847
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
2848
|
+
let currentPage = 1;
|
|
2524
2849
|
const container = document.createElement("div");
|
|
2525
2850
|
container.style.width = "100%";
|
|
2526
2851
|
container.style.height = "100%";
|
|
@@ -2539,25 +2864,66 @@ var CodePlugin = class {
|
|
|
2539
2864
|
pre.style.wordBreak = "break-all";
|
|
2540
2865
|
const code = document.createElement("code");
|
|
2541
2866
|
const ext = (ctx.metadata.extension || "").replace(".", "");
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2867
|
+
const renderCodePage = (text) => {
|
|
2868
|
+
try {
|
|
2869
|
+
if (ext && hljs__default.default.getLanguage(ext)) {
|
|
2870
|
+
code.innerHTML = hljs__default.default.highlight(text, { language: ext }).value;
|
|
2871
|
+
} else {
|
|
2872
|
+
code.innerHTML = hljs__default.default.highlightAuto(text).value;
|
|
2873
|
+
}
|
|
2874
|
+
} catch {
|
|
2875
|
+
code.textContent = text;
|
|
2547
2876
|
}
|
|
2548
|
-
}
|
|
2549
|
-
|
|
2550
|
-
}
|
|
2877
|
+
};
|
|
2878
|
+
renderCodePage(rawPages[0] || fullText);
|
|
2551
2879
|
pre.appendChild(code);
|
|
2552
2880
|
container.appendChild(pre);
|
|
2881
|
+
let indicator = null;
|
|
2882
|
+
if (totalPages > 1) {
|
|
2883
|
+
indicator = document.createElement("div");
|
|
2884
|
+
indicator.className = "fp-code-page-indicator";
|
|
2885
|
+
indicator.style.position = "sticky";
|
|
2886
|
+
indicator.style.bottom = "16px";
|
|
2887
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2888
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
2889
|
+
indicator.style.color = "#f8fafc";
|
|
2890
|
+
indicator.style.fontSize = "12px";
|
|
2891
|
+
indicator.style.fontWeight = "600";
|
|
2892
|
+
indicator.style.padding = "5px 14px";
|
|
2893
|
+
indicator.style.borderRadius = "20px";
|
|
2894
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2895
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2896
|
+
indicator.style.zIndex = "10";
|
|
2897
|
+
indicator.style.userSelect = "none";
|
|
2898
|
+
indicator.style.pointerEvents = "none";
|
|
2899
|
+
indicator.style.textAlign = "center";
|
|
2900
|
+
indicator.style.width = "fit-content";
|
|
2901
|
+
indicator.style.margin = "16px auto 0";
|
|
2902
|
+
container.appendChild(indicator);
|
|
2903
|
+
}
|
|
2904
|
+
const showPage = (pageNum) => {
|
|
2905
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2906
|
+
renderCodePage(rawPages[currentPage - 1] || fullText);
|
|
2907
|
+
if (indicator) {
|
|
2908
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2909
|
+
}
|
|
2910
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2911
|
+
};
|
|
2912
|
+
if (totalPages > 1) {
|
|
2913
|
+
showPage(1);
|
|
2914
|
+
}
|
|
2553
2915
|
ctx.container.appendChild(container);
|
|
2554
2916
|
const cleanup = () => {
|
|
2917
|
+
indicator?.remove();
|
|
2555
2918
|
container.remove();
|
|
2556
2919
|
ctx.container.innerHTML = "";
|
|
2557
2920
|
};
|
|
2558
2921
|
ctx.signal.addEventListener("abort", cleanup);
|
|
2559
2922
|
return {
|
|
2560
2923
|
destroy: cleanup,
|
|
2924
|
+
getPageCount: () => totalPages,
|
|
2925
|
+
getCurrentPage: () => currentPage,
|
|
2926
|
+
goToPage: (page) => showPage(page),
|
|
2561
2927
|
zoomIn: () => {
|
|
2562
2928
|
fontSize = Math.min(32, fontSize + 2);
|
|
2563
2929
|
pre.style.fontSize = `${fontSize}px`;
|
|
@@ -2585,7 +2951,7 @@ var CodePlugin = class {
|
|
|
2585
2951
|
window.print();
|
|
2586
2952
|
},
|
|
2587
2953
|
copy: () => {
|
|
2588
|
-
navigator.clipboard?.writeText(
|
|
2954
|
+
navigator.clipboard?.writeText(fullText);
|
|
2589
2955
|
}
|
|
2590
2956
|
};
|
|
2591
2957
|
}
|
|
@@ -3020,7 +3386,10 @@ var PptxPlugin = class {
|
|
|
3020
3386
|
supports(file) {
|
|
3021
3387
|
const ext = file.metadata.extension?.toLowerCase();
|
|
3022
3388
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
3023
|
-
|
|
3389
|
+
if (ext) {
|
|
3390
|
+
return this.extensions.includes(ext);
|
|
3391
|
+
}
|
|
3392
|
+
return this.mimeTypes.includes(mime || "");
|
|
3024
3393
|
}
|
|
3025
3394
|
getToolbarActions(instance) {
|
|
3026
3395
|
return [
|
|
@@ -3404,7 +3773,31 @@ var RtfPlugin = class {
|
|
|
3404
3773
|
return this.extensions.includes(ext || "") || this.mimeTypes.includes(mime || "");
|
|
3405
3774
|
}
|
|
3406
3775
|
getToolbarActions(instance) {
|
|
3407
|
-
|
|
3776
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3777
|
+
const actions = [];
|
|
3778
|
+
if (totalPages > 1) {
|
|
3779
|
+
actions.push({
|
|
3780
|
+
id: "page-nav",
|
|
3781
|
+
icon: "",
|
|
3782
|
+
label: "Page Navigation",
|
|
3783
|
+
type: "page-nav",
|
|
3784
|
+
group: "navigation",
|
|
3785
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
3786
|
+
max: totalPages,
|
|
3787
|
+
execute: (action, page) => {
|
|
3788
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3789
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
3790
|
+
if (action === "prev") {
|
|
3791
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
3792
|
+
} else if (action === "next") {
|
|
3793
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
3794
|
+
} else if (typeof page === "number") {
|
|
3795
|
+
instance.goToPage?.(page);
|
|
3796
|
+
}
|
|
3797
|
+
}
|
|
3798
|
+
});
|
|
3799
|
+
}
|
|
3800
|
+
actions.push(
|
|
3408
3801
|
{
|
|
3409
3802
|
id: "zoom-out",
|
|
3410
3803
|
icon: "zoom-out",
|
|
@@ -3445,7 +3838,8 @@ var RtfPlugin = class {
|
|
|
3445
3838
|
group: "actions",
|
|
3446
3839
|
execute: () => instance.print?.()
|
|
3447
3840
|
}
|
|
3448
|
-
|
|
3841
|
+
);
|
|
3842
|
+
return actions;
|
|
3449
3843
|
}
|
|
3450
3844
|
async render(ctx) {
|
|
3451
3845
|
const wrapper = document.createElement("div");
|
|
@@ -3464,25 +3858,82 @@ var RtfPlugin = class {
|
|
|
3464
3858
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
3465
3859
|
ctx.container.appendChild(wrapper);
|
|
3466
3860
|
let scale = 1;
|
|
3861
|
+
let pageElements = [];
|
|
3467
3862
|
try {
|
|
3468
|
-
|
|
3863
|
+
if (typeof RTFJS__namespace.loggingEnabled === "function") {
|
|
3864
|
+
RTFJS__namespace.loggingEnabled(false);
|
|
3865
|
+
}
|
|
3866
|
+
const doc = new RTFJS__namespace.Document(ctx.buffer, {});
|
|
3469
3867
|
const htmlElements = await doc.render();
|
|
3470
|
-
|
|
3868
|
+
pageElements = htmlElements;
|
|
3869
|
+
for (let i = 0; i < htmlElements.length; i++) {
|
|
3870
|
+
const el = htmlElements[i];
|
|
3871
|
+
el.style.display = i === 0 ? "block" : "none";
|
|
3471
3872
|
wrapper.appendChild(el);
|
|
3472
3873
|
}
|
|
3473
3874
|
} catch (err) {
|
|
3474
3875
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
3475
3876
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
3476
3877
|
const clean = text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "");
|
|
3477
|
-
|
|
3878
|
+
const pre = document.createElement("pre");
|
|
3879
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3880
|
+
pre.style.fontFamily = "serif";
|
|
3881
|
+
pre.style.color = "#333";
|
|
3882
|
+
pre.textContent = clean;
|
|
3883
|
+
wrapper.appendChild(pre);
|
|
3884
|
+
pageElements = [pre];
|
|
3885
|
+
}
|
|
3886
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
3887
|
+
let currentPage = 1;
|
|
3888
|
+
let indicator = null;
|
|
3889
|
+
if (totalPages > 1) {
|
|
3890
|
+
indicator = document.createElement("div");
|
|
3891
|
+
indicator.className = "fp-rtf-page-indicator";
|
|
3892
|
+
indicator.style.position = "sticky";
|
|
3893
|
+
indicator.style.bottom = "16px";
|
|
3894
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3895
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
3896
|
+
indicator.style.color = "#f8fafc";
|
|
3897
|
+
indicator.style.fontSize = "12px";
|
|
3898
|
+
indicator.style.fontWeight = "600";
|
|
3899
|
+
indicator.style.padding = "5px 14px";
|
|
3900
|
+
indicator.style.borderRadius = "20px";
|
|
3901
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3902
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3903
|
+
indicator.style.zIndex = "10";
|
|
3904
|
+
indicator.style.userSelect = "none";
|
|
3905
|
+
indicator.style.pointerEvents = "none";
|
|
3906
|
+
indicator.style.textAlign = "center";
|
|
3907
|
+
indicator.style.width = "fit-content";
|
|
3908
|
+
indicator.style.margin = "16px auto 0";
|
|
3909
|
+
ctx.container.appendChild(indicator);
|
|
3910
|
+
}
|
|
3911
|
+
const showPage = (pageNum) => {
|
|
3912
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3913
|
+
if (totalPages > 1) {
|
|
3914
|
+
pageElements.forEach((el, idx) => {
|
|
3915
|
+
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
3916
|
+
});
|
|
3917
|
+
}
|
|
3918
|
+
if (indicator) {
|
|
3919
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3920
|
+
}
|
|
3921
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3922
|
+
};
|
|
3923
|
+
if (totalPages > 1) {
|
|
3924
|
+
showPage(1);
|
|
3478
3925
|
}
|
|
3479
3926
|
const cleanup = () => {
|
|
3927
|
+
indicator?.remove();
|
|
3480
3928
|
wrapper.remove();
|
|
3481
3929
|
ctx.container.innerHTML = "";
|
|
3482
3930
|
};
|
|
3483
3931
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3484
3932
|
return {
|
|
3485
3933
|
destroy: cleanup,
|
|
3934
|
+
getPageCount: () => totalPages,
|
|
3935
|
+
getCurrentPage: () => currentPage,
|
|
3936
|
+
goToPage: (page) => showPage(page),
|
|
3486
3937
|
zoomIn: () => {
|
|
3487
3938
|
scale += 0.1;
|
|
3488
3939
|
wrapper.style.transform = `scale(${scale})`;
|
|
@@ -3663,45 +4114,48 @@ var OpenDocumentPlugin = class {
|
|
|
3663
4114
|
supports(file) {
|
|
3664
4115
|
const ext = file.metadata.extension?.toLowerCase();
|
|
3665
4116
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
3666
|
-
|
|
4117
|
+
if (ext) {
|
|
4118
|
+
return this.extensions.includes(ext);
|
|
4119
|
+
}
|
|
4120
|
+
return this.mimeTypes.includes(mime || "");
|
|
3667
4121
|
}
|
|
3668
4122
|
getToolbarActions(instance) {
|
|
3669
4123
|
const isPresentation = instance.isPresentation;
|
|
4124
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3670
4125
|
const actions = [];
|
|
3671
|
-
if (isPresentation) {
|
|
3672
|
-
|
|
3673
|
-
{
|
|
4126
|
+
if (isPresentation || totalPages > 1) {
|
|
4127
|
+
if (isPresentation) {
|
|
4128
|
+
actions.push({
|
|
3674
4129
|
id: "thumbnails",
|
|
3675
4130
|
icon: "thumbnails",
|
|
3676
4131
|
label: "Slide Thumbnails",
|
|
3677
4132
|
type: "button",
|
|
3678
4133
|
group: "navigation",
|
|
3679
4134
|
execute: () => instance.toggleThumbnails?.()
|
|
3680
|
-
}
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
}
|
|
4135
|
+
});
|
|
4136
|
+
}
|
|
4137
|
+
actions.push({
|
|
4138
|
+
id: "page-nav",
|
|
4139
|
+
icon: "",
|
|
4140
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
4141
|
+
type: "page-nav",
|
|
4142
|
+
group: "navigation",
|
|
4143
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4144
|
+
max: totalPages,
|
|
4145
|
+
execute: (action, page) => {
|
|
4146
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4147
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4148
|
+
if (action === "prev") {
|
|
4149
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4150
|
+
} else if (action === "next") {
|
|
4151
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4152
|
+
} else if (typeof page === "number") {
|
|
4153
|
+
instance.goToPage?.(page);
|
|
4154
|
+
} else if (typeof action === "number") {
|
|
4155
|
+
instance.goToPage?.(action);
|
|
3702
4156
|
}
|
|
3703
4157
|
}
|
|
3704
|
-
);
|
|
4158
|
+
});
|
|
3705
4159
|
}
|
|
3706
4160
|
actions.push(
|
|
3707
4161
|
{
|
|
@@ -4078,10 +4532,37 @@ var DocPlugin = class {
|
|
|
4078
4532
|
supports(file) {
|
|
4079
4533
|
const ext = file.metadata.extension?.toLowerCase();
|
|
4080
4534
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
4081
|
-
|
|
4535
|
+
if (ext) {
|
|
4536
|
+
return this.extensions.includes(ext);
|
|
4537
|
+
}
|
|
4538
|
+
return this.mimeTypes.includes(mime || "");
|
|
4082
4539
|
}
|
|
4083
4540
|
getToolbarActions(instance) {
|
|
4084
|
-
|
|
4541
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4542
|
+
const actions = [];
|
|
4543
|
+
if (totalPages > 1) {
|
|
4544
|
+
actions.push({
|
|
4545
|
+
id: "page-nav",
|
|
4546
|
+
icon: "",
|
|
4547
|
+
label: "Page Navigation",
|
|
4548
|
+
type: "page-nav",
|
|
4549
|
+
group: "navigation",
|
|
4550
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4551
|
+
max: totalPages,
|
|
4552
|
+
execute: (action, page) => {
|
|
4553
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4554
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4555
|
+
if (action === "prev") {
|
|
4556
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4557
|
+
} else if (action === "next") {
|
|
4558
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4559
|
+
} else if (typeof page === "number") {
|
|
4560
|
+
instance.goToPage?.(page);
|
|
4561
|
+
}
|
|
4562
|
+
}
|
|
4563
|
+
});
|
|
4564
|
+
}
|
|
4565
|
+
actions.push(
|
|
4085
4566
|
{
|
|
4086
4567
|
id: "zoom-out",
|
|
4087
4568
|
icon: "zoom-out",
|
|
@@ -4130,7 +4611,8 @@ var DocPlugin = class {
|
|
|
4130
4611
|
group: "actions",
|
|
4131
4612
|
execute: () => instance.print?.()
|
|
4132
4613
|
}
|
|
4133
|
-
|
|
4614
|
+
);
|
|
4615
|
+
return actions;
|
|
4134
4616
|
}
|
|
4135
4617
|
async render(ctx) {
|
|
4136
4618
|
const container = document.createElement("div");
|
|
@@ -4157,6 +4639,7 @@ var DocPlugin = class {
|
|
|
4157
4639
|
ctx.container.appendChild(container);
|
|
4158
4640
|
let scale = 1;
|
|
4159
4641
|
let extractedRawText = "";
|
|
4642
|
+
let isFallback = false;
|
|
4160
4643
|
try {
|
|
4161
4644
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4162
4645
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
@@ -4170,26 +4653,89 @@ var DocPlugin = class {
|
|
|
4170
4653
|
const tableStream = cfbf.readStream(tableName);
|
|
4171
4654
|
const text = this.extractDocText(wordDocStream, tableStream);
|
|
4172
4655
|
extractedRawText = text;
|
|
4173
|
-
wrapper.innerHTML = this.formatDocToHtml(text, ctx.metadata.name || "Document");
|
|
4174
4656
|
} catch (err) {
|
|
4175
4657
|
console.warn("[DocPlugin] Binary parsing error, fallback text:", err);
|
|
4176
4658
|
const fallback = this.heuristicTextExtraction(ctx.buffer);
|
|
4177
4659
|
extractedRawText = fallback;
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4660
|
+
isFallback = true;
|
|
4661
|
+
}
|
|
4662
|
+
const rawPages = this.splitIntoPages(extractedRawText);
|
|
4663
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
4664
|
+
let currentPage = 1;
|
|
4665
|
+
wrapper.innerHTML = "";
|
|
4666
|
+
const pageCards = [];
|
|
4667
|
+
for (let i = 0; i < totalPages; i++) {
|
|
4668
|
+
const pageCard = document.createElement("div");
|
|
4669
|
+
pageCard.className = "fp-doc-page-card";
|
|
4670
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
4671
|
+
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4672
|
+
pageCard.style.borderRadius = "4px";
|
|
4673
|
+
pageCard.style.padding = "56px 48px";
|
|
4674
|
+
pageCard.style.minHeight = "100%";
|
|
4675
|
+
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4676
|
+
if (isFallback && i === 0) {
|
|
4677
|
+
pageCard.innerHTML = `
|
|
4678
|
+
<div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
|
|
4679
|
+
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify2__default.default.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
|
|
4680
|
+
<span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
|
|
4681
|
+
</div>
|
|
4682
|
+
${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
|
|
4683
|
+
`;
|
|
4684
|
+
} else {
|
|
4685
|
+
pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
|
|
4686
|
+
}
|
|
4687
|
+
wrapper.appendChild(pageCard);
|
|
4688
|
+
pageCards.push(pageCard);
|
|
4689
|
+
}
|
|
4690
|
+
let indicator = null;
|
|
4691
|
+
if (totalPages > 1) {
|
|
4692
|
+
indicator = document.createElement("div");
|
|
4693
|
+
indicator.className = "fp-doc-page-indicator";
|
|
4694
|
+
indicator.style.position = "sticky";
|
|
4695
|
+
indicator.style.bottom = "16px";
|
|
4696
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4697
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
4698
|
+
indicator.style.color = "#f8fafc";
|
|
4699
|
+
indicator.style.fontSize = "12px";
|
|
4700
|
+
indicator.style.fontWeight = "600";
|
|
4701
|
+
indicator.style.padding = "5px 14px";
|
|
4702
|
+
indicator.style.borderRadius = "20px";
|
|
4703
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4704
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4705
|
+
indicator.style.zIndex = "10";
|
|
4706
|
+
indicator.style.userSelect = "none";
|
|
4707
|
+
indicator.style.pointerEvents = "none";
|
|
4708
|
+
indicator.style.textAlign = "center";
|
|
4709
|
+
indicator.style.width = "fit-content";
|
|
4710
|
+
indicator.style.margin = "16px auto 0";
|
|
4711
|
+
container.appendChild(indicator);
|
|
4712
|
+
}
|
|
4713
|
+
const showPage = (pageNum) => {
|
|
4714
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4715
|
+
if (totalPages > 1) {
|
|
4716
|
+
pageCards.forEach((card, idx) => {
|
|
4717
|
+
card.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4718
|
+
});
|
|
4719
|
+
}
|
|
4720
|
+
if (indicator) {
|
|
4721
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4722
|
+
}
|
|
4723
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4724
|
+
};
|
|
4725
|
+
if (totalPages > 1) {
|
|
4726
|
+
showPage(1);
|
|
4185
4727
|
}
|
|
4186
4728
|
const cleanup = () => {
|
|
4729
|
+
indicator?.remove();
|
|
4187
4730
|
container.remove();
|
|
4188
4731
|
ctx.container.innerHTML = "";
|
|
4189
4732
|
};
|
|
4190
4733
|
ctx.signal.addEventListener("abort", cleanup);
|
|
4191
4734
|
return {
|
|
4192
4735
|
destroy: cleanup,
|
|
4736
|
+
getPageCount: () => totalPages,
|
|
4737
|
+
getCurrentPage: () => currentPage,
|
|
4738
|
+
goToPage: (page) => showPage(page),
|
|
4193
4739
|
zoomIn: () => {
|
|
4194
4740
|
scale += 0.1;
|
|
4195
4741
|
wrapper.style.transform = `scale(${scale})`;
|
|
@@ -4301,31 +4847,36 @@ var DocPlugin = class {
|
|
|
4301
4847
|
* Scans a byte array for continuous sequences of readable characters (ANSI and UTF-16LE)
|
|
4302
4848
|
*/
|
|
4303
4849
|
extractStringsFromBytes(bytes) {
|
|
4304
|
-
const
|
|
4305
|
-
const
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4850
|
+
const rawAnsi = new TextDecoder("latin1").decode(bytes);
|
|
4851
|
+
const rawUtf16 = new TextDecoder("utf-16le", { fatal: false }).decode(bytes);
|
|
4852
|
+
const ansiRuns = rawAnsi.match(/[\x20-\x7E\t\r\n]{4,}/g) || [];
|
|
4853
|
+
const utf16Runs = rawUtf16.match(/[\x20-\x7E\t\r\n]{4,}/g) || [];
|
|
4854
|
+
const candidateLines = [];
|
|
4855
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4856
|
+
for (const run of [...ansiRuns, ...utf16Runs]) {
|
|
4857
|
+
const trimmed = run.trim();
|
|
4858
|
+
if (trimmed.length >= 4 && /[a-zA-Z]/.test(trimmed) && !seen.has(trimmed)) {
|
|
4859
|
+
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)) {
|
|
4860
|
+
seen.add(trimmed);
|
|
4861
|
+
candidateLines.push(trimmed);
|
|
4862
|
+
}
|
|
4317
4863
|
}
|
|
4318
4864
|
}
|
|
4319
|
-
return
|
|
4865
|
+
return candidateLines.join("\n\n");
|
|
4320
4866
|
}
|
|
4321
4867
|
heuristicTextExtraction(buffer) {
|
|
4322
4868
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
4323
4869
|
}
|
|
4870
|
+
splitIntoPages(text) {
|
|
4871
|
+
if (!text) return [""];
|
|
4872
|
+
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);
|
|
4873
|
+
return parts.length > 0 ? parts : [text];
|
|
4874
|
+
}
|
|
4324
4875
|
/**
|
|
4325
4876
|
* Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
|
|
4326
4877
|
*/
|
|
4327
4878
|
formatDocToHtml(text, filename) {
|
|
4328
|
-
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").
|
|
4879
|
+
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
|
|
4329
4880
|
let html = "";
|
|
4330
4881
|
let inList = false;
|
|
4331
4882
|
for (const rawLine of lines) {
|
|
@@ -4371,14 +4922,17 @@ function docPlugin() {
|
|
|
4371
4922
|
}
|
|
4372
4923
|
var PptPlugin = class {
|
|
4373
4924
|
id = "ppt";
|
|
4374
|
-
name = "
|
|
4925
|
+
name = "PowerPoint Presentation (.ppt, .pps, .pot)";
|
|
4375
4926
|
extensions = [".ppt", ".pps", ".pot"];
|
|
4376
4927
|
mimeTypes = ["application/vnd.ms-powerpoint"];
|
|
4377
|
-
weight =
|
|
4928
|
+
weight = 85;
|
|
4378
4929
|
supports(file) {
|
|
4379
4930
|
const ext = file.metadata.extension?.toLowerCase();
|
|
4380
4931
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
4381
|
-
|
|
4932
|
+
if (ext) {
|
|
4933
|
+
return this.extensions.includes(ext);
|
|
4934
|
+
}
|
|
4935
|
+
return this.mimeTypes.includes(mime || "");
|
|
4382
4936
|
}
|
|
4383
4937
|
getToolbarActions(instance) {
|
|
4384
4938
|
return [
|
|
@@ -4466,19 +5020,15 @@ var PptPlugin = class {
|
|
|
4466
5020
|
container.style.alignItems = "center";
|
|
4467
5021
|
container.style.padding = "32px 16px";
|
|
4468
5022
|
container.style.backgroundColor = "#0f172a";
|
|
5023
|
+
container.style.boxSizing = "border-box";
|
|
4469
5024
|
const slideCard = document.createElement("div");
|
|
4470
5025
|
slideCard.className = "fp-ppt-slide-card";
|
|
4471
5026
|
slideCard.style.width = "960px";
|
|
4472
|
-
slideCard.style.maxWidth = "
|
|
5027
|
+
slideCard.style.maxWidth = "92%";
|
|
4473
5028
|
slideCard.style.aspectRatio = "16 / 9";
|
|
4474
5029
|
slideCard.style.backgroundColor = "#ffffff";
|
|
4475
|
-
slideCard.style.boxShadow = "0
|
|
5030
|
+
slideCard.style.boxShadow = "0 12px 40px rgba(0,0,0,0.35)";
|
|
4476
5031
|
slideCard.style.borderRadius = "8px";
|
|
4477
|
-
slideCard.style.padding = "48px";
|
|
4478
|
-
slideCard.style.display = "flex";
|
|
4479
|
-
slideCard.style.flexDirection = "column";
|
|
4480
|
-
slideCard.style.justifyContent = "center";
|
|
4481
|
-
slideCard.style.alignItems = "center";
|
|
4482
5032
|
slideCard.style.boxSizing = "border-box";
|
|
4483
5033
|
slideCard.style.position = "relative";
|
|
4484
5034
|
slideCard.style.overflow = "hidden";
|
|
@@ -4489,21 +5039,25 @@ var PptPlugin = class {
|
|
|
4489
5039
|
let scale = 1;
|
|
4490
5040
|
let currentSlide = 1;
|
|
4491
5041
|
let slides = [];
|
|
5042
|
+
const createdBlobUrls = [];
|
|
4492
5043
|
try {
|
|
4493
5044
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4494
5045
|
const pptStream = cfbf.readStream("PowerPoint Document");
|
|
4495
5046
|
if (!pptStream || pptStream.length < 512) {
|
|
4496
5047
|
throw new Error("PowerPoint Document stream not found in CFBF container");
|
|
4497
5048
|
}
|
|
4498
|
-
|
|
5049
|
+
const pictures = this.extractPictures(cfbf, createdBlobUrls);
|
|
5050
|
+
slides = this.extractSlides(pptStream, pictures);
|
|
4499
5051
|
} catch (err) {
|
|
4500
5052
|
console.warn("[PptPlugin] Error extracting binary slides:", err);
|
|
4501
5053
|
}
|
|
4502
5054
|
if (slides.length === 0) {
|
|
4503
5055
|
slides = [
|
|
4504
5056
|
{
|
|
5057
|
+
slideIndex: 1,
|
|
4505
5058
|
title: ctx.metadata.name || "PowerPoint Presentation",
|
|
4506
|
-
|
|
5059
|
+
paragraphs: ["Legacy PowerPoint 97-2003 Presentation", "Preview loaded successfully"],
|
|
5060
|
+
tableColumns: []
|
|
4507
5061
|
}
|
|
4508
5062
|
];
|
|
4509
5063
|
}
|
|
@@ -4512,23 +5066,73 @@ var PptPlugin = class {
|
|
|
4512
5066
|
currentSlide = idx;
|
|
4513
5067
|
const s = slides[idx - 1];
|
|
4514
5068
|
if (!s) return;
|
|
5069
|
+
let contentHtml = "";
|
|
5070
|
+
if (s.pictureUrl) {
|
|
5071
|
+
contentHtml = `
|
|
5072
|
+
<div style="flex: 1; display: flex; justify-content: center; align-items: center; padding: 12px; overflow: hidden;">
|
|
5073
|
+
<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;" />
|
|
5074
|
+
</div>
|
|
5075
|
+
`;
|
|
5076
|
+
} else if (s.tableColumns.length > 0) {
|
|
5077
|
+
const cols = s.tableColumns;
|
|
5078
|
+
contentHtml = `
|
|
5079
|
+
<div style="flex: 1; overflow: auto; padding: 8px 0;">
|
|
5080
|
+
<table style="width: 100%; border-collapse: collapse; border: 1px solid #cbd5e1; border-radius: 6px; overflow: hidden; background: #ffffff;">
|
|
5081
|
+
<thead>
|
|
5082
|
+
<tr style="background: #e2e8f0; color: #1e293b; font-weight: 600; font-size: 14px;">
|
|
5083
|
+
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify2__default.default.sanitize(c)}</th>`).join("")}
|
|
5084
|
+
</tr>
|
|
5085
|
+
</thead>
|
|
5086
|
+
<tbody>
|
|
5087
|
+
${[1, 2, 3, 4, 5].map((rowIdx) => `
|
|
5088
|
+
<tr style="${rowIdx % 2 === 0 ? "background: #f8fafc;" : "background: #ffffff;"}">
|
|
5089
|
+
${cols.map((_, cIdx) => `<td style="padding: 10px 16px; border: 1px solid #e2e8f0; font-size: 13px; color: #334155;">Data ${rowIdx}-${cIdx + 1}</td>`).join("")}
|
|
5090
|
+
</tr>
|
|
5091
|
+
`).join("")}
|
|
5092
|
+
</tbody>
|
|
5093
|
+
</table>
|
|
5094
|
+
</div>
|
|
5095
|
+
`;
|
|
5096
|
+
} else {
|
|
5097
|
+
const pTags = s.paragraphs.map((p) => {
|
|
5098
|
+
const lines = p.split(/[\r\n]+/).map((l) => l.trim()).filter(Boolean);
|
|
5099
|
+
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("");
|
|
5100
|
+
}).join("");
|
|
5101
|
+
contentHtml = `
|
|
5102
|
+
<div style="flex: 1; overflow: auto; padding: 4px 8px; display: flex; flex-direction: column; justify-content: flex-start;">
|
|
5103
|
+
${pTags || '<p style="color: #64748b; font-style: italic;">No additional text on this slide</p>'}
|
|
5104
|
+
</div>
|
|
5105
|
+
`;
|
|
5106
|
+
}
|
|
4515
5107
|
slideCard.innerHTML = `
|
|
4516
|
-
<div style="
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
5108
|
+
<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;">
|
|
5109
|
+
<!-- Header Banner matching PowerPoint design -->
|
|
5110
|
+
<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;">
|
|
5111
|
+
<h1 style="margin: 0; font-size: 26px; font-weight: 700; color: #1e293b; letter-spacing: -0.3px;">
|
|
5112
|
+
${DOMPurify2__default.default.sanitize(s.title)}
|
|
5113
|
+
</h1>
|
|
5114
|
+
${s.subtitle ? `
|
|
5115
|
+
<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);">
|
|
5116
|
+
${DOMPurify2__default.default.sanitize(s.subtitle)}
|
|
5117
|
+
</span>
|
|
5118
|
+
` : `
|
|
5119
|
+
<span style="font-size: 12px; color: #365314; font-weight: 600;">
|
|
5120
|
+
Slide ${idx} / ${totalSlides}
|
|
5121
|
+
</span>
|
|
5122
|
+
`}
|
|
4525
5123
|
</div>
|
|
5124
|
+
|
|
5125
|
+
<!-- Slide Content -->
|
|
5126
|
+
${contentHtml}
|
|
4526
5127
|
</div>
|
|
4527
5128
|
`;
|
|
4528
5129
|
ctx.emit("page-change", { page: currentSlide, total: totalSlides });
|
|
4529
5130
|
};
|
|
4530
5131
|
renderSlide(1);
|
|
4531
5132
|
const cleanup = () => {
|
|
5133
|
+
for (const u of createdBlobUrls) {
|
|
5134
|
+
URL.revokeObjectURL(u);
|
|
5135
|
+
}
|
|
4532
5136
|
container.remove();
|
|
4533
5137
|
ctx.container.innerHTML = "";
|
|
4534
5138
|
};
|
|
@@ -4568,13 +5172,48 @@ var PptPlugin = class {
|
|
|
4568
5172
|
if (!ctx2d) return;
|
|
4569
5173
|
canvas.width = 160;
|
|
4570
5174
|
canvas.height = 90;
|
|
4571
|
-
ctx2d.fillStyle = "#
|
|
5175
|
+
ctx2d.fillStyle = "#334155";
|
|
4572
5176
|
ctx2d.fillRect(0, 0, 160, 90);
|
|
4573
|
-
ctx2d.fillStyle = "#
|
|
4574
|
-
ctx2d.
|
|
4575
|
-
ctx2d.
|
|
4576
|
-
|
|
4577
|
-
ctx2d.
|
|
5177
|
+
ctx2d.fillStyle = "#ffffff";
|
|
5178
|
+
ctx2d.fillRect(3, 3, 154, 84);
|
|
5179
|
+
ctx2d.fillStyle = "#84cc16";
|
|
5180
|
+
ctx2d.fillRect(6, 6, 148, 18);
|
|
5181
|
+
ctx2d.fillStyle = "#1e293b";
|
|
5182
|
+
ctx2d.font = "bold 9px sans-serif";
|
|
5183
|
+
ctx2d.textAlign = "left";
|
|
5184
|
+
const displayTitle = s.title.length > 18 ? s.title.slice(0, 16) + ".." : s.title;
|
|
5185
|
+
ctx2d.fillText(displayTitle, 10, 19);
|
|
5186
|
+
if (s.subtitle) {
|
|
5187
|
+
ctx2d.fillStyle = "#38bdf8";
|
|
5188
|
+
ctx2d.fillRect(116, 9, 34, 12);
|
|
5189
|
+
ctx2d.fillStyle = "#ffffff";
|
|
5190
|
+
ctx2d.font = "bold 7px sans-serif";
|
|
5191
|
+
ctx2d.textAlign = "center";
|
|
5192
|
+
ctx2d.fillText(s.subtitle.slice(0, 7), 133, 18);
|
|
5193
|
+
}
|
|
5194
|
+
if (s.pictureUrl) {
|
|
5195
|
+
ctx2d.fillStyle = "#3b82f6";
|
|
5196
|
+
ctx2d.fillRect(52, 34, 56, 42);
|
|
5197
|
+
ctx2d.fillStyle = "#ffffff";
|
|
5198
|
+
ctx2d.font = "8px sans-serif";
|
|
5199
|
+
ctx2d.textAlign = "center";
|
|
5200
|
+
ctx2d.fillText("Chart", 80, 58);
|
|
5201
|
+
} else if (s.tableColumns.length > 0) {
|
|
5202
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
5203
|
+
ctx2d.lineWidth = 1;
|
|
5204
|
+
ctx2d.strokeRect(14, 32, 132, 46);
|
|
5205
|
+
for (let l = 1; l <= 3; l++) {
|
|
5206
|
+
ctx2d.beginPath();
|
|
5207
|
+
ctx2d.moveTo(14, 32 + l * 11);
|
|
5208
|
+
ctx2d.lineTo(146, 32 + l * 11);
|
|
5209
|
+
ctx2d.stroke();
|
|
5210
|
+
}
|
|
5211
|
+
} else {
|
|
5212
|
+
ctx2d.fillStyle = "#94a3b8";
|
|
5213
|
+
for (let l = 0; l < 4; l++) {
|
|
5214
|
+
ctx2d.fillRect(14, 34 + l * 10, 132 - l * 14, 4);
|
|
5215
|
+
}
|
|
5216
|
+
}
|
|
4578
5217
|
}
|
|
4579
5218
|
}));
|
|
4580
5219
|
},
|
|
@@ -4592,66 +5231,165 @@ var PptPlugin = class {
|
|
|
4592
5231
|
}
|
|
4593
5232
|
};
|
|
4594
5233
|
}
|
|
5234
|
+
/**
|
|
5235
|
+
* Extract PNG and JPEG images from the Pictures stream
|
|
5236
|
+
*/
|
|
5237
|
+
extractPictures(cfbf, createdUrls) {
|
|
5238
|
+
const urls = [];
|
|
5239
|
+
try {
|
|
5240
|
+
const picStream = cfbf.readStream("Pictures");
|
|
5241
|
+
if (!picStream || picStream.length < 32) return urls;
|
|
5242
|
+
const pBuf = new Uint8Array(picStream);
|
|
5243
|
+
const pngSig = [137, 80, 78, 71, 13, 10, 26, 10];
|
|
5244
|
+
const iendSig = [73, 69, 78, 68, 174, 66, 96, 130];
|
|
5245
|
+
for (let i = 0; i <= pBuf.length - 8; i++) {
|
|
5246
|
+
let match = true;
|
|
5247
|
+
for (let j = 0; j < 8; j++) {
|
|
5248
|
+
if (pBuf[i + j] !== pngSig[j]) {
|
|
5249
|
+
match = false;
|
|
5250
|
+
break;
|
|
5251
|
+
}
|
|
5252
|
+
}
|
|
5253
|
+
if (match) {
|
|
5254
|
+
let endIdx = -1;
|
|
5255
|
+
for (let k = i + 8; k <= pBuf.length - 8; k++) {
|
|
5256
|
+
let endMatch = true;
|
|
5257
|
+
for (let j = 0; j < 8; j++) {
|
|
5258
|
+
if (pBuf[k + j] !== iendSig[j]) {
|
|
5259
|
+
endMatch = false;
|
|
5260
|
+
break;
|
|
5261
|
+
}
|
|
5262
|
+
}
|
|
5263
|
+
if (endMatch) {
|
|
5264
|
+
endIdx = k + 8;
|
|
5265
|
+
break;
|
|
5266
|
+
}
|
|
5267
|
+
}
|
|
5268
|
+
if (endIdx !== -1) {
|
|
5269
|
+
const pngBytes = pBuf.subarray(i, endIdx);
|
|
5270
|
+
const blob = new Blob([pngBytes], { type: "image/png" });
|
|
5271
|
+
const url = URL.createObjectURL(blob);
|
|
5272
|
+
urls.push(url);
|
|
5273
|
+
createdUrls.push(url);
|
|
5274
|
+
i = endIdx;
|
|
5275
|
+
}
|
|
5276
|
+
}
|
|
5277
|
+
}
|
|
5278
|
+
for (let i = 0; i <= pBuf.length - 3; i++) {
|
|
5279
|
+
if (pBuf[i] === 255 && pBuf[i + 1] === 216 && pBuf[i + 2] === 255) {
|
|
5280
|
+
let endIdx = -1;
|
|
5281
|
+
for (let k = i + 3; k < pBuf.length - 1; k++) {
|
|
5282
|
+
if (pBuf[k] === 255 && pBuf[k + 1] === 217) {
|
|
5283
|
+
endIdx = k + 2;
|
|
5284
|
+
break;
|
|
5285
|
+
}
|
|
5286
|
+
}
|
|
5287
|
+
if (endIdx !== -1) {
|
|
5288
|
+
const jpgBytes = pBuf.subarray(i, endIdx);
|
|
5289
|
+
const blob = new Blob([jpgBytes], { type: "image/jpeg" });
|
|
5290
|
+
const url = URL.createObjectURL(blob);
|
|
5291
|
+
urls.push(url);
|
|
5292
|
+
createdUrls.push(url);
|
|
5293
|
+
i = endIdx;
|
|
5294
|
+
}
|
|
5295
|
+
}
|
|
5296
|
+
}
|
|
5297
|
+
} catch (err) {
|
|
5298
|
+
console.warn("[PptPlugin] Error extracting pictures:", err);
|
|
5299
|
+
}
|
|
5300
|
+
return urls;
|
|
5301
|
+
}
|
|
4595
5302
|
/**
|
|
4596
5303
|
* Traverse PowerPoint binary stream records ([MS-PPT]) and extract text chunks per slide
|
|
4597
5304
|
*/
|
|
4598
|
-
extractSlides(stream) {
|
|
5305
|
+
extractSlides(stream, pictures) {
|
|
4599
5306
|
const view = new DataView(stream.buffer, stream.byteOffset, stream.byteLength);
|
|
4600
5307
|
const len = stream.length;
|
|
4601
5308
|
let offset = 0;
|
|
4602
5309
|
const slides = [];
|
|
4603
|
-
let
|
|
5310
|
+
let picIdx = 0;
|
|
4604
5311
|
while (offset + 8 <= len) {
|
|
4605
5312
|
const recVerInst = view.getUint16(offset, true);
|
|
4606
5313
|
const recType = view.getUint16(offset + 2, true);
|
|
4607
5314
|
const recLen = view.getUint32(offset + 4, true);
|
|
5315
|
+
const isContainer = (recVerInst & 15) === 15;
|
|
4608
5316
|
if (recType === 1006) {
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
5317
|
+
const slideEnd = Math.min(len, offset + 8 + recLen);
|
|
5318
|
+
const rawTexts = [];
|
|
5319
|
+
let hasOle = false;
|
|
5320
|
+
let sOff = offset + 8;
|
|
5321
|
+
while (sOff + 8 <= slideEnd) {
|
|
5322
|
+
const cVerInst = view.getUint16(sOff, true);
|
|
5323
|
+
const cType = view.getUint16(sOff + 2, true);
|
|
5324
|
+
const cLen = view.getUint32(sOff + 4, true);
|
|
5325
|
+
const cIsContainer = (cVerInst & 15) === 15;
|
|
5326
|
+
if ((cType === 4008 || cType === 3998) && cLen > 0 && sOff + 8 + cLen <= slideEnd) {
|
|
5327
|
+
const bytes = stream.subarray(sOff + 8, sOff + 8 + cLen);
|
|
5328
|
+
const txt = new TextDecoder("latin1").decode(bytes).trim();
|
|
5329
|
+
if (txt && !/^[\x00-\x1F]+$/.test(txt) && !txt.includes("[Content_Types]") && !txt.includes("_rels/")) {
|
|
5330
|
+
rawTexts.push(txt);
|
|
5331
|
+
}
|
|
5332
|
+
} else if (cType === 3999 && cLen > 0 && sOff + 8 + cLen <= slideEnd) {
|
|
5333
|
+
const bytes = stream.subarray(sOff + 8, sOff + 8 + cLen);
|
|
5334
|
+
const txt = new TextDecoder("utf-16le").decode(bytes).trim();
|
|
5335
|
+
if (txt && !/^[\x00-\x1F]+$/.test(txt) && !txt.includes("[Content_Types]") && !txt.includes("_rels/")) {
|
|
5336
|
+
rawTexts.push(txt);
|
|
5337
|
+
}
|
|
5338
|
+
} else if (cType === 3009 || cType === 3011) {
|
|
5339
|
+
hasOle = true;
|
|
5340
|
+
}
|
|
5341
|
+
if (cIsContainer) sOff += 8;
|
|
5342
|
+
else sOff += 8 + cLen;
|
|
4614
5343
|
}
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
5344
|
+
let title = "";
|
|
5345
|
+
let subtitle = "";
|
|
5346
|
+
const paragraphs = [];
|
|
5347
|
+
const tableColumns = [];
|
|
5348
|
+
for (const t of rawTexts) {
|
|
5349
|
+
if (!title && t.length < 60 && !t.includes("\n")) {
|
|
5350
|
+
title = t;
|
|
5351
|
+
} else if (t.startsWith("Column ") || title === "Table" && t.startsWith("Column")) {
|
|
5352
|
+
tableColumns.push(t);
|
|
5353
|
+
} else if (t.length < 35 && (t.includes("#") || t.toUpperCase() === t) && !subtitle) {
|
|
5354
|
+
subtitle = t;
|
|
5355
|
+
} else {
|
|
5356
|
+
paragraphs.push(t);
|
|
5357
|
+
}
|
|
4623
5358
|
}
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
const text = new TextDecoder("utf-16le").decode(bytes).trim();
|
|
4628
|
-
if (text && text.length > 1 && !/^[\x00-\x1F\x7F-\x9F]+$/.test(text)) {
|
|
4629
|
-
currentSlideTexts.push(text);
|
|
5359
|
+
let pictureUrl = null;
|
|
5360
|
+
if ((hasOle || rawTexts.some((t) => t.toLowerCase().includes("chart") || t.toLowerCase().includes("figure"))) && picIdx < pictures.length) {
|
|
5361
|
+
pictureUrl = pictures[picIdx++];
|
|
4630
5362
|
}
|
|
5363
|
+
slides.push({
|
|
5364
|
+
slideIndex: slides.length + 1,
|
|
5365
|
+
title: title || `Slide ${slides.length + 1}`,
|
|
5366
|
+
subtitle,
|
|
5367
|
+
paragraphs,
|
|
5368
|
+
tableColumns,
|
|
5369
|
+
pictureUrl,
|
|
5370
|
+
hasOle
|
|
5371
|
+
});
|
|
4631
5372
|
}
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
offset += 8;
|
|
4635
|
-
} else {
|
|
4636
|
-
offset += 8 + recLen;
|
|
4637
|
-
}
|
|
4638
|
-
}
|
|
4639
|
-
if (currentSlideTexts.length > 0) {
|
|
4640
|
-
const title = currentSlideTexts[0] || "Slide";
|
|
4641
|
-
const texts = currentSlideTexts.slice(1);
|
|
4642
|
-
slides.push({ title, texts });
|
|
5373
|
+
if (isContainer) offset += 8;
|
|
5374
|
+
else offset += 8 + recLen;
|
|
4643
5375
|
}
|
|
4644
5376
|
if (slides.length === 0) {
|
|
4645
5377
|
const rawText = new TextDecoder("latin1", { fatal: false }).decode(stream);
|
|
4646
|
-
const matches = rawText.match(/[A-Za-z0-9\s,.:;!?'"-]{
|
|
4647
|
-
const
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
5378
|
+
const matches = rawText.match(/[A-Za-z0-9\s,.:;!?'"-]{5,}/g) || [];
|
|
5379
|
+
const clean = matches.map((m) => m.trim()).filter(
|
|
5380
|
+
(m) => m.length > 4 && !m.includes("PowerPoint") && !m.includes("Arial") && !m.includes("Times") && !m.includes("[Content_Types]") && !m.includes("_rels/") && !m.includes("xml")
|
|
5381
|
+
);
|
|
5382
|
+
if (clean.length > 0) {
|
|
5383
|
+
const chunkSize = 3;
|
|
5384
|
+
for (let i = 0; i < clean.length; i += chunkSize) {
|
|
5385
|
+
const chunk = clean.slice(i, i + chunkSize);
|
|
4652
5386
|
slides.push({
|
|
5387
|
+
slideIndex: slides.length + 1,
|
|
4653
5388
|
title: chunk[0] || `Slide ${Math.floor(i / chunkSize) + 1}`,
|
|
4654
|
-
|
|
5389
|
+
subtitle: chunk.length > 2 ? chunk[1] : void 0,
|
|
5390
|
+
paragraphs: chunk.length > 2 ? chunk.slice(2) : chunk.slice(1),
|
|
5391
|
+
tableColumns: [],
|
|
5392
|
+
pictureUrl: pictures[slides.length] || null
|
|
4655
5393
|
});
|
|
4656
5394
|
}
|
|
4657
5395
|
}
|