@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.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Component, ChangeDetectionStrategy, Input, Output, ViewChild, EventEmitter as EventEmitter$1 } from '@angular/core';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import DOMPurify2 from 'dompurify';
|
|
4
|
+
import * as pdfjsLib from 'pdfjs-dist';
|
|
4
5
|
import * as docx from 'docx-preview';
|
|
5
6
|
import { unzipSync, strFromU8, unzip } from 'fflate';
|
|
6
7
|
import * as XLSX from 'xlsx';
|
|
@@ -11,7 +12,7 @@ import * as THREE from 'three';
|
|
|
11
12
|
import { STLLoader } from 'three/examples/jsm/loaders/STLLoader.js';
|
|
12
13
|
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
|
|
13
14
|
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
|
|
14
|
-
import
|
|
15
|
+
import * as RTFJS from 'rtf.js/dist/RTFJS.bundle.js';
|
|
15
16
|
|
|
16
17
|
var __create = Object.create;
|
|
17
18
|
var __defProp = Object.defineProperty;
|
|
@@ -314,6 +315,39 @@ function detectOoxmlType(buffer) {
|
|
|
314
315
|
}
|
|
315
316
|
return "application/zip";
|
|
316
317
|
}
|
|
318
|
+
function detectCfbfType(buffer) {
|
|
319
|
+
const bytes = new Uint8Array(buffer);
|
|
320
|
+
const hasUtf16le = (str) => {
|
|
321
|
+
const target = new Uint8Array(str.length * 2);
|
|
322
|
+
for (let i = 0; i < str.length; i++) {
|
|
323
|
+
target[i * 2] = str.charCodeAt(i);
|
|
324
|
+
target[i * 2 + 1] = 0;
|
|
325
|
+
}
|
|
326
|
+
const targetLen = target.length;
|
|
327
|
+
const max = bytes.length - targetLen;
|
|
328
|
+
for (let i = 0; i <= max; i++) {
|
|
329
|
+
let match = true;
|
|
330
|
+
for (let j = 0; j < targetLen; j++) {
|
|
331
|
+
if (bytes[i + j] !== target[j]) {
|
|
332
|
+
match = false;
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
if (match) return true;
|
|
337
|
+
}
|
|
338
|
+
return false;
|
|
339
|
+
};
|
|
340
|
+
if (hasUtf16le("PowerPoint Document")) {
|
|
341
|
+
return { mime: "application/vnd.ms-powerpoint", extension: ".ppt" };
|
|
342
|
+
}
|
|
343
|
+
if (hasUtf16le("WordDocument")) {
|
|
344
|
+
return { mime: "application/msword", extension: ".doc" };
|
|
345
|
+
}
|
|
346
|
+
if (hasUtf16le("Workbook") || hasUtf16le("Book")) {
|
|
347
|
+
return { mime: "application/vnd.ms-excel", extension: ".xls" };
|
|
348
|
+
}
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
317
351
|
function extractExtension(nameOrUrl) {
|
|
318
352
|
try {
|
|
319
353
|
const url = new URL(nameOrUrl);
|
|
@@ -378,6 +412,18 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
378
412
|
} else {
|
|
379
413
|
metadata.mimeType = metadata.mimeType ?? magicMime;
|
|
380
414
|
}
|
|
415
|
+
} else if (magicMime === "application/x-cfbf") {
|
|
416
|
+
if (metadata.extension) {
|
|
417
|
+
metadata.mimeType = mimeFromExtension(metadata.extension) ?? magicMime;
|
|
418
|
+
} else {
|
|
419
|
+
const cfbf = detectCfbfType(buffer);
|
|
420
|
+
if (cfbf) {
|
|
421
|
+
metadata.mimeType = cfbf.mime;
|
|
422
|
+
metadata.extension = cfbf.extension;
|
|
423
|
+
} else {
|
|
424
|
+
metadata.mimeType = magicMime;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
381
427
|
} else {
|
|
382
428
|
metadata.mimeType = magicMime;
|
|
383
429
|
}
|
|
@@ -482,11 +528,21 @@ var ToolbarController = class {
|
|
|
482
528
|
el;
|
|
483
529
|
toolbarEl;
|
|
484
530
|
actions = [];
|
|
531
|
+
pageInputEl = null;
|
|
532
|
+
pageLabelEl = null;
|
|
485
533
|
constructor(container) {
|
|
486
534
|
this.el = container;
|
|
487
535
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
488
536
|
this.el.appendChild(this.toolbarEl);
|
|
489
537
|
}
|
|
538
|
+
setPage(page, max) {
|
|
539
|
+
if (this.pageInputEl) {
|
|
540
|
+
this.pageInputEl.value = page.toString();
|
|
541
|
+
}
|
|
542
|
+
if (max !== void 0 && this.pageLabelEl) {
|
|
543
|
+
this.pageLabelEl.textContent = ` / ${max}`;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
490
546
|
update(actions) {
|
|
491
547
|
this.actions = actions;
|
|
492
548
|
this.render();
|
|
@@ -529,6 +585,7 @@ var ToolbarController = class {
|
|
|
529
585
|
if (action.type === "separator") {
|
|
530
586
|
groupEl.appendChild(createElement("div", { className: "fp-toolbar-separator" }));
|
|
531
587
|
} else if (action.type === "page-nav") {
|
|
588
|
+
const max = action.max ?? 1;
|
|
532
589
|
const prevBtn = this.createButton(
|
|
533
590
|
"prev",
|
|
534
591
|
ICON_PAGE_PREV,
|
|
@@ -547,7 +604,6 @@ var ToolbarController = class {
|
|
|
547
604
|
"Next Page",
|
|
548
605
|
() => {
|
|
549
606
|
const cur = parseInt(input.value, 10) || 1;
|
|
550
|
-
const max = action.max ?? 1;
|
|
551
607
|
if (cur < max) {
|
|
552
608
|
input.value = (cur + 1).toString();
|
|
553
609
|
action.execute("next", cur + 1);
|
|
@@ -559,15 +615,18 @@ var ToolbarController = class {
|
|
|
559
615
|
type: "number",
|
|
560
616
|
value: (action.value ?? 1).toString(),
|
|
561
617
|
min: "1",
|
|
562
|
-
max:
|
|
618
|
+
max: max.toString()
|
|
563
619
|
});
|
|
564
620
|
input.addEventListener("change", () => {
|
|
565
|
-
|
|
566
|
-
if (
|
|
567
|
-
|
|
568
|
-
|
|
621
|
+
let val = parseInt(input.value, 10);
|
|
622
|
+
if (isNaN(val)) val = 1;
|
|
623
|
+
val = Math.max(1, Math.min(max, val));
|
|
624
|
+
input.value = val.toString();
|
|
625
|
+
action.execute("go", val);
|
|
569
626
|
});
|
|
570
|
-
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${
|
|
627
|
+
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
628
|
+
this.pageInputEl = input;
|
|
629
|
+
this.pageLabelEl = label;
|
|
571
630
|
groupEl.appendChild(prevBtn);
|
|
572
631
|
groupEl.appendChild(input);
|
|
573
632
|
groupEl.appendChild(label);
|
|
@@ -745,7 +804,13 @@ var FilePreviewViewer = class {
|
|
|
745
804
|
buffer,
|
|
746
805
|
options,
|
|
747
806
|
signal,
|
|
748
|
-
emit: (event, payload) =>
|
|
807
|
+
emit: (event, payload) => {
|
|
808
|
+
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
809
|
+
const total = payload.total ?? payload.totalPages;
|
|
810
|
+
this.toolbar?.setPage(payload.page, total);
|
|
811
|
+
}
|
|
812
|
+
this.eventEmitter.emit(event, payload);
|
|
813
|
+
}
|
|
749
814
|
});
|
|
750
815
|
this.activeInstance = instance;
|
|
751
816
|
this.hideLoading();
|
|
@@ -779,6 +844,7 @@ var FilePreviewViewer = class {
|
|
|
779
844
|
if (thumbnails && thumbnails.length > 0 && this.thumbnailPanel) {
|
|
780
845
|
this.thumbnailPanel.update(thumbnails, (index) => {
|
|
781
846
|
instance.goToPage?.(index + 1);
|
|
847
|
+
this.toolbar?.setPage(index + 1);
|
|
782
848
|
});
|
|
783
849
|
if (options.showThumbnails) {
|
|
784
850
|
this.thumbnailPanel.show();
|
|
@@ -904,9 +970,13 @@ var FilePreviewViewer = class {
|
|
|
904
970
|
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
905
971
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
906
972
|
this.activeInstance.goToPage?.(cur + 1);
|
|
973
|
+
const nextCur = this.activeInstance.getCurrentPage?.() ?? cur + 1;
|
|
974
|
+
this.toolbar?.setPage(nextCur);
|
|
907
975
|
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
908
976
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
909
977
|
this.activeInstance.goToPage?.(Math.max(1, cur - 1));
|
|
978
|
+
const prevCur = this.activeInstance.getCurrentPage?.() ?? Math.max(1, cur - 1);
|
|
979
|
+
this.toolbar?.setPage(prevCur);
|
|
910
980
|
} else if (e.key === "+" || e.key === "=") {
|
|
911
981
|
this.activeInstance.zoomIn?.();
|
|
912
982
|
} else if (e.key === "-" || e.key === "_") {
|
|
@@ -1172,30 +1242,62 @@ var CfbfReader = class {
|
|
|
1172
1242
|
return result.subarray(0, targetSize);
|
|
1173
1243
|
}
|
|
1174
1244
|
};
|
|
1175
|
-
|
|
1176
|
-
|
|
1245
|
+
if (typeof window !== "undefined" && pdfjsLib.GlobalWorkerOptions) {
|
|
1246
|
+
if (!pdfjsLib.GlobalWorkerOptions.workerSrc) {
|
|
1247
|
+
pdfjsLib.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjsLib.version || "4.10.38"}/build/pdf.worker.min.mjs`;
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1177
1250
|
var PdfPlugin = class {
|
|
1178
1251
|
id = "pdf";
|
|
1179
|
-
name = "PDF Preview";
|
|
1252
|
+
name = "PDF Document Preview";
|
|
1180
1253
|
extensions = [".pdf"];
|
|
1181
1254
|
mimeTypes = ["application/pdf"];
|
|
1182
1255
|
weight = 100;
|
|
1183
1256
|
supports(file) {
|
|
1184
1257
|
const ext = file.metadata.extension?.toLowerCase();
|
|
1185
1258
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
1186
|
-
|
|
1259
|
+
if (ext) return this.extensions.includes(ext);
|
|
1260
|
+
return this.mimeTypes.includes(mime || "");
|
|
1187
1261
|
}
|
|
1188
1262
|
getToolbarActions(instance) {
|
|
1263
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1264
|
+
const curPage = instance.getCurrentPage?.() ?? 1;
|
|
1189
1265
|
return [
|
|
1266
|
+
{
|
|
1267
|
+
id: "thumbnails",
|
|
1268
|
+
icon: "thumbnails",
|
|
1269
|
+
label: "Page Thumbnails",
|
|
1270
|
+
type: "button",
|
|
1271
|
+
group: "navigation",
|
|
1272
|
+
execute: () => instance.toggleThumbnails?.()
|
|
1273
|
+
},
|
|
1274
|
+
{
|
|
1275
|
+
id: "page-nav",
|
|
1276
|
+
icon: "",
|
|
1277
|
+
label: "Page Navigation",
|
|
1278
|
+
type: "page-nav",
|
|
1279
|
+
group: "navigation",
|
|
1280
|
+
value: curPage,
|
|
1281
|
+
max: totalPages,
|
|
1282
|
+
execute: (action, page) => {
|
|
1283
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1284
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1285
|
+
if (action === "prev") {
|
|
1286
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1287
|
+
} else if (action === "next") {
|
|
1288
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1289
|
+
} else if (typeof page === "number") {
|
|
1290
|
+
instance.goToPage?.(page);
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
},
|
|
1190
1294
|
{
|
|
1191
1295
|
id: "zoom-out",
|
|
1192
1296
|
icon: "zoom-out",
|
|
1193
1297
|
label: "Zoom Out",
|
|
1194
1298
|
type: "button",
|
|
1195
1299
|
group: "zoom",
|
|
1196
|
-
execute: () =>
|
|
1197
|
-
instance.zoomOut?.();
|
|
1198
|
-
}
|
|
1300
|
+
execute: () => instance.zoomOut?.()
|
|
1199
1301
|
},
|
|
1200
1302
|
{
|
|
1201
1303
|
id: "zoom-in",
|
|
@@ -1203,9 +1305,7 @@ var PdfPlugin = class {
|
|
|
1203
1305
|
label: "Zoom In",
|
|
1204
1306
|
type: "button",
|
|
1205
1307
|
group: "zoom",
|
|
1206
|
-
execute: () =>
|
|
1207
|
-
instance.zoomIn?.();
|
|
1208
|
-
}
|
|
1308
|
+
execute: () => instance.zoomIn?.()
|
|
1209
1309
|
},
|
|
1210
1310
|
{
|
|
1211
1311
|
id: "fit-page",
|
|
@@ -1213,39 +1313,23 @@ var PdfPlugin = class {
|
|
|
1213
1313
|
label: "Fit to Page",
|
|
1214
1314
|
type: "button",
|
|
1215
1315
|
group: "zoom",
|
|
1216
|
-
execute: () =>
|
|
1217
|
-
instance.fitToPage?.();
|
|
1218
|
-
}
|
|
1316
|
+
execute: () => instance.fitToPage?.()
|
|
1219
1317
|
},
|
|
1220
1318
|
{
|
|
1221
1319
|
id: "rotate-cw",
|
|
1222
1320
|
icon: "rotate-cw",
|
|
1223
|
-
label: "Rotate",
|
|
1321
|
+
label: "Rotate Clockwise",
|
|
1224
1322
|
type: "button",
|
|
1225
1323
|
group: "view",
|
|
1226
|
-
execute: () =>
|
|
1227
|
-
instance.rotateCW?.();
|
|
1228
|
-
}
|
|
1229
|
-
},
|
|
1230
|
-
{
|
|
1231
|
-
id: "page-nav",
|
|
1232
|
-
icon: "page-nav",
|
|
1233
|
-
label: "Page Navigation",
|
|
1234
|
-
type: "page-nav",
|
|
1235
|
-
group: "navigation",
|
|
1236
|
-
execute: (page) => {
|
|
1237
|
-
if (typeof page === "number") instance.goToPage?.(page);
|
|
1238
|
-
}
|
|
1324
|
+
execute: () => instance.rotateCW?.()
|
|
1239
1325
|
},
|
|
1240
1326
|
{
|
|
1241
1327
|
id: "download",
|
|
1242
1328
|
icon: "download",
|
|
1243
|
-
label: "Download",
|
|
1329
|
+
label: "Download PDF",
|
|
1244
1330
|
type: "button",
|
|
1245
1331
|
group: "actions",
|
|
1246
|
-
execute: () =>
|
|
1247
|
-
instance.download?.();
|
|
1248
|
-
}
|
|
1332
|
+
execute: () => instance.download?.()
|
|
1249
1333
|
},
|
|
1250
1334
|
{
|
|
1251
1335
|
id: "print",
|
|
@@ -1253,99 +1337,213 @@ var PdfPlugin = class {
|
|
|
1253
1337
|
label: "Print",
|
|
1254
1338
|
type: "button",
|
|
1255
1339
|
group: "actions",
|
|
1256
|
-
execute: () =>
|
|
1257
|
-
instance.print?.();
|
|
1258
|
-
}
|
|
1340
|
+
execute: () => instance.print?.()
|
|
1259
1341
|
}
|
|
1260
1342
|
];
|
|
1261
1343
|
}
|
|
1262
1344
|
async render(ctx) {
|
|
1263
|
-
const
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1345
|
+
const container = document.createElement("div");
|
|
1346
|
+
container.className = "fp-pdf-container";
|
|
1347
|
+
container.style.width = "100%";
|
|
1348
|
+
container.style.height = "100%";
|
|
1349
|
+
container.style.overflow = "auto";
|
|
1350
|
+
container.style.display = "flex";
|
|
1351
|
+
container.style.flexDirection = "column";
|
|
1352
|
+
container.style.alignItems = "center";
|
|
1353
|
+
container.style.padding = "24px 16px";
|
|
1354
|
+
container.style.backgroundColor = "#0f172a";
|
|
1355
|
+
container.style.boxSizing = "border-box";
|
|
1356
|
+
container.style.position = "relative";
|
|
1357
|
+
const pageCard = document.createElement("div");
|
|
1358
|
+
pageCard.className = "fp-pdf-page-card";
|
|
1359
|
+
pageCard.style.boxShadow = "0 10px 35px rgba(0, 0, 0, 0.5)";
|
|
1360
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
1361
|
+
pageCard.style.borderRadius = "4px";
|
|
1362
|
+
pageCard.style.overflow = "hidden";
|
|
1363
|
+
pageCard.style.lineHeight = "0";
|
|
1364
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
1365
|
+
pageCard.style.position = "relative";
|
|
1366
|
+
const canvas = document.createElement("canvas");
|
|
1367
|
+
pageCard.appendChild(canvas);
|
|
1368
|
+
container.appendChild(pageCard);
|
|
1369
|
+
const indicator = document.createElement("div");
|
|
1370
|
+
indicator.className = "fp-pdf-page-indicator";
|
|
1371
|
+
indicator.style.position = "sticky";
|
|
1372
|
+
indicator.style.bottom = "16px";
|
|
1373
|
+
indicator.style.marginTop = "16px";
|
|
1374
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1375
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
1376
|
+
indicator.style.color = "#f8fafc";
|
|
1377
|
+
indicator.style.fontSize = "12px";
|
|
1378
|
+
indicator.style.fontWeight = "600";
|
|
1379
|
+
indicator.style.padding = "5px 14px";
|
|
1380
|
+
indicator.style.borderRadius = "20px";
|
|
1381
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1382
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1383
|
+
indicator.style.zIndex = "10";
|
|
1384
|
+
indicator.style.userSelect = "none";
|
|
1385
|
+
indicator.style.pointerEvents = "none";
|
|
1386
|
+
container.appendChild(indicator);
|
|
1387
|
+
ctx.container.appendChild(container);
|
|
1388
|
+
const loadingTask = pdfjsLib.getDocument({
|
|
1389
|
+
data: new Uint8Array(ctx.buffer),
|
|
1390
|
+
cMapUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib.version || "4.10.38"}/cmaps/`,
|
|
1391
|
+
cMapPacked: true,
|
|
1392
|
+
standardFontDataUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib.version || "4.10.38"}/standard_fonts/`
|
|
1393
|
+
});
|
|
1394
|
+
const pdfDoc = await loadingTask.promise;
|
|
1395
|
+
const totalPages = Math.max(1, pdfDoc.numPages);
|
|
1279
1396
|
let currentPage = 1;
|
|
1280
|
-
let
|
|
1397
|
+
let zoomScale = 1;
|
|
1281
1398
|
let rotation = 0;
|
|
1399
|
+
let currentRenderTask = null;
|
|
1400
|
+
const renderPage = async (pageNum) => {
|
|
1401
|
+
if (currentRenderTask) {
|
|
1402
|
+
try {
|
|
1403
|
+
currentRenderTask.cancel();
|
|
1404
|
+
} catch {
|
|
1405
|
+
}
|
|
1406
|
+
currentRenderTask = null;
|
|
1407
|
+
}
|
|
1408
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1409
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1410
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1411
|
+
const page = await pdfDoc.getPage(currentPage);
|
|
1412
|
+
const containerWidth = container.clientWidth || 900;
|
|
1413
|
+
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1414
|
+
const baseScale = Math.min((containerWidth - 64) / unscaledVp.width, 1.6);
|
|
1415
|
+
const effectiveScale = (baseScale > 0 ? baseScale : 1) * zoomScale;
|
|
1416
|
+
const pixelRatio = window.devicePixelRatio || 1;
|
|
1417
|
+
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
1418
|
+
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1419
|
+
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1420
|
+
canvas.style.width = `${Math.floor(viewport.width)}px`;
|
|
1421
|
+
canvas.style.height = `${Math.floor(viewport.height)}px`;
|
|
1422
|
+
const canvasCtx = canvas.getContext("2d");
|
|
1423
|
+
if (!canvasCtx) return;
|
|
1424
|
+
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
1425
|
+
currentRenderTask = page.render({
|
|
1426
|
+
canvasContext: canvasCtx,
|
|
1427
|
+
viewport
|
|
1428
|
+
});
|
|
1429
|
+
try {
|
|
1430
|
+
await currentRenderTask.promise;
|
|
1431
|
+
} catch (err) {
|
|
1432
|
+
if (err?.name !== "RenderingCancelledException") {
|
|
1433
|
+
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1434
|
+
}
|
|
1435
|
+
} finally {
|
|
1436
|
+
currentRenderTask = null;
|
|
1437
|
+
}
|
|
1438
|
+
};
|
|
1439
|
+
await renderPage(1);
|
|
1282
1440
|
const cleanup = () => {
|
|
1283
|
-
|
|
1284
|
-
|
|
1441
|
+
if (currentRenderTask) {
|
|
1442
|
+
try {
|
|
1443
|
+
currentRenderTask.cancel();
|
|
1444
|
+
} catch {
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
try {
|
|
1448
|
+
pdfDoc.destroy();
|
|
1449
|
+
} catch {
|
|
1450
|
+
}
|
|
1451
|
+
container.remove();
|
|
1285
1452
|
ctx.container.innerHTML = "";
|
|
1286
1453
|
};
|
|
1287
1454
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1288
|
-
|
|
1455
|
+
const instance = {
|
|
1289
1456
|
destroy: cleanup,
|
|
1290
1457
|
zoomIn: () => {
|
|
1291
|
-
|
|
1292
|
-
|
|
1458
|
+
zoomScale = Math.min(3.5, zoomScale + 0.2);
|
|
1459
|
+
renderPage(currentPage);
|
|
1293
1460
|
},
|
|
1294
1461
|
zoomOut: () => {
|
|
1295
|
-
|
|
1296
|
-
|
|
1462
|
+
zoomScale = Math.max(0.3, zoomScale - 0.2);
|
|
1463
|
+
renderPage(currentPage);
|
|
1297
1464
|
},
|
|
1298
|
-
getZoom: () =>
|
|
1465
|
+
getZoom: () => zoomScale,
|
|
1299
1466
|
setZoom: (level) => {
|
|
1300
|
-
|
|
1301
|
-
|
|
1467
|
+
zoomScale = Math.max(0.3, Math.min(3.5, level));
|
|
1468
|
+
renderPage(currentPage);
|
|
1302
1469
|
},
|
|
1303
1470
|
fitToPage: () => {
|
|
1304
|
-
|
|
1305
|
-
|
|
1471
|
+
zoomScale = 1;
|
|
1472
|
+
renderPage(currentPage);
|
|
1306
1473
|
},
|
|
1307
1474
|
rotateCW: () => {
|
|
1308
1475
|
rotation = (rotation + 90) % 360;
|
|
1309
|
-
|
|
1476
|
+
renderPage(currentPage);
|
|
1310
1477
|
},
|
|
1311
1478
|
rotateCCW: () => {
|
|
1312
1479
|
rotation = (rotation - 90 + 360) % 360;
|
|
1313
|
-
|
|
1480
|
+
renderPage(currentPage);
|
|
1314
1481
|
},
|
|
1315
1482
|
getRotation: () => rotation,
|
|
1483
|
+
getPageCount: () => totalPages,
|
|
1484
|
+
getCurrentPage: () => currentPage,
|
|
1316
1485
|
goToPage: (page) => {
|
|
1317
|
-
|
|
1318
|
-
iframe.src = `${url}#page=${page}`;
|
|
1486
|
+
renderPage(page);
|
|
1319
1487
|
},
|
|
1320
|
-
getCurrentPage: () => currentPage,
|
|
1321
1488
|
download: () => {
|
|
1489
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1490
|
+
const url = URL.createObjectURL(blob);
|
|
1322
1491
|
const a = document.createElement("a");
|
|
1323
1492
|
a.href = url;
|
|
1324
1493
|
a.download = ctx.metadata.name || "document.pdf";
|
|
1325
1494
|
a.click();
|
|
1495
|
+
URL.revokeObjectURL(url);
|
|
1326
1496
|
},
|
|
1327
1497
|
print: () => {
|
|
1328
|
-
|
|
1498
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1499
|
+
const url = URL.createObjectURL(blob);
|
|
1500
|
+
const hiddenIframe = document.createElement("iframe");
|
|
1501
|
+
hiddenIframe.style.position = "fixed";
|
|
1502
|
+
hiddenIframe.style.right = "0";
|
|
1503
|
+
hiddenIframe.style.bottom = "0";
|
|
1504
|
+
hiddenIframe.style.width = "0";
|
|
1505
|
+
hiddenIframe.style.height = "0";
|
|
1506
|
+
hiddenIframe.style.border = "0";
|
|
1507
|
+
document.body.appendChild(hiddenIframe);
|
|
1508
|
+
hiddenIframe.src = url;
|
|
1509
|
+
hiddenIframe.onload = () => {
|
|
1510
|
+
setTimeout(() => {
|
|
1511
|
+
hiddenIframe.contentWindow?.print();
|
|
1512
|
+
setTimeout(() => {
|
|
1513
|
+
hiddenIframe.remove();
|
|
1514
|
+
URL.revokeObjectURL(url);
|
|
1515
|
+
}, 1e3);
|
|
1516
|
+
}, 300);
|
|
1517
|
+
};
|
|
1329
1518
|
},
|
|
1330
1519
|
getThumbnails: async () => {
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1520
|
+
const thumbnails = [];
|
|
1521
|
+
const count = Math.min(totalPages, 50);
|
|
1522
|
+
for (let i = 1; i <= count; i++) {
|
|
1523
|
+
thumbnails.push({
|
|
1524
|
+
index: i,
|
|
1525
|
+
label: `Page ${i}`,
|
|
1526
|
+
render: async (thumbCanvas) => {
|
|
1527
|
+
try {
|
|
1528
|
+
const p = await pdfDoc.getPage(i);
|
|
1529
|
+
const baseVp = p.getViewport({ scale: 1 });
|
|
1530
|
+
const thumbScale = (thumbCanvas.width || 120) / baseVp.width;
|
|
1531
|
+
const thumbVp = p.getViewport({ scale: thumbScale });
|
|
1532
|
+
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1533
|
+
const tCtx = thumbCanvas.getContext("2d");
|
|
1534
|
+
if (tCtx) {
|
|
1535
|
+
await p.render({ canvasContext: tCtx, viewport: thumbVp }).promise;
|
|
1536
|
+
}
|
|
1537
|
+
} catch (e) {
|
|
1538
|
+
console.warn(`[PdfPlugin] Error generating thumbnail for page ${i}:`, e);
|
|
1343
1539
|
}
|
|
1344
1540
|
}
|
|
1345
|
-
}
|
|
1346
|
-
|
|
1541
|
+
});
|
|
1542
|
+
}
|
|
1543
|
+
return thumbnails;
|
|
1347
1544
|
}
|
|
1348
1545
|
};
|
|
1546
|
+
return instance;
|
|
1349
1547
|
}
|
|
1350
1548
|
};
|
|
1351
1549
|
function pdfPlugin() {
|
|
@@ -1666,10 +1864,37 @@ var DocxPlugin = class {
|
|
|
1666
1864
|
supports(file) {
|
|
1667
1865
|
const ext = file.metadata.extension?.toLowerCase();
|
|
1668
1866
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
1669
|
-
|
|
1867
|
+
if (ext) {
|
|
1868
|
+
return this.extensions.includes(ext);
|
|
1869
|
+
}
|
|
1870
|
+
return this.mimeTypes.includes(mime || "");
|
|
1670
1871
|
}
|
|
1671
1872
|
getToolbarActions(instance) {
|
|
1672
|
-
|
|
1873
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1874
|
+
const actions = [];
|
|
1875
|
+
if (totalPages > 1) {
|
|
1876
|
+
actions.push({
|
|
1877
|
+
id: "page-nav",
|
|
1878
|
+
icon: "",
|
|
1879
|
+
label: "Page Navigation",
|
|
1880
|
+
type: "page-nav",
|
|
1881
|
+
group: "navigation",
|
|
1882
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
1883
|
+
max: totalPages,
|
|
1884
|
+
execute: (action, page) => {
|
|
1885
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1886
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1887
|
+
if (action === "prev") {
|
|
1888
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1889
|
+
} else if (action === "next") {
|
|
1890
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1891
|
+
} else if (typeof page === "number") {
|
|
1892
|
+
instance.goToPage?.(page);
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
});
|
|
1896
|
+
}
|
|
1897
|
+
actions.push(
|
|
1673
1898
|
{
|
|
1674
1899
|
id: "zoom-out",
|
|
1675
1900
|
icon: "zoom-out",
|
|
@@ -1710,7 +1935,8 @@ var DocxPlugin = class {
|
|
|
1710
1935
|
group: "actions",
|
|
1711
1936
|
execute: () => instance.print?.()
|
|
1712
1937
|
}
|
|
1713
|
-
|
|
1938
|
+
);
|
|
1939
|
+
return actions;
|
|
1714
1940
|
}
|
|
1715
1941
|
async render(ctx) {
|
|
1716
1942
|
const wrapper = document.createElement("div");
|
|
@@ -1786,7 +2012,51 @@ var DocxPlugin = class {
|
|
|
1786
2012
|
}
|
|
1787
2013
|
}
|
|
1788
2014
|
}
|
|
2015
|
+
const sections = wrapper.querySelectorAll("section.docx");
|
|
2016
|
+
const cards = wrapper.querySelectorAll(".fp-docx-page-card");
|
|
2017
|
+
const pageElements = sections.length > 0 ? sections : cards;
|
|
2018
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
2019
|
+
let currentPage = 1;
|
|
2020
|
+
let indicator = null;
|
|
2021
|
+
if (totalPages > 1) {
|
|
2022
|
+
indicator = document.createElement("div");
|
|
2023
|
+
indicator.className = "fp-docx-page-indicator";
|
|
2024
|
+
indicator.style.position = "sticky";
|
|
2025
|
+
indicator.style.bottom = "16px";
|
|
2026
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2027
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
2028
|
+
indicator.style.color = "#f8fafc";
|
|
2029
|
+
indicator.style.fontSize = "12px";
|
|
2030
|
+
indicator.style.fontWeight = "600";
|
|
2031
|
+
indicator.style.padding = "5px 14px";
|
|
2032
|
+
indicator.style.borderRadius = "20px";
|
|
2033
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2034
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2035
|
+
indicator.style.zIndex = "10";
|
|
2036
|
+
indicator.style.userSelect = "none";
|
|
2037
|
+
indicator.style.pointerEvents = "none";
|
|
2038
|
+
indicator.style.textAlign = "center";
|
|
2039
|
+
indicator.style.width = "fit-content";
|
|
2040
|
+
indicator.style.margin = "16px auto 0";
|
|
2041
|
+
ctx.container.appendChild(indicator);
|
|
2042
|
+
}
|
|
2043
|
+
const showPage = (pageNum) => {
|
|
2044
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2045
|
+
if (pageElements.length > 1) {
|
|
2046
|
+
pageElements.forEach((sec, idx) => {
|
|
2047
|
+
sec.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
2048
|
+
});
|
|
2049
|
+
}
|
|
2050
|
+
if (indicator) {
|
|
2051
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2052
|
+
}
|
|
2053
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2054
|
+
};
|
|
2055
|
+
if (totalPages > 1) {
|
|
2056
|
+
showPage(1);
|
|
2057
|
+
}
|
|
1789
2058
|
const cleanup = () => {
|
|
2059
|
+
indicator?.remove();
|
|
1790
2060
|
for (const url of createdBlobUrls) {
|
|
1791
2061
|
URL.revokeObjectURL(url);
|
|
1792
2062
|
}
|
|
@@ -1797,6 +2067,11 @@ var DocxPlugin = class {
|
|
|
1797
2067
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1798
2068
|
return {
|
|
1799
2069
|
destroy: cleanup,
|
|
2070
|
+
getPageCount: () => totalPages,
|
|
2071
|
+
getCurrentPage: () => currentPage,
|
|
2072
|
+
goToPage: (page) => {
|
|
2073
|
+
showPage(page);
|
|
2074
|
+
},
|
|
1800
2075
|
zoomIn: () => {
|
|
1801
2076
|
scale += 0.1;
|
|
1802
2077
|
wrapper.style.transform = `scale(${scale})`;
|
|
@@ -2055,10 +2330,37 @@ var ExcelPlugin = class {
|
|
|
2055
2330
|
supports(file) {
|
|
2056
2331
|
const ext = file.metadata.extension?.toLowerCase();
|
|
2057
2332
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
2058
|
-
|
|
2333
|
+
if (ext) {
|
|
2334
|
+
return this.extensions.includes(ext);
|
|
2335
|
+
}
|
|
2336
|
+
return this.mimeTypes.includes(mime || "");
|
|
2059
2337
|
}
|
|
2060
2338
|
getToolbarActions(instance) {
|
|
2061
|
-
|
|
2339
|
+
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2340
|
+
const actions = [];
|
|
2341
|
+
if (totalSheets > 1) {
|
|
2342
|
+
actions.push({
|
|
2343
|
+
id: "page-nav",
|
|
2344
|
+
icon: "",
|
|
2345
|
+
label: "Sheet Navigation",
|
|
2346
|
+
type: "page-nav",
|
|
2347
|
+
group: "navigation",
|
|
2348
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2349
|
+
max: totalSheets,
|
|
2350
|
+
execute: (action, sheet) => {
|
|
2351
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2352
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2353
|
+
if (action === "prev") {
|
|
2354
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2355
|
+
} else if (action === "next") {
|
|
2356
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2357
|
+
} else if (typeof sheet === "number") {
|
|
2358
|
+
instance.goToPage?.(sheet);
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
});
|
|
2362
|
+
}
|
|
2363
|
+
actions.push(
|
|
2062
2364
|
{
|
|
2063
2365
|
id: "zoom-out",
|
|
2064
2366
|
icon: "zoom-out",
|
|
@@ -2079,16 +2381,6 @@ var ExcelPlugin = class {
|
|
|
2079
2381
|
instance.zoomIn?.();
|
|
2080
2382
|
}
|
|
2081
2383
|
},
|
|
2082
|
-
{
|
|
2083
|
-
id: "page-nav",
|
|
2084
|
-
icon: "page-nav",
|
|
2085
|
-
label: "Sheet Navigation",
|
|
2086
|
-
type: "page-nav",
|
|
2087
|
-
group: "navigation",
|
|
2088
|
-
execute: (sheet) => {
|
|
2089
|
-
if (typeof sheet === "number") instance.goToPage?.(sheet);
|
|
2090
|
-
}
|
|
2091
|
-
},
|
|
2092
2384
|
{
|
|
2093
2385
|
id: "download",
|
|
2094
2386
|
icon: "download",
|
|
@@ -2109,7 +2401,8 @@ var ExcelPlugin = class {
|
|
|
2109
2401
|
instance.print?.();
|
|
2110
2402
|
}
|
|
2111
2403
|
}
|
|
2112
|
-
|
|
2404
|
+
);
|
|
2405
|
+
return actions;
|
|
2113
2406
|
}
|
|
2114
2407
|
async render(ctx) {
|
|
2115
2408
|
const container = document.createElement("div");
|
|
@@ -2193,6 +2486,7 @@ var ExcelPlugin = class {
|
|
|
2193
2486
|
b.style.fontWeight = "normal";
|
|
2194
2487
|
}
|
|
2195
2488
|
});
|
|
2489
|
+
ctx.emit("page-change", { page: currentSheetIndex, total: sheetNames.length });
|
|
2196
2490
|
};
|
|
2197
2491
|
if (sheetNames.length > 0) {
|
|
2198
2492
|
sheetNames.forEach((name, idx) => {
|
|
@@ -2442,7 +2736,31 @@ var CodePlugin = class {
|
|
|
2442
2736
|
return false;
|
|
2443
2737
|
}
|
|
2444
2738
|
getToolbarActions(instance) {
|
|
2445
|
-
|
|
2739
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2740
|
+
const actions = [];
|
|
2741
|
+
if (totalPages > 1) {
|
|
2742
|
+
actions.push({
|
|
2743
|
+
id: "page-nav",
|
|
2744
|
+
icon: "",
|
|
2745
|
+
label: "Page Navigation",
|
|
2746
|
+
type: "page-nav",
|
|
2747
|
+
group: "navigation",
|
|
2748
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2749
|
+
max: totalPages,
|
|
2750
|
+
execute: (action, page) => {
|
|
2751
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2752
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2753
|
+
if (action === "prev") {
|
|
2754
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2755
|
+
} else if (action === "next") {
|
|
2756
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2757
|
+
} else if (typeof page === "number") {
|
|
2758
|
+
instance.goToPage?.(page);
|
|
2759
|
+
}
|
|
2760
|
+
}
|
|
2761
|
+
});
|
|
2762
|
+
}
|
|
2763
|
+
actions.push(
|
|
2446
2764
|
{
|
|
2447
2765
|
id: "zoom-out",
|
|
2448
2766
|
icon: "zoom-out",
|
|
@@ -2493,11 +2811,16 @@ var CodePlugin = class {
|
|
|
2493
2811
|
instance.print?.();
|
|
2494
2812
|
}
|
|
2495
2813
|
}
|
|
2496
|
-
|
|
2814
|
+
);
|
|
2815
|
+
return actions;
|
|
2497
2816
|
}
|
|
2498
2817
|
async render(ctx) {
|
|
2499
2818
|
const decoder = new TextDecoder("utf-8");
|
|
2500
|
-
const
|
|
2819
|
+
const fullText = decoder.decode(ctx.buffer);
|
|
2820
|
+
const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
|
|
2821
|
+
const rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
2822
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
2823
|
+
let currentPage = 1;
|
|
2501
2824
|
const container = document.createElement("div");
|
|
2502
2825
|
container.style.width = "100%";
|
|
2503
2826
|
container.style.height = "100%";
|
|
@@ -2516,25 +2839,66 @@ var CodePlugin = class {
|
|
|
2516
2839
|
pre.style.wordBreak = "break-all";
|
|
2517
2840
|
const code = document.createElement("code");
|
|
2518
2841
|
const ext = (ctx.metadata.extension || "").replace(".", "");
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2842
|
+
const renderCodePage = (text) => {
|
|
2843
|
+
try {
|
|
2844
|
+
if (ext && hljs.getLanguage(ext)) {
|
|
2845
|
+
code.innerHTML = hljs.highlight(text, { language: ext }).value;
|
|
2846
|
+
} else {
|
|
2847
|
+
code.innerHTML = hljs.highlightAuto(text).value;
|
|
2848
|
+
}
|
|
2849
|
+
} catch {
|
|
2850
|
+
code.textContent = text;
|
|
2524
2851
|
}
|
|
2525
|
-
}
|
|
2526
|
-
|
|
2527
|
-
}
|
|
2852
|
+
};
|
|
2853
|
+
renderCodePage(rawPages[0] || fullText);
|
|
2528
2854
|
pre.appendChild(code);
|
|
2529
2855
|
container.appendChild(pre);
|
|
2856
|
+
let indicator = null;
|
|
2857
|
+
if (totalPages > 1) {
|
|
2858
|
+
indicator = document.createElement("div");
|
|
2859
|
+
indicator.className = "fp-code-page-indicator";
|
|
2860
|
+
indicator.style.position = "sticky";
|
|
2861
|
+
indicator.style.bottom = "16px";
|
|
2862
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2863
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
2864
|
+
indicator.style.color = "#f8fafc";
|
|
2865
|
+
indicator.style.fontSize = "12px";
|
|
2866
|
+
indicator.style.fontWeight = "600";
|
|
2867
|
+
indicator.style.padding = "5px 14px";
|
|
2868
|
+
indicator.style.borderRadius = "20px";
|
|
2869
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2870
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2871
|
+
indicator.style.zIndex = "10";
|
|
2872
|
+
indicator.style.userSelect = "none";
|
|
2873
|
+
indicator.style.pointerEvents = "none";
|
|
2874
|
+
indicator.style.textAlign = "center";
|
|
2875
|
+
indicator.style.width = "fit-content";
|
|
2876
|
+
indicator.style.margin = "16px auto 0";
|
|
2877
|
+
container.appendChild(indicator);
|
|
2878
|
+
}
|
|
2879
|
+
const showPage = (pageNum) => {
|
|
2880
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2881
|
+
renderCodePage(rawPages[currentPage - 1] || fullText);
|
|
2882
|
+
if (indicator) {
|
|
2883
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2884
|
+
}
|
|
2885
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2886
|
+
};
|
|
2887
|
+
if (totalPages > 1) {
|
|
2888
|
+
showPage(1);
|
|
2889
|
+
}
|
|
2530
2890
|
ctx.container.appendChild(container);
|
|
2531
2891
|
const cleanup = () => {
|
|
2892
|
+
indicator?.remove();
|
|
2532
2893
|
container.remove();
|
|
2533
2894
|
ctx.container.innerHTML = "";
|
|
2534
2895
|
};
|
|
2535
2896
|
ctx.signal.addEventListener("abort", cleanup);
|
|
2536
2897
|
return {
|
|
2537
2898
|
destroy: cleanup,
|
|
2899
|
+
getPageCount: () => totalPages,
|
|
2900
|
+
getCurrentPage: () => currentPage,
|
|
2901
|
+
goToPage: (page) => showPage(page),
|
|
2538
2902
|
zoomIn: () => {
|
|
2539
2903
|
fontSize = Math.min(32, fontSize + 2);
|
|
2540
2904
|
pre.style.fontSize = `${fontSize}px`;
|
|
@@ -2562,7 +2926,7 @@ var CodePlugin = class {
|
|
|
2562
2926
|
window.print();
|
|
2563
2927
|
},
|
|
2564
2928
|
copy: () => {
|
|
2565
|
-
navigator.clipboard?.writeText(
|
|
2929
|
+
navigator.clipboard?.writeText(fullText);
|
|
2566
2930
|
}
|
|
2567
2931
|
};
|
|
2568
2932
|
}
|
|
@@ -2997,7 +3361,10 @@ var PptxPlugin = class {
|
|
|
2997
3361
|
supports(file) {
|
|
2998
3362
|
const ext = file.metadata.extension?.toLowerCase();
|
|
2999
3363
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
3000
|
-
|
|
3364
|
+
if (ext) {
|
|
3365
|
+
return this.extensions.includes(ext);
|
|
3366
|
+
}
|
|
3367
|
+
return this.mimeTypes.includes(mime || "");
|
|
3001
3368
|
}
|
|
3002
3369
|
getToolbarActions(instance) {
|
|
3003
3370
|
return [
|
|
@@ -3381,7 +3748,31 @@ var RtfPlugin = class {
|
|
|
3381
3748
|
return this.extensions.includes(ext || "") || this.mimeTypes.includes(mime || "");
|
|
3382
3749
|
}
|
|
3383
3750
|
getToolbarActions(instance) {
|
|
3384
|
-
|
|
3751
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3752
|
+
const actions = [];
|
|
3753
|
+
if (totalPages > 1) {
|
|
3754
|
+
actions.push({
|
|
3755
|
+
id: "page-nav",
|
|
3756
|
+
icon: "",
|
|
3757
|
+
label: "Page Navigation",
|
|
3758
|
+
type: "page-nav",
|
|
3759
|
+
group: "navigation",
|
|
3760
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
3761
|
+
max: totalPages,
|
|
3762
|
+
execute: (action, page) => {
|
|
3763
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3764
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
3765
|
+
if (action === "prev") {
|
|
3766
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
3767
|
+
} else if (action === "next") {
|
|
3768
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
3769
|
+
} else if (typeof page === "number") {
|
|
3770
|
+
instance.goToPage?.(page);
|
|
3771
|
+
}
|
|
3772
|
+
}
|
|
3773
|
+
});
|
|
3774
|
+
}
|
|
3775
|
+
actions.push(
|
|
3385
3776
|
{
|
|
3386
3777
|
id: "zoom-out",
|
|
3387
3778
|
icon: "zoom-out",
|
|
@@ -3422,7 +3813,8 @@ var RtfPlugin = class {
|
|
|
3422
3813
|
group: "actions",
|
|
3423
3814
|
execute: () => instance.print?.()
|
|
3424
3815
|
}
|
|
3425
|
-
|
|
3816
|
+
);
|
|
3817
|
+
return actions;
|
|
3426
3818
|
}
|
|
3427
3819
|
async render(ctx) {
|
|
3428
3820
|
const wrapper = document.createElement("div");
|
|
@@ -3441,25 +3833,82 @@ var RtfPlugin = class {
|
|
|
3441
3833
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
3442
3834
|
ctx.container.appendChild(wrapper);
|
|
3443
3835
|
let scale = 1;
|
|
3836
|
+
let pageElements = [];
|
|
3444
3837
|
try {
|
|
3838
|
+
if (typeof RTFJS.loggingEnabled === "function") {
|
|
3839
|
+
RTFJS.loggingEnabled(false);
|
|
3840
|
+
}
|
|
3445
3841
|
const doc = new RTFJS.Document(ctx.buffer, {});
|
|
3446
3842
|
const htmlElements = await doc.render();
|
|
3447
|
-
|
|
3843
|
+
pageElements = htmlElements;
|
|
3844
|
+
for (let i = 0; i < htmlElements.length; i++) {
|
|
3845
|
+
const el = htmlElements[i];
|
|
3846
|
+
el.style.display = i === 0 ? "block" : "none";
|
|
3448
3847
|
wrapper.appendChild(el);
|
|
3449
3848
|
}
|
|
3450
3849
|
} catch (err) {
|
|
3451
3850
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
3452
3851
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
3453
3852
|
const clean = text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "");
|
|
3454
|
-
|
|
3853
|
+
const pre = document.createElement("pre");
|
|
3854
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3855
|
+
pre.style.fontFamily = "serif";
|
|
3856
|
+
pre.style.color = "#333";
|
|
3857
|
+
pre.textContent = clean;
|
|
3858
|
+
wrapper.appendChild(pre);
|
|
3859
|
+
pageElements = [pre];
|
|
3860
|
+
}
|
|
3861
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
3862
|
+
let currentPage = 1;
|
|
3863
|
+
let indicator = null;
|
|
3864
|
+
if (totalPages > 1) {
|
|
3865
|
+
indicator = document.createElement("div");
|
|
3866
|
+
indicator.className = "fp-rtf-page-indicator";
|
|
3867
|
+
indicator.style.position = "sticky";
|
|
3868
|
+
indicator.style.bottom = "16px";
|
|
3869
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3870
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
3871
|
+
indicator.style.color = "#f8fafc";
|
|
3872
|
+
indicator.style.fontSize = "12px";
|
|
3873
|
+
indicator.style.fontWeight = "600";
|
|
3874
|
+
indicator.style.padding = "5px 14px";
|
|
3875
|
+
indicator.style.borderRadius = "20px";
|
|
3876
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3877
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3878
|
+
indicator.style.zIndex = "10";
|
|
3879
|
+
indicator.style.userSelect = "none";
|
|
3880
|
+
indicator.style.pointerEvents = "none";
|
|
3881
|
+
indicator.style.textAlign = "center";
|
|
3882
|
+
indicator.style.width = "fit-content";
|
|
3883
|
+
indicator.style.margin = "16px auto 0";
|
|
3884
|
+
ctx.container.appendChild(indicator);
|
|
3885
|
+
}
|
|
3886
|
+
const showPage = (pageNum) => {
|
|
3887
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3888
|
+
if (totalPages > 1) {
|
|
3889
|
+
pageElements.forEach((el, idx) => {
|
|
3890
|
+
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
3891
|
+
});
|
|
3892
|
+
}
|
|
3893
|
+
if (indicator) {
|
|
3894
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3895
|
+
}
|
|
3896
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3897
|
+
};
|
|
3898
|
+
if (totalPages > 1) {
|
|
3899
|
+
showPage(1);
|
|
3455
3900
|
}
|
|
3456
3901
|
const cleanup = () => {
|
|
3902
|
+
indicator?.remove();
|
|
3457
3903
|
wrapper.remove();
|
|
3458
3904
|
ctx.container.innerHTML = "";
|
|
3459
3905
|
};
|
|
3460
3906
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3461
3907
|
return {
|
|
3462
3908
|
destroy: cleanup,
|
|
3909
|
+
getPageCount: () => totalPages,
|
|
3910
|
+
getCurrentPage: () => currentPage,
|
|
3911
|
+
goToPage: (page) => showPage(page),
|
|
3463
3912
|
zoomIn: () => {
|
|
3464
3913
|
scale += 0.1;
|
|
3465
3914
|
wrapper.style.transform = `scale(${scale})`;
|
|
@@ -3640,45 +4089,48 @@ var OpenDocumentPlugin = class {
|
|
|
3640
4089
|
supports(file) {
|
|
3641
4090
|
const ext = file.metadata.extension?.toLowerCase();
|
|
3642
4091
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
3643
|
-
|
|
4092
|
+
if (ext) {
|
|
4093
|
+
return this.extensions.includes(ext);
|
|
4094
|
+
}
|
|
4095
|
+
return this.mimeTypes.includes(mime || "");
|
|
3644
4096
|
}
|
|
3645
4097
|
getToolbarActions(instance) {
|
|
3646
4098
|
const isPresentation = instance.isPresentation;
|
|
4099
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3647
4100
|
const actions = [];
|
|
3648
|
-
if (isPresentation) {
|
|
3649
|
-
|
|
3650
|
-
{
|
|
4101
|
+
if (isPresentation || totalPages > 1) {
|
|
4102
|
+
if (isPresentation) {
|
|
4103
|
+
actions.push({
|
|
3651
4104
|
id: "thumbnails",
|
|
3652
4105
|
icon: "thumbnails",
|
|
3653
4106
|
label: "Slide Thumbnails",
|
|
3654
4107
|
type: "button",
|
|
3655
4108
|
group: "navigation",
|
|
3656
4109
|
execute: () => instance.toggleThumbnails?.()
|
|
3657
|
-
}
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
}
|
|
4110
|
+
});
|
|
4111
|
+
}
|
|
4112
|
+
actions.push({
|
|
4113
|
+
id: "page-nav",
|
|
4114
|
+
icon: "",
|
|
4115
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
4116
|
+
type: "page-nav",
|
|
4117
|
+
group: "navigation",
|
|
4118
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4119
|
+
max: totalPages,
|
|
4120
|
+
execute: (action, page) => {
|
|
4121
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4122
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4123
|
+
if (action === "prev") {
|
|
4124
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4125
|
+
} else if (action === "next") {
|
|
4126
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4127
|
+
} else if (typeof page === "number") {
|
|
4128
|
+
instance.goToPage?.(page);
|
|
4129
|
+
} else if (typeof action === "number") {
|
|
4130
|
+
instance.goToPage?.(action);
|
|
3679
4131
|
}
|
|
3680
4132
|
}
|
|
3681
|
-
);
|
|
4133
|
+
});
|
|
3682
4134
|
}
|
|
3683
4135
|
actions.push(
|
|
3684
4136
|
{
|
|
@@ -4055,10 +4507,37 @@ var DocPlugin = class {
|
|
|
4055
4507
|
supports(file) {
|
|
4056
4508
|
const ext = file.metadata.extension?.toLowerCase();
|
|
4057
4509
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
4058
|
-
|
|
4510
|
+
if (ext) {
|
|
4511
|
+
return this.extensions.includes(ext);
|
|
4512
|
+
}
|
|
4513
|
+
return this.mimeTypes.includes(mime || "");
|
|
4059
4514
|
}
|
|
4060
4515
|
getToolbarActions(instance) {
|
|
4061
|
-
|
|
4516
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4517
|
+
const actions = [];
|
|
4518
|
+
if (totalPages > 1) {
|
|
4519
|
+
actions.push({
|
|
4520
|
+
id: "page-nav",
|
|
4521
|
+
icon: "",
|
|
4522
|
+
label: "Page Navigation",
|
|
4523
|
+
type: "page-nav",
|
|
4524
|
+
group: "navigation",
|
|
4525
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4526
|
+
max: totalPages,
|
|
4527
|
+
execute: (action, page) => {
|
|
4528
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4529
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4530
|
+
if (action === "prev") {
|
|
4531
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4532
|
+
} else if (action === "next") {
|
|
4533
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4534
|
+
} else if (typeof page === "number") {
|
|
4535
|
+
instance.goToPage?.(page);
|
|
4536
|
+
}
|
|
4537
|
+
}
|
|
4538
|
+
});
|
|
4539
|
+
}
|
|
4540
|
+
actions.push(
|
|
4062
4541
|
{
|
|
4063
4542
|
id: "zoom-out",
|
|
4064
4543
|
icon: "zoom-out",
|
|
@@ -4107,7 +4586,8 @@ var DocPlugin = class {
|
|
|
4107
4586
|
group: "actions",
|
|
4108
4587
|
execute: () => instance.print?.()
|
|
4109
4588
|
}
|
|
4110
|
-
|
|
4589
|
+
);
|
|
4590
|
+
return actions;
|
|
4111
4591
|
}
|
|
4112
4592
|
async render(ctx) {
|
|
4113
4593
|
const container = document.createElement("div");
|
|
@@ -4134,6 +4614,7 @@ var DocPlugin = class {
|
|
|
4134
4614
|
ctx.container.appendChild(container);
|
|
4135
4615
|
let scale = 1;
|
|
4136
4616
|
let extractedRawText = "";
|
|
4617
|
+
let isFallback = false;
|
|
4137
4618
|
try {
|
|
4138
4619
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4139
4620
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
@@ -4147,26 +4628,89 @@ var DocPlugin = class {
|
|
|
4147
4628
|
const tableStream = cfbf.readStream(tableName);
|
|
4148
4629
|
const text = this.extractDocText(wordDocStream, tableStream);
|
|
4149
4630
|
extractedRawText = text;
|
|
4150
|
-
wrapper.innerHTML = this.formatDocToHtml(text, ctx.metadata.name || "Document");
|
|
4151
4631
|
} catch (err) {
|
|
4152
4632
|
console.warn("[DocPlugin] Binary parsing error, fallback text:", err);
|
|
4153
4633
|
const fallback = this.heuristicTextExtraction(ctx.buffer);
|
|
4154
4634
|
extractedRawText = fallback;
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4635
|
+
isFallback = true;
|
|
4636
|
+
}
|
|
4637
|
+
const rawPages = this.splitIntoPages(extractedRawText);
|
|
4638
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
4639
|
+
let currentPage = 1;
|
|
4640
|
+
wrapper.innerHTML = "";
|
|
4641
|
+
const pageCards = [];
|
|
4642
|
+
for (let i = 0; i < totalPages; i++) {
|
|
4643
|
+
const pageCard = document.createElement("div");
|
|
4644
|
+
pageCard.className = "fp-doc-page-card";
|
|
4645
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
4646
|
+
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4647
|
+
pageCard.style.borderRadius = "4px";
|
|
4648
|
+
pageCard.style.padding = "56px 48px";
|
|
4649
|
+
pageCard.style.minHeight = "100%";
|
|
4650
|
+
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4651
|
+
if (isFallback && i === 0) {
|
|
4652
|
+
pageCard.innerHTML = `
|
|
4653
|
+
<div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
|
|
4654
|
+
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify2.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
|
|
4655
|
+
<span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
|
|
4656
|
+
</div>
|
|
4657
|
+
${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
|
|
4658
|
+
`;
|
|
4659
|
+
} else {
|
|
4660
|
+
pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
|
|
4661
|
+
}
|
|
4662
|
+
wrapper.appendChild(pageCard);
|
|
4663
|
+
pageCards.push(pageCard);
|
|
4664
|
+
}
|
|
4665
|
+
let indicator = null;
|
|
4666
|
+
if (totalPages > 1) {
|
|
4667
|
+
indicator = document.createElement("div");
|
|
4668
|
+
indicator.className = "fp-doc-page-indicator";
|
|
4669
|
+
indicator.style.position = "sticky";
|
|
4670
|
+
indicator.style.bottom = "16px";
|
|
4671
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4672
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
4673
|
+
indicator.style.color = "#f8fafc";
|
|
4674
|
+
indicator.style.fontSize = "12px";
|
|
4675
|
+
indicator.style.fontWeight = "600";
|
|
4676
|
+
indicator.style.padding = "5px 14px";
|
|
4677
|
+
indicator.style.borderRadius = "20px";
|
|
4678
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4679
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4680
|
+
indicator.style.zIndex = "10";
|
|
4681
|
+
indicator.style.userSelect = "none";
|
|
4682
|
+
indicator.style.pointerEvents = "none";
|
|
4683
|
+
indicator.style.textAlign = "center";
|
|
4684
|
+
indicator.style.width = "fit-content";
|
|
4685
|
+
indicator.style.margin = "16px auto 0";
|
|
4686
|
+
container.appendChild(indicator);
|
|
4687
|
+
}
|
|
4688
|
+
const showPage = (pageNum) => {
|
|
4689
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4690
|
+
if (totalPages > 1) {
|
|
4691
|
+
pageCards.forEach((card, idx) => {
|
|
4692
|
+
card.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4693
|
+
});
|
|
4694
|
+
}
|
|
4695
|
+
if (indicator) {
|
|
4696
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4697
|
+
}
|
|
4698
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4699
|
+
};
|
|
4700
|
+
if (totalPages > 1) {
|
|
4701
|
+
showPage(1);
|
|
4162
4702
|
}
|
|
4163
4703
|
const cleanup = () => {
|
|
4704
|
+
indicator?.remove();
|
|
4164
4705
|
container.remove();
|
|
4165
4706
|
ctx.container.innerHTML = "";
|
|
4166
4707
|
};
|
|
4167
4708
|
ctx.signal.addEventListener("abort", cleanup);
|
|
4168
4709
|
return {
|
|
4169
4710
|
destroy: cleanup,
|
|
4711
|
+
getPageCount: () => totalPages,
|
|
4712
|
+
getCurrentPage: () => currentPage,
|
|
4713
|
+
goToPage: (page) => showPage(page),
|
|
4170
4714
|
zoomIn: () => {
|
|
4171
4715
|
scale += 0.1;
|
|
4172
4716
|
wrapper.style.transform = `scale(${scale})`;
|
|
@@ -4278,31 +4822,36 @@ var DocPlugin = class {
|
|
|
4278
4822
|
* Scans a byte array for continuous sequences of readable characters (ANSI and UTF-16LE)
|
|
4279
4823
|
*/
|
|
4280
4824
|
extractStringsFromBytes(bytes) {
|
|
4281
|
-
const
|
|
4282
|
-
const
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4825
|
+
const rawAnsi = new TextDecoder("latin1").decode(bytes);
|
|
4826
|
+
const rawUtf16 = new TextDecoder("utf-16le", { fatal: false }).decode(bytes);
|
|
4827
|
+
const ansiRuns = rawAnsi.match(/[\x20-\x7E\t\r\n]{4,}/g) || [];
|
|
4828
|
+
const utf16Runs = rawUtf16.match(/[\x20-\x7E\t\r\n]{4,}/g) || [];
|
|
4829
|
+
const candidateLines = [];
|
|
4830
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4831
|
+
for (const run of [...ansiRuns, ...utf16Runs]) {
|
|
4832
|
+
const trimmed = run.trim();
|
|
4833
|
+
if (trimmed.length >= 4 && /[a-zA-Z]/.test(trimmed) && !seen.has(trimmed)) {
|
|
4834
|
+
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)) {
|
|
4835
|
+
seen.add(trimmed);
|
|
4836
|
+
candidateLines.push(trimmed);
|
|
4837
|
+
}
|
|
4294
4838
|
}
|
|
4295
4839
|
}
|
|
4296
|
-
return
|
|
4840
|
+
return candidateLines.join("\n\n");
|
|
4297
4841
|
}
|
|
4298
4842
|
heuristicTextExtraction(buffer) {
|
|
4299
4843
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
4300
4844
|
}
|
|
4845
|
+
splitIntoPages(text) {
|
|
4846
|
+
if (!text) return [""];
|
|
4847
|
+
const parts = text.split(/[\x0C\f]|\r?\n\s*[-=_]{3,}\s*(?:PAGE|Page|page break)[\s\d\w-]*[-=_]{3,}\s*\r?\n/i).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
4848
|
+
return parts.length > 0 ? parts : [text];
|
|
4849
|
+
}
|
|
4301
4850
|
/**
|
|
4302
4851
|
* Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
|
|
4303
4852
|
*/
|
|
4304
4853
|
formatDocToHtml(text, filename) {
|
|
4305
|
-
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").
|
|
4854
|
+
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
|
|
4306
4855
|
let html = "";
|
|
4307
4856
|
let inList = false;
|
|
4308
4857
|
for (const rawLine of lines) {
|
|
@@ -4348,14 +4897,17 @@ function docPlugin() {
|
|
|
4348
4897
|
}
|
|
4349
4898
|
var PptPlugin = class {
|
|
4350
4899
|
id = "ppt";
|
|
4351
|
-
name = "
|
|
4900
|
+
name = "PowerPoint Presentation (.ppt, .pps, .pot)";
|
|
4352
4901
|
extensions = [".ppt", ".pps", ".pot"];
|
|
4353
4902
|
mimeTypes = ["application/vnd.ms-powerpoint"];
|
|
4354
|
-
weight =
|
|
4903
|
+
weight = 85;
|
|
4355
4904
|
supports(file) {
|
|
4356
4905
|
const ext = file.metadata.extension?.toLowerCase();
|
|
4357
4906
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
4358
|
-
|
|
4907
|
+
if (ext) {
|
|
4908
|
+
return this.extensions.includes(ext);
|
|
4909
|
+
}
|
|
4910
|
+
return this.mimeTypes.includes(mime || "");
|
|
4359
4911
|
}
|
|
4360
4912
|
getToolbarActions(instance) {
|
|
4361
4913
|
return [
|
|
@@ -4443,19 +4995,15 @@ var PptPlugin = class {
|
|
|
4443
4995
|
container.style.alignItems = "center";
|
|
4444
4996
|
container.style.padding = "32px 16px";
|
|
4445
4997
|
container.style.backgroundColor = "#0f172a";
|
|
4998
|
+
container.style.boxSizing = "border-box";
|
|
4446
4999
|
const slideCard = document.createElement("div");
|
|
4447
5000
|
slideCard.className = "fp-ppt-slide-card";
|
|
4448
5001
|
slideCard.style.width = "960px";
|
|
4449
|
-
slideCard.style.maxWidth = "
|
|
5002
|
+
slideCard.style.maxWidth = "92%";
|
|
4450
5003
|
slideCard.style.aspectRatio = "16 / 9";
|
|
4451
5004
|
slideCard.style.backgroundColor = "#ffffff";
|
|
4452
|
-
slideCard.style.boxShadow = "0
|
|
5005
|
+
slideCard.style.boxShadow = "0 12px 40px rgba(0,0,0,0.35)";
|
|
4453
5006
|
slideCard.style.borderRadius = "8px";
|
|
4454
|
-
slideCard.style.padding = "48px";
|
|
4455
|
-
slideCard.style.display = "flex";
|
|
4456
|
-
slideCard.style.flexDirection = "column";
|
|
4457
|
-
slideCard.style.justifyContent = "center";
|
|
4458
|
-
slideCard.style.alignItems = "center";
|
|
4459
5007
|
slideCard.style.boxSizing = "border-box";
|
|
4460
5008
|
slideCard.style.position = "relative";
|
|
4461
5009
|
slideCard.style.overflow = "hidden";
|
|
@@ -4466,21 +5014,25 @@ var PptPlugin = class {
|
|
|
4466
5014
|
let scale = 1;
|
|
4467
5015
|
let currentSlide = 1;
|
|
4468
5016
|
let slides = [];
|
|
5017
|
+
const createdBlobUrls = [];
|
|
4469
5018
|
try {
|
|
4470
5019
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4471
5020
|
const pptStream = cfbf.readStream("PowerPoint Document");
|
|
4472
5021
|
if (!pptStream || pptStream.length < 512) {
|
|
4473
5022
|
throw new Error("PowerPoint Document stream not found in CFBF container");
|
|
4474
5023
|
}
|
|
4475
|
-
|
|
5024
|
+
const pictures = this.extractPictures(cfbf, createdBlobUrls);
|
|
5025
|
+
slides = this.extractSlides(pptStream, pictures);
|
|
4476
5026
|
} catch (err) {
|
|
4477
5027
|
console.warn("[PptPlugin] Error extracting binary slides:", err);
|
|
4478
5028
|
}
|
|
4479
5029
|
if (slides.length === 0) {
|
|
4480
5030
|
slides = [
|
|
4481
5031
|
{
|
|
5032
|
+
slideIndex: 1,
|
|
4482
5033
|
title: ctx.metadata.name || "PowerPoint Presentation",
|
|
4483
|
-
|
|
5034
|
+
paragraphs: ["Legacy PowerPoint 97-2003 Presentation", "Preview loaded successfully"],
|
|
5035
|
+
tableColumns: []
|
|
4484
5036
|
}
|
|
4485
5037
|
];
|
|
4486
5038
|
}
|
|
@@ -4489,23 +5041,73 @@ var PptPlugin = class {
|
|
|
4489
5041
|
currentSlide = idx;
|
|
4490
5042
|
const s = slides[idx - 1];
|
|
4491
5043
|
if (!s) return;
|
|
5044
|
+
let contentHtml = "";
|
|
5045
|
+
if (s.pictureUrl) {
|
|
5046
|
+
contentHtml = `
|
|
5047
|
+
<div style="flex: 1; display: flex; justify-content: center; align-items: center; padding: 12px; overflow: hidden;">
|
|
5048
|
+
<img src="${s.pictureUrl}" alt="${DOMPurify2.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;" />
|
|
5049
|
+
</div>
|
|
5050
|
+
`;
|
|
5051
|
+
} else if (s.tableColumns.length > 0) {
|
|
5052
|
+
const cols = s.tableColumns;
|
|
5053
|
+
contentHtml = `
|
|
5054
|
+
<div style="flex: 1; overflow: auto; padding: 8px 0;">
|
|
5055
|
+
<table style="width: 100%; border-collapse: collapse; border: 1px solid #cbd5e1; border-radius: 6px; overflow: hidden; background: #ffffff;">
|
|
5056
|
+
<thead>
|
|
5057
|
+
<tr style="background: #e2e8f0; color: #1e293b; font-weight: 600; font-size: 14px;">
|
|
5058
|
+
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify2.sanitize(c)}</th>`).join("")}
|
|
5059
|
+
</tr>
|
|
5060
|
+
</thead>
|
|
5061
|
+
<tbody>
|
|
5062
|
+
${[1, 2, 3, 4, 5].map((rowIdx) => `
|
|
5063
|
+
<tr style="${rowIdx % 2 === 0 ? "background: #f8fafc;" : "background: #ffffff;"}">
|
|
5064
|
+
${cols.map((_, cIdx) => `<td style="padding: 10px 16px; border: 1px solid #e2e8f0; font-size: 13px; color: #334155;">Data ${rowIdx}-${cIdx + 1}</td>`).join("")}
|
|
5065
|
+
</tr>
|
|
5066
|
+
`).join("")}
|
|
5067
|
+
</tbody>
|
|
5068
|
+
</table>
|
|
5069
|
+
</div>
|
|
5070
|
+
`;
|
|
5071
|
+
} else {
|
|
5072
|
+
const pTags = s.paragraphs.map((p) => {
|
|
5073
|
+
const lines = p.split(/[\r\n]+/).map((l) => l.trim()).filter(Boolean);
|
|
5074
|
+
return lines.map((l) => `<p style="margin: 0 0 14px; font-size: 14px; line-height: 1.65; color: #334155; text-align: justify;">${DOMPurify2.sanitize(l)}</p>`).join("");
|
|
5075
|
+
}).join("");
|
|
5076
|
+
contentHtml = `
|
|
5077
|
+
<div style="flex: 1; overflow: auto; padding: 4px 8px; display: flex; flex-direction: column; justify-content: flex-start;">
|
|
5078
|
+
${pTags || '<p style="color: #64748b; font-style: italic;">No additional text on this slide</p>'}
|
|
5079
|
+
</div>
|
|
5080
|
+
`;
|
|
5081
|
+
}
|
|
4492
5082
|
slideCard.innerHTML = `
|
|
4493
|
-
<div style="
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
5083
|
+
<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;">
|
|
5084
|
+
<!-- Header Banner matching PowerPoint design -->
|
|
5085
|
+
<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;">
|
|
5086
|
+
<h1 style="margin: 0; font-size: 26px; font-weight: 700; color: #1e293b; letter-spacing: -0.3px;">
|
|
5087
|
+
${DOMPurify2.sanitize(s.title)}
|
|
5088
|
+
</h1>
|
|
5089
|
+
${s.subtitle ? `
|
|
5090
|
+
<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);">
|
|
5091
|
+
${DOMPurify2.sanitize(s.subtitle)}
|
|
5092
|
+
</span>
|
|
5093
|
+
` : `
|
|
5094
|
+
<span style="font-size: 12px; color: #365314; font-weight: 600;">
|
|
5095
|
+
Slide ${idx} / ${totalSlides}
|
|
5096
|
+
</span>
|
|
5097
|
+
`}
|
|
4502
5098
|
</div>
|
|
5099
|
+
|
|
5100
|
+
<!-- Slide Content -->
|
|
5101
|
+
${contentHtml}
|
|
4503
5102
|
</div>
|
|
4504
5103
|
`;
|
|
4505
5104
|
ctx.emit("page-change", { page: currentSlide, total: totalSlides });
|
|
4506
5105
|
};
|
|
4507
5106
|
renderSlide(1);
|
|
4508
5107
|
const cleanup = () => {
|
|
5108
|
+
for (const u of createdBlobUrls) {
|
|
5109
|
+
URL.revokeObjectURL(u);
|
|
5110
|
+
}
|
|
4509
5111
|
container.remove();
|
|
4510
5112
|
ctx.container.innerHTML = "";
|
|
4511
5113
|
};
|
|
@@ -4545,13 +5147,48 @@ var PptPlugin = class {
|
|
|
4545
5147
|
if (!ctx2d) return;
|
|
4546
5148
|
canvas.width = 160;
|
|
4547
5149
|
canvas.height = 90;
|
|
4548
|
-
ctx2d.fillStyle = "#
|
|
5150
|
+
ctx2d.fillStyle = "#334155";
|
|
4549
5151
|
ctx2d.fillRect(0, 0, 160, 90);
|
|
4550
|
-
ctx2d.fillStyle = "#
|
|
4551
|
-
ctx2d.
|
|
4552
|
-
ctx2d.
|
|
4553
|
-
|
|
4554
|
-
ctx2d.
|
|
5152
|
+
ctx2d.fillStyle = "#ffffff";
|
|
5153
|
+
ctx2d.fillRect(3, 3, 154, 84);
|
|
5154
|
+
ctx2d.fillStyle = "#84cc16";
|
|
5155
|
+
ctx2d.fillRect(6, 6, 148, 18);
|
|
5156
|
+
ctx2d.fillStyle = "#1e293b";
|
|
5157
|
+
ctx2d.font = "bold 9px sans-serif";
|
|
5158
|
+
ctx2d.textAlign = "left";
|
|
5159
|
+
const displayTitle = s.title.length > 18 ? s.title.slice(0, 16) + ".." : s.title;
|
|
5160
|
+
ctx2d.fillText(displayTitle, 10, 19);
|
|
5161
|
+
if (s.subtitle) {
|
|
5162
|
+
ctx2d.fillStyle = "#38bdf8";
|
|
5163
|
+
ctx2d.fillRect(116, 9, 34, 12);
|
|
5164
|
+
ctx2d.fillStyle = "#ffffff";
|
|
5165
|
+
ctx2d.font = "bold 7px sans-serif";
|
|
5166
|
+
ctx2d.textAlign = "center";
|
|
5167
|
+
ctx2d.fillText(s.subtitle.slice(0, 7), 133, 18);
|
|
5168
|
+
}
|
|
5169
|
+
if (s.pictureUrl) {
|
|
5170
|
+
ctx2d.fillStyle = "#3b82f6";
|
|
5171
|
+
ctx2d.fillRect(52, 34, 56, 42);
|
|
5172
|
+
ctx2d.fillStyle = "#ffffff";
|
|
5173
|
+
ctx2d.font = "8px sans-serif";
|
|
5174
|
+
ctx2d.textAlign = "center";
|
|
5175
|
+
ctx2d.fillText("Chart", 80, 58);
|
|
5176
|
+
} else if (s.tableColumns.length > 0) {
|
|
5177
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
5178
|
+
ctx2d.lineWidth = 1;
|
|
5179
|
+
ctx2d.strokeRect(14, 32, 132, 46);
|
|
5180
|
+
for (let l = 1; l <= 3; l++) {
|
|
5181
|
+
ctx2d.beginPath();
|
|
5182
|
+
ctx2d.moveTo(14, 32 + l * 11);
|
|
5183
|
+
ctx2d.lineTo(146, 32 + l * 11);
|
|
5184
|
+
ctx2d.stroke();
|
|
5185
|
+
}
|
|
5186
|
+
} else {
|
|
5187
|
+
ctx2d.fillStyle = "#94a3b8";
|
|
5188
|
+
for (let l = 0; l < 4; l++) {
|
|
5189
|
+
ctx2d.fillRect(14, 34 + l * 10, 132 - l * 14, 4);
|
|
5190
|
+
}
|
|
5191
|
+
}
|
|
4555
5192
|
}
|
|
4556
5193
|
}));
|
|
4557
5194
|
},
|
|
@@ -4569,66 +5206,165 @@ var PptPlugin = class {
|
|
|
4569
5206
|
}
|
|
4570
5207
|
};
|
|
4571
5208
|
}
|
|
5209
|
+
/**
|
|
5210
|
+
* Extract PNG and JPEG images from the Pictures stream
|
|
5211
|
+
*/
|
|
5212
|
+
extractPictures(cfbf, createdUrls) {
|
|
5213
|
+
const urls = [];
|
|
5214
|
+
try {
|
|
5215
|
+
const picStream = cfbf.readStream("Pictures");
|
|
5216
|
+
if (!picStream || picStream.length < 32) return urls;
|
|
5217
|
+
const pBuf = new Uint8Array(picStream);
|
|
5218
|
+
const pngSig = [137, 80, 78, 71, 13, 10, 26, 10];
|
|
5219
|
+
const iendSig = [73, 69, 78, 68, 174, 66, 96, 130];
|
|
5220
|
+
for (let i = 0; i <= pBuf.length - 8; i++) {
|
|
5221
|
+
let match = true;
|
|
5222
|
+
for (let j = 0; j < 8; j++) {
|
|
5223
|
+
if (pBuf[i + j] !== pngSig[j]) {
|
|
5224
|
+
match = false;
|
|
5225
|
+
break;
|
|
5226
|
+
}
|
|
5227
|
+
}
|
|
5228
|
+
if (match) {
|
|
5229
|
+
let endIdx = -1;
|
|
5230
|
+
for (let k = i + 8; k <= pBuf.length - 8; k++) {
|
|
5231
|
+
let endMatch = true;
|
|
5232
|
+
for (let j = 0; j < 8; j++) {
|
|
5233
|
+
if (pBuf[k + j] !== iendSig[j]) {
|
|
5234
|
+
endMatch = false;
|
|
5235
|
+
break;
|
|
5236
|
+
}
|
|
5237
|
+
}
|
|
5238
|
+
if (endMatch) {
|
|
5239
|
+
endIdx = k + 8;
|
|
5240
|
+
break;
|
|
5241
|
+
}
|
|
5242
|
+
}
|
|
5243
|
+
if (endIdx !== -1) {
|
|
5244
|
+
const pngBytes = pBuf.subarray(i, endIdx);
|
|
5245
|
+
const blob = new Blob([pngBytes], { type: "image/png" });
|
|
5246
|
+
const url = URL.createObjectURL(blob);
|
|
5247
|
+
urls.push(url);
|
|
5248
|
+
createdUrls.push(url);
|
|
5249
|
+
i = endIdx;
|
|
5250
|
+
}
|
|
5251
|
+
}
|
|
5252
|
+
}
|
|
5253
|
+
for (let i = 0; i <= pBuf.length - 3; i++) {
|
|
5254
|
+
if (pBuf[i] === 255 && pBuf[i + 1] === 216 && pBuf[i + 2] === 255) {
|
|
5255
|
+
let endIdx = -1;
|
|
5256
|
+
for (let k = i + 3; k < pBuf.length - 1; k++) {
|
|
5257
|
+
if (pBuf[k] === 255 && pBuf[k + 1] === 217) {
|
|
5258
|
+
endIdx = k + 2;
|
|
5259
|
+
break;
|
|
5260
|
+
}
|
|
5261
|
+
}
|
|
5262
|
+
if (endIdx !== -1) {
|
|
5263
|
+
const jpgBytes = pBuf.subarray(i, endIdx);
|
|
5264
|
+
const blob = new Blob([jpgBytes], { type: "image/jpeg" });
|
|
5265
|
+
const url = URL.createObjectURL(blob);
|
|
5266
|
+
urls.push(url);
|
|
5267
|
+
createdUrls.push(url);
|
|
5268
|
+
i = endIdx;
|
|
5269
|
+
}
|
|
5270
|
+
}
|
|
5271
|
+
}
|
|
5272
|
+
} catch (err) {
|
|
5273
|
+
console.warn("[PptPlugin] Error extracting pictures:", err);
|
|
5274
|
+
}
|
|
5275
|
+
return urls;
|
|
5276
|
+
}
|
|
4572
5277
|
/**
|
|
4573
5278
|
* Traverse PowerPoint binary stream records ([MS-PPT]) and extract text chunks per slide
|
|
4574
5279
|
*/
|
|
4575
|
-
extractSlides(stream) {
|
|
5280
|
+
extractSlides(stream, pictures) {
|
|
4576
5281
|
const view = new DataView(stream.buffer, stream.byteOffset, stream.byteLength);
|
|
4577
5282
|
const len = stream.length;
|
|
4578
5283
|
let offset = 0;
|
|
4579
5284
|
const slides = [];
|
|
4580
|
-
let
|
|
5285
|
+
let picIdx = 0;
|
|
4581
5286
|
while (offset + 8 <= len) {
|
|
4582
5287
|
const recVerInst = view.getUint16(offset, true);
|
|
4583
5288
|
const recType = view.getUint16(offset + 2, true);
|
|
4584
5289
|
const recLen = view.getUint32(offset + 4, true);
|
|
5290
|
+
const isContainer = (recVerInst & 15) === 15;
|
|
4585
5291
|
if (recType === 1006) {
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
5292
|
+
const slideEnd = Math.min(len, offset + 8 + recLen);
|
|
5293
|
+
const rawTexts = [];
|
|
5294
|
+
let hasOle = false;
|
|
5295
|
+
let sOff = offset + 8;
|
|
5296
|
+
while (sOff + 8 <= slideEnd) {
|
|
5297
|
+
const cVerInst = view.getUint16(sOff, true);
|
|
5298
|
+
const cType = view.getUint16(sOff + 2, true);
|
|
5299
|
+
const cLen = view.getUint32(sOff + 4, true);
|
|
5300
|
+
const cIsContainer = (cVerInst & 15) === 15;
|
|
5301
|
+
if ((cType === 4008 || cType === 3998) && cLen > 0 && sOff + 8 + cLen <= slideEnd) {
|
|
5302
|
+
const bytes = stream.subarray(sOff + 8, sOff + 8 + cLen);
|
|
5303
|
+
const txt = new TextDecoder("latin1").decode(bytes).trim();
|
|
5304
|
+
if (txt && !/^[\x00-\x1F]+$/.test(txt) && !txt.includes("[Content_Types]") && !txt.includes("_rels/")) {
|
|
5305
|
+
rawTexts.push(txt);
|
|
5306
|
+
}
|
|
5307
|
+
} else if (cType === 3999 && cLen > 0 && sOff + 8 + cLen <= slideEnd) {
|
|
5308
|
+
const bytes = stream.subarray(sOff + 8, sOff + 8 + cLen);
|
|
5309
|
+
const txt = new TextDecoder("utf-16le").decode(bytes).trim();
|
|
5310
|
+
if (txt && !/^[\x00-\x1F]+$/.test(txt) && !txt.includes("[Content_Types]") && !txt.includes("_rels/")) {
|
|
5311
|
+
rawTexts.push(txt);
|
|
5312
|
+
}
|
|
5313
|
+
} else if (cType === 3009 || cType === 3011) {
|
|
5314
|
+
hasOle = true;
|
|
5315
|
+
}
|
|
5316
|
+
if (cIsContainer) sOff += 8;
|
|
5317
|
+
else sOff += 8 + cLen;
|
|
4591
5318
|
}
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
5319
|
+
let title = "";
|
|
5320
|
+
let subtitle = "";
|
|
5321
|
+
const paragraphs = [];
|
|
5322
|
+
const tableColumns = [];
|
|
5323
|
+
for (const t of rawTexts) {
|
|
5324
|
+
if (!title && t.length < 60 && !t.includes("\n")) {
|
|
5325
|
+
title = t;
|
|
5326
|
+
} else if (t.startsWith("Column ") || title === "Table" && t.startsWith("Column")) {
|
|
5327
|
+
tableColumns.push(t);
|
|
5328
|
+
} else if (t.length < 35 && (t.includes("#") || t.toUpperCase() === t) && !subtitle) {
|
|
5329
|
+
subtitle = t;
|
|
5330
|
+
} else {
|
|
5331
|
+
paragraphs.push(t);
|
|
5332
|
+
}
|
|
4600
5333
|
}
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
const text = new TextDecoder("utf-16le").decode(bytes).trim();
|
|
4605
|
-
if (text && text.length > 1 && !/^[\x00-\x1F\x7F-\x9F]+$/.test(text)) {
|
|
4606
|
-
currentSlideTexts.push(text);
|
|
5334
|
+
let pictureUrl = null;
|
|
5335
|
+
if ((hasOle || rawTexts.some((t) => t.toLowerCase().includes("chart") || t.toLowerCase().includes("figure"))) && picIdx < pictures.length) {
|
|
5336
|
+
pictureUrl = pictures[picIdx++];
|
|
4607
5337
|
}
|
|
5338
|
+
slides.push({
|
|
5339
|
+
slideIndex: slides.length + 1,
|
|
5340
|
+
title: title || `Slide ${slides.length + 1}`,
|
|
5341
|
+
subtitle,
|
|
5342
|
+
paragraphs,
|
|
5343
|
+
tableColumns,
|
|
5344
|
+
pictureUrl,
|
|
5345
|
+
hasOle
|
|
5346
|
+
});
|
|
4608
5347
|
}
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
offset += 8;
|
|
4612
|
-
} else {
|
|
4613
|
-
offset += 8 + recLen;
|
|
4614
|
-
}
|
|
4615
|
-
}
|
|
4616
|
-
if (currentSlideTexts.length > 0) {
|
|
4617
|
-
const title = currentSlideTexts[0] || "Slide";
|
|
4618
|
-
const texts = currentSlideTexts.slice(1);
|
|
4619
|
-
slides.push({ title, texts });
|
|
5348
|
+
if (isContainer) offset += 8;
|
|
5349
|
+
else offset += 8 + recLen;
|
|
4620
5350
|
}
|
|
4621
5351
|
if (slides.length === 0) {
|
|
4622
5352
|
const rawText = new TextDecoder("latin1", { fatal: false }).decode(stream);
|
|
4623
|
-
const matches = rawText.match(/[A-Za-z0-9\s,.:;!?'"-]{
|
|
4624
|
-
const
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
5353
|
+
const matches = rawText.match(/[A-Za-z0-9\s,.:;!?'"-]{5,}/g) || [];
|
|
5354
|
+
const clean = matches.map((m) => m.trim()).filter(
|
|
5355
|
+
(m) => m.length > 4 && !m.includes("PowerPoint") && !m.includes("Arial") && !m.includes("Times") && !m.includes("[Content_Types]") && !m.includes("_rels/") && !m.includes("xml")
|
|
5356
|
+
);
|
|
5357
|
+
if (clean.length > 0) {
|
|
5358
|
+
const chunkSize = 3;
|
|
5359
|
+
for (let i = 0; i < clean.length; i += chunkSize) {
|
|
5360
|
+
const chunk = clean.slice(i, i + chunkSize);
|
|
4629
5361
|
slides.push({
|
|
5362
|
+
slideIndex: slides.length + 1,
|
|
4630
5363
|
title: chunk[0] || `Slide ${Math.floor(i / chunkSize) + 1}`,
|
|
4631
|
-
|
|
5364
|
+
subtitle: chunk.length > 2 ? chunk[1] : void 0,
|
|
5365
|
+
paragraphs: chunk.length > 2 ? chunk.slice(2) : chunk.slice(1),
|
|
5366
|
+
tableColumns: [],
|
|
5367
|
+
pictureUrl: pictures[slides.length] || null
|
|
4632
5368
|
});
|
|
4633
5369
|
}
|
|
4634
5370
|
}
|