@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/react.cjs
CHANGED
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var react = require('react');
|
|
6
6
|
var DOMPurify2 = require('dompurify');
|
|
7
|
+
var pdfjsLib = require('pdfjs-dist');
|
|
7
8
|
var docx = require('docx-preview');
|
|
8
9
|
var fflate = require('fflate');
|
|
9
10
|
var XLSX = require('xlsx');
|
|
@@ -14,7 +15,7 @@ var THREE = require('three');
|
|
|
14
15
|
var STLLoader_js = require('three/examples/jsm/loaders/STLLoader.js');
|
|
15
16
|
var OBJLoader_js = require('three/examples/jsm/loaders/OBJLoader.js');
|
|
16
17
|
var OrbitControls_js = require('three/examples/jsm/controls/OrbitControls.js');
|
|
17
|
-
var
|
|
18
|
+
var RTFJS = require('rtf.js/dist/RTFJS.bundle.js');
|
|
18
19
|
var jsxRuntime = require('react/jsx-runtime');
|
|
19
20
|
|
|
20
21
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -38,10 +39,12 @@ function _interopNamespace(e) {
|
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
var DOMPurify2__default = /*#__PURE__*/_interopDefault(DOMPurify2);
|
|
42
|
+
var pdfjsLib__namespace = /*#__PURE__*/_interopNamespace(pdfjsLib);
|
|
41
43
|
var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
|
|
42
44
|
var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
|
|
43
45
|
var hljs__default = /*#__PURE__*/_interopDefault(hljs);
|
|
44
46
|
var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
|
|
47
|
+
var RTFJS__namespace = /*#__PURE__*/_interopNamespace(RTFJS);
|
|
45
48
|
|
|
46
49
|
// src/react.tsx
|
|
47
50
|
var EventEmitter = class {
|
|
@@ -297,6 +300,39 @@ function detectOoxmlType(buffer) {
|
|
|
297
300
|
}
|
|
298
301
|
return "application/zip";
|
|
299
302
|
}
|
|
303
|
+
function detectCfbfType(buffer) {
|
|
304
|
+
const bytes = new Uint8Array(buffer);
|
|
305
|
+
const hasUtf16le = (str) => {
|
|
306
|
+
const target = new Uint8Array(str.length * 2);
|
|
307
|
+
for (let i = 0; i < str.length; i++) {
|
|
308
|
+
target[i * 2] = str.charCodeAt(i);
|
|
309
|
+
target[i * 2 + 1] = 0;
|
|
310
|
+
}
|
|
311
|
+
const targetLen = target.length;
|
|
312
|
+
const max = bytes.length - targetLen;
|
|
313
|
+
for (let i = 0; i <= max; i++) {
|
|
314
|
+
let match = true;
|
|
315
|
+
for (let j = 0; j < targetLen; j++) {
|
|
316
|
+
if (bytes[i + j] !== target[j]) {
|
|
317
|
+
match = false;
|
|
318
|
+
break;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
if (match) return true;
|
|
322
|
+
}
|
|
323
|
+
return false;
|
|
324
|
+
};
|
|
325
|
+
if (hasUtf16le("PowerPoint Document")) {
|
|
326
|
+
return { mime: "application/vnd.ms-powerpoint", extension: ".ppt" };
|
|
327
|
+
}
|
|
328
|
+
if (hasUtf16le("WordDocument")) {
|
|
329
|
+
return { mime: "application/msword", extension: ".doc" };
|
|
330
|
+
}
|
|
331
|
+
if (hasUtf16le("Workbook") || hasUtf16le("Book")) {
|
|
332
|
+
return { mime: "application/vnd.ms-excel", extension: ".xls" };
|
|
333
|
+
}
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
300
336
|
function extractExtension(nameOrUrl) {
|
|
301
337
|
try {
|
|
302
338
|
const url = new URL(nameOrUrl);
|
|
@@ -361,6 +397,18 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
361
397
|
} else {
|
|
362
398
|
metadata.mimeType = metadata.mimeType ?? magicMime;
|
|
363
399
|
}
|
|
400
|
+
} else if (magicMime === "application/x-cfbf") {
|
|
401
|
+
if (metadata.extension) {
|
|
402
|
+
metadata.mimeType = mimeFromExtension(metadata.extension) ?? magicMime;
|
|
403
|
+
} else {
|
|
404
|
+
const cfbf = detectCfbfType(buffer);
|
|
405
|
+
if (cfbf) {
|
|
406
|
+
metadata.mimeType = cfbf.mime;
|
|
407
|
+
metadata.extension = cfbf.extension;
|
|
408
|
+
} else {
|
|
409
|
+
metadata.mimeType = magicMime;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
364
412
|
} else {
|
|
365
413
|
metadata.mimeType = magicMime;
|
|
366
414
|
}
|
|
@@ -465,11 +513,21 @@ var ToolbarController = class {
|
|
|
465
513
|
el;
|
|
466
514
|
toolbarEl;
|
|
467
515
|
actions = [];
|
|
516
|
+
pageInputEl = null;
|
|
517
|
+
pageLabelEl = null;
|
|
468
518
|
constructor(container) {
|
|
469
519
|
this.el = container;
|
|
470
520
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
471
521
|
this.el.appendChild(this.toolbarEl);
|
|
472
522
|
}
|
|
523
|
+
setPage(page, max) {
|
|
524
|
+
if (this.pageInputEl) {
|
|
525
|
+
this.pageInputEl.value = page.toString();
|
|
526
|
+
}
|
|
527
|
+
if (max !== void 0 && this.pageLabelEl) {
|
|
528
|
+
this.pageLabelEl.textContent = ` / ${max}`;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
473
531
|
update(actions) {
|
|
474
532
|
this.actions = actions;
|
|
475
533
|
this.render();
|
|
@@ -512,6 +570,7 @@ var ToolbarController = class {
|
|
|
512
570
|
if (action.type === "separator") {
|
|
513
571
|
groupEl.appendChild(createElement("div", { className: "fp-toolbar-separator" }));
|
|
514
572
|
} else if (action.type === "page-nav") {
|
|
573
|
+
const max = action.max ?? 1;
|
|
515
574
|
const prevBtn = this.createButton(
|
|
516
575
|
"prev",
|
|
517
576
|
ICON_PAGE_PREV,
|
|
@@ -530,7 +589,6 @@ var ToolbarController = class {
|
|
|
530
589
|
"Next Page",
|
|
531
590
|
() => {
|
|
532
591
|
const cur = parseInt(input.value, 10) || 1;
|
|
533
|
-
const max = action.max ?? 1;
|
|
534
592
|
if (cur < max) {
|
|
535
593
|
input.value = (cur + 1).toString();
|
|
536
594
|
action.execute("next", cur + 1);
|
|
@@ -542,15 +600,18 @@ var ToolbarController = class {
|
|
|
542
600
|
type: "number",
|
|
543
601
|
value: (action.value ?? 1).toString(),
|
|
544
602
|
min: "1",
|
|
545
|
-
max:
|
|
603
|
+
max: max.toString()
|
|
546
604
|
});
|
|
547
605
|
input.addEventListener("change", () => {
|
|
548
|
-
|
|
549
|
-
if (
|
|
550
|
-
|
|
551
|
-
|
|
606
|
+
let val = parseInt(input.value, 10);
|
|
607
|
+
if (isNaN(val)) val = 1;
|
|
608
|
+
val = Math.max(1, Math.min(max, val));
|
|
609
|
+
input.value = val.toString();
|
|
610
|
+
action.execute("go", val);
|
|
552
611
|
});
|
|
553
|
-
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${
|
|
612
|
+
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
613
|
+
this.pageInputEl = input;
|
|
614
|
+
this.pageLabelEl = label;
|
|
554
615
|
groupEl.appendChild(prevBtn);
|
|
555
616
|
groupEl.appendChild(input);
|
|
556
617
|
groupEl.appendChild(label);
|
|
@@ -728,7 +789,13 @@ var FilePreviewViewer = class {
|
|
|
728
789
|
buffer,
|
|
729
790
|
options,
|
|
730
791
|
signal,
|
|
731
|
-
emit: (event, payload) =>
|
|
792
|
+
emit: (event, payload) => {
|
|
793
|
+
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
794
|
+
const total = payload.total ?? payload.totalPages;
|
|
795
|
+
this.toolbar?.setPage(payload.page, total);
|
|
796
|
+
}
|
|
797
|
+
this.eventEmitter.emit(event, payload);
|
|
798
|
+
}
|
|
732
799
|
});
|
|
733
800
|
this.activeInstance = instance;
|
|
734
801
|
this.hideLoading();
|
|
@@ -762,6 +829,7 @@ var FilePreviewViewer = class {
|
|
|
762
829
|
if (thumbnails && thumbnails.length > 0 && this.thumbnailPanel) {
|
|
763
830
|
this.thumbnailPanel.update(thumbnails, (index) => {
|
|
764
831
|
instance.goToPage?.(index + 1);
|
|
832
|
+
this.toolbar?.setPage(index + 1);
|
|
765
833
|
});
|
|
766
834
|
if (options.showThumbnails) {
|
|
767
835
|
this.thumbnailPanel.show();
|
|
@@ -887,9 +955,13 @@ var FilePreviewViewer = class {
|
|
|
887
955
|
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
888
956
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
889
957
|
this.activeInstance.goToPage?.(cur + 1);
|
|
958
|
+
const nextCur = this.activeInstance.getCurrentPage?.() ?? cur + 1;
|
|
959
|
+
this.toolbar?.setPage(nextCur);
|
|
890
960
|
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
891
961
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
892
962
|
this.activeInstance.goToPage?.(Math.max(1, cur - 1));
|
|
963
|
+
const prevCur = this.activeInstance.getCurrentPage?.() ?? Math.max(1, cur - 1);
|
|
964
|
+
this.toolbar?.setPage(prevCur);
|
|
893
965
|
} else if (e.key === "+" || e.key === "=") {
|
|
894
966
|
this.activeInstance.zoomIn?.();
|
|
895
967
|
} else if (e.key === "-" || e.key === "_") {
|
|
@@ -1155,30 +1227,62 @@ var CfbfReader = class {
|
|
|
1155
1227
|
return result.subarray(0, targetSize);
|
|
1156
1228
|
}
|
|
1157
1229
|
};
|
|
1158
|
-
|
|
1159
|
-
|
|
1230
|
+
if (typeof window !== "undefined" && pdfjsLib__namespace.GlobalWorkerOptions) {
|
|
1231
|
+
if (!pdfjsLib__namespace.GlobalWorkerOptions.workerSrc) {
|
|
1232
|
+
pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/build/pdf.worker.min.mjs`;
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1160
1235
|
var PdfPlugin = class {
|
|
1161
1236
|
id = "pdf";
|
|
1162
|
-
name = "PDF Preview";
|
|
1237
|
+
name = "PDF Document Preview";
|
|
1163
1238
|
extensions = [".pdf"];
|
|
1164
1239
|
mimeTypes = ["application/pdf"];
|
|
1165
1240
|
weight = 100;
|
|
1166
1241
|
supports(file) {
|
|
1167
1242
|
const ext = file.metadata.extension?.toLowerCase();
|
|
1168
1243
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
1169
|
-
|
|
1244
|
+
if (ext) return this.extensions.includes(ext);
|
|
1245
|
+
return this.mimeTypes.includes(mime || "");
|
|
1170
1246
|
}
|
|
1171
1247
|
getToolbarActions(instance) {
|
|
1248
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1249
|
+
const curPage = instance.getCurrentPage?.() ?? 1;
|
|
1172
1250
|
return [
|
|
1251
|
+
{
|
|
1252
|
+
id: "thumbnails",
|
|
1253
|
+
icon: "thumbnails",
|
|
1254
|
+
label: "Page Thumbnails",
|
|
1255
|
+
type: "button",
|
|
1256
|
+
group: "navigation",
|
|
1257
|
+
execute: () => instance.toggleThumbnails?.()
|
|
1258
|
+
},
|
|
1259
|
+
{
|
|
1260
|
+
id: "page-nav",
|
|
1261
|
+
icon: "",
|
|
1262
|
+
label: "Page Navigation",
|
|
1263
|
+
type: "page-nav",
|
|
1264
|
+
group: "navigation",
|
|
1265
|
+
value: curPage,
|
|
1266
|
+
max: totalPages,
|
|
1267
|
+
execute: (action, page) => {
|
|
1268
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1269
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1270
|
+
if (action === "prev") {
|
|
1271
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1272
|
+
} else if (action === "next") {
|
|
1273
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1274
|
+
} else if (typeof page === "number") {
|
|
1275
|
+
instance.goToPage?.(page);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
},
|
|
1173
1279
|
{
|
|
1174
1280
|
id: "zoom-out",
|
|
1175
1281
|
icon: "zoom-out",
|
|
1176
1282
|
label: "Zoom Out",
|
|
1177
1283
|
type: "button",
|
|
1178
1284
|
group: "zoom",
|
|
1179
|
-
execute: () =>
|
|
1180
|
-
instance.zoomOut?.();
|
|
1181
|
-
}
|
|
1285
|
+
execute: () => instance.zoomOut?.()
|
|
1182
1286
|
},
|
|
1183
1287
|
{
|
|
1184
1288
|
id: "zoom-in",
|
|
@@ -1186,9 +1290,7 @@ var PdfPlugin = class {
|
|
|
1186
1290
|
label: "Zoom In",
|
|
1187
1291
|
type: "button",
|
|
1188
1292
|
group: "zoom",
|
|
1189
|
-
execute: () =>
|
|
1190
|
-
instance.zoomIn?.();
|
|
1191
|
-
}
|
|
1293
|
+
execute: () => instance.zoomIn?.()
|
|
1192
1294
|
},
|
|
1193
1295
|
{
|
|
1194
1296
|
id: "fit-page",
|
|
@@ -1196,39 +1298,23 @@ var PdfPlugin = class {
|
|
|
1196
1298
|
label: "Fit to Page",
|
|
1197
1299
|
type: "button",
|
|
1198
1300
|
group: "zoom",
|
|
1199
|
-
execute: () =>
|
|
1200
|
-
instance.fitToPage?.();
|
|
1201
|
-
}
|
|
1301
|
+
execute: () => instance.fitToPage?.()
|
|
1202
1302
|
},
|
|
1203
1303
|
{
|
|
1204
1304
|
id: "rotate-cw",
|
|
1205
1305
|
icon: "rotate-cw",
|
|
1206
|
-
label: "Rotate",
|
|
1306
|
+
label: "Rotate Clockwise",
|
|
1207
1307
|
type: "button",
|
|
1208
1308
|
group: "view",
|
|
1209
|
-
execute: () =>
|
|
1210
|
-
instance.rotateCW?.();
|
|
1211
|
-
}
|
|
1212
|
-
},
|
|
1213
|
-
{
|
|
1214
|
-
id: "page-nav",
|
|
1215
|
-
icon: "page-nav",
|
|
1216
|
-
label: "Page Navigation",
|
|
1217
|
-
type: "page-nav",
|
|
1218
|
-
group: "navigation",
|
|
1219
|
-
execute: (page) => {
|
|
1220
|
-
if (typeof page === "number") instance.goToPage?.(page);
|
|
1221
|
-
}
|
|
1309
|
+
execute: () => instance.rotateCW?.()
|
|
1222
1310
|
},
|
|
1223
1311
|
{
|
|
1224
1312
|
id: "download",
|
|
1225
1313
|
icon: "download",
|
|
1226
|
-
label: "Download",
|
|
1314
|
+
label: "Download PDF",
|
|
1227
1315
|
type: "button",
|
|
1228
1316
|
group: "actions",
|
|
1229
|
-
execute: () =>
|
|
1230
|
-
instance.download?.();
|
|
1231
|
-
}
|
|
1317
|
+
execute: () => instance.download?.()
|
|
1232
1318
|
},
|
|
1233
1319
|
{
|
|
1234
1320
|
id: "print",
|
|
@@ -1236,99 +1322,213 @@ var PdfPlugin = class {
|
|
|
1236
1322
|
label: "Print",
|
|
1237
1323
|
type: "button",
|
|
1238
1324
|
group: "actions",
|
|
1239
|
-
execute: () =>
|
|
1240
|
-
instance.print?.();
|
|
1241
|
-
}
|
|
1325
|
+
execute: () => instance.print?.()
|
|
1242
1326
|
}
|
|
1243
1327
|
];
|
|
1244
1328
|
}
|
|
1245
1329
|
async render(ctx) {
|
|
1246
|
-
const
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1330
|
+
const container = document.createElement("div");
|
|
1331
|
+
container.className = "fp-pdf-container";
|
|
1332
|
+
container.style.width = "100%";
|
|
1333
|
+
container.style.height = "100%";
|
|
1334
|
+
container.style.overflow = "auto";
|
|
1335
|
+
container.style.display = "flex";
|
|
1336
|
+
container.style.flexDirection = "column";
|
|
1337
|
+
container.style.alignItems = "center";
|
|
1338
|
+
container.style.padding = "24px 16px";
|
|
1339
|
+
container.style.backgroundColor = "#0f172a";
|
|
1340
|
+
container.style.boxSizing = "border-box";
|
|
1341
|
+
container.style.position = "relative";
|
|
1342
|
+
const pageCard = document.createElement("div");
|
|
1343
|
+
pageCard.className = "fp-pdf-page-card";
|
|
1344
|
+
pageCard.style.boxShadow = "0 10px 35px rgba(0, 0, 0, 0.5)";
|
|
1345
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
1346
|
+
pageCard.style.borderRadius = "4px";
|
|
1347
|
+
pageCard.style.overflow = "hidden";
|
|
1348
|
+
pageCard.style.lineHeight = "0";
|
|
1349
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
1350
|
+
pageCard.style.position = "relative";
|
|
1351
|
+
const canvas = document.createElement("canvas");
|
|
1352
|
+
pageCard.appendChild(canvas);
|
|
1353
|
+
container.appendChild(pageCard);
|
|
1354
|
+
const indicator = document.createElement("div");
|
|
1355
|
+
indicator.className = "fp-pdf-page-indicator";
|
|
1356
|
+
indicator.style.position = "sticky";
|
|
1357
|
+
indicator.style.bottom = "16px";
|
|
1358
|
+
indicator.style.marginTop = "16px";
|
|
1359
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1360
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
1361
|
+
indicator.style.color = "#f8fafc";
|
|
1362
|
+
indicator.style.fontSize = "12px";
|
|
1363
|
+
indicator.style.fontWeight = "600";
|
|
1364
|
+
indicator.style.padding = "5px 14px";
|
|
1365
|
+
indicator.style.borderRadius = "20px";
|
|
1366
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1367
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1368
|
+
indicator.style.zIndex = "10";
|
|
1369
|
+
indicator.style.userSelect = "none";
|
|
1370
|
+
indicator.style.pointerEvents = "none";
|
|
1371
|
+
container.appendChild(indicator);
|
|
1372
|
+
ctx.container.appendChild(container);
|
|
1373
|
+
const loadingTask = pdfjsLib__namespace.getDocument({
|
|
1374
|
+
data: new Uint8Array(ctx.buffer),
|
|
1375
|
+
cMapUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/cmaps/`,
|
|
1376
|
+
cMapPacked: true,
|
|
1377
|
+
standardFontDataUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/standard_fonts/`
|
|
1378
|
+
});
|
|
1379
|
+
const pdfDoc = await loadingTask.promise;
|
|
1380
|
+
const totalPages = Math.max(1, pdfDoc.numPages);
|
|
1262
1381
|
let currentPage = 1;
|
|
1263
|
-
let
|
|
1382
|
+
let zoomScale = 1;
|
|
1264
1383
|
let rotation = 0;
|
|
1384
|
+
let currentRenderTask = null;
|
|
1385
|
+
const renderPage = async (pageNum) => {
|
|
1386
|
+
if (currentRenderTask) {
|
|
1387
|
+
try {
|
|
1388
|
+
currentRenderTask.cancel();
|
|
1389
|
+
} catch {
|
|
1390
|
+
}
|
|
1391
|
+
currentRenderTask = null;
|
|
1392
|
+
}
|
|
1393
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1394
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1395
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1396
|
+
const page = await pdfDoc.getPage(currentPage);
|
|
1397
|
+
const containerWidth = container.clientWidth || 900;
|
|
1398
|
+
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1399
|
+
const baseScale = Math.min((containerWidth - 64) / unscaledVp.width, 1.6);
|
|
1400
|
+
const effectiveScale = (baseScale > 0 ? baseScale : 1) * zoomScale;
|
|
1401
|
+
const pixelRatio = window.devicePixelRatio || 1;
|
|
1402
|
+
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
1403
|
+
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1404
|
+
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1405
|
+
canvas.style.width = `${Math.floor(viewport.width)}px`;
|
|
1406
|
+
canvas.style.height = `${Math.floor(viewport.height)}px`;
|
|
1407
|
+
const canvasCtx = canvas.getContext("2d");
|
|
1408
|
+
if (!canvasCtx) return;
|
|
1409
|
+
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
1410
|
+
currentRenderTask = page.render({
|
|
1411
|
+
canvasContext: canvasCtx,
|
|
1412
|
+
viewport
|
|
1413
|
+
});
|
|
1414
|
+
try {
|
|
1415
|
+
await currentRenderTask.promise;
|
|
1416
|
+
} catch (err) {
|
|
1417
|
+
if (err?.name !== "RenderingCancelledException") {
|
|
1418
|
+
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1419
|
+
}
|
|
1420
|
+
} finally {
|
|
1421
|
+
currentRenderTask = null;
|
|
1422
|
+
}
|
|
1423
|
+
};
|
|
1424
|
+
await renderPage(1);
|
|
1265
1425
|
const cleanup = () => {
|
|
1266
|
-
|
|
1267
|
-
|
|
1426
|
+
if (currentRenderTask) {
|
|
1427
|
+
try {
|
|
1428
|
+
currentRenderTask.cancel();
|
|
1429
|
+
} catch {
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
try {
|
|
1433
|
+
pdfDoc.destroy();
|
|
1434
|
+
} catch {
|
|
1435
|
+
}
|
|
1436
|
+
container.remove();
|
|
1268
1437
|
ctx.container.innerHTML = "";
|
|
1269
1438
|
};
|
|
1270
1439
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1271
|
-
|
|
1440
|
+
const instance = {
|
|
1272
1441
|
destroy: cleanup,
|
|
1273
1442
|
zoomIn: () => {
|
|
1274
|
-
|
|
1275
|
-
|
|
1443
|
+
zoomScale = Math.min(3.5, zoomScale + 0.2);
|
|
1444
|
+
renderPage(currentPage);
|
|
1276
1445
|
},
|
|
1277
1446
|
zoomOut: () => {
|
|
1278
|
-
|
|
1279
|
-
|
|
1447
|
+
zoomScale = Math.max(0.3, zoomScale - 0.2);
|
|
1448
|
+
renderPage(currentPage);
|
|
1280
1449
|
},
|
|
1281
|
-
getZoom: () =>
|
|
1450
|
+
getZoom: () => zoomScale,
|
|
1282
1451
|
setZoom: (level) => {
|
|
1283
|
-
|
|
1284
|
-
|
|
1452
|
+
zoomScale = Math.max(0.3, Math.min(3.5, level));
|
|
1453
|
+
renderPage(currentPage);
|
|
1285
1454
|
},
|
|
1286
1455
|
fitToPage: () => {
|
|
1287
|
-
|
|
1288
|
-
|
|
1456
|
+
zoomScale = 1;
|
|
1457
|
+
renderPage(currentPage);
|
|
1289
1458
|
},
|
|
1290
1459
|
rotateCW: () => {
|
|
1291
1460
|
rotation = (rotation + 90) % 360;
|
|
1292
|
-
|
|
1461
|
+
renderPage(currentPage);
|
|
1293
1462
|
},
|
|
1294
1463
|
rotateCCW: () => {
|
|
1295
1464
|
rotation = (rotation - 90 + 360) % 360;
|
|
1296
|
-
|
|
1465
|
+
renderPage(currentPage);
|
|
1297
1466
|
},
|
|
1298
1467
|
getRotation: () => rotation,
|
|
1468
|
+
getPageCount: () => totalPages,
|
|
1469
|
+
getCurrentPage: () => currentPage,
|
|
1299
1470
|
goToPage: (page) => {
|
|
1300
|
-
|
|
1301
|
-
iframe.src = `${url}#page=${page}`;
|
|
1471
|
+
renderPage(page);
|
|
1302
1472
|
},
|
|
1303
|
-
getCurrentPage: () => currentPage,
|
|
1304
1473
|
download: () => {
|
|
1474
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1475
|
+
const url = URL.createObjectURL(blob);
|
|
1305
1476
|
const a = document.createElement("a");
|
|
1306
1477
|
a.href = url;
|
|
1307
1478
|
a.download = ctx.metadata.name || "document.pdf";
|
|
1308
1479
|
a.click();
|
|
1480
|
+
URL.revokeObjectURL(url);
|
|
1309
1481
|
},
|
|
1310
1482
|
print: () => {
|
|
1311
|
-
|
|
1483
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1484
|
+
const url = URL.createObjectURL(blob);
|
|
1485
|
+
const hiddenIframe = document.createElement("iframe");
|
|
1486
|
+
hiddenIframe.style.position = "fixed";
|
|
1487
|
+
hiddenIframe.style.right = "0";
|
|
1488
|
+
hiddenIframe.style.bottom = "0";
|
|
1489
|
+
hiddenIframe.style.width = "0";
|
|
1490
|
+
hiddenIframe.style.height = "0";
|
|
1491
|
+
hiddenIframe.style.border = "0";
|
|
1492
|
+
document.body.appendChild(hiddenIframe);
|
|
1493
|
+
hiddenIframe.src = url;
|
|
1494
|
+
hiddenIframe.onload = () => {
|
|
1495
|
+
setTimeout(() => {
|
|
1496
|
+
hiddenIframe.contentWindow?.print();
|
|
1497
|
+
setTimeout(() => {
|
|
1498
|
+
hiddenIframe.remove();
|
|
1499
|
+
URL.revokeObjectURL(url);
|
|
1500
|
+
}, 1e3);
|
|
1501
|
+
}, 300);
|
|
1502
|
+
};
|
|
1312
1503
|
},
|
|
1313
1504
|
getThumbnails: async () => {
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1505
|
+
const thumbnails = [];
|
|
1506
|
+
const count = Math.min(totalPages, 50);
|
|
1507
|
+
for (let i = 1; i <= count; i++) {
|
|
1508
|
+
thumbnails.push({
|
|
1509
|
+
index: i,
|
|
1510
|
+
label: `Page ${i}`,
|
|
1511
|
+
render: async (thumbCanvas) => {
|
|
1512
|
+
try {
|
|
1513
|
+
const p = await pdfDoc.getPage(i);
|
|
1514
|
+
const baseVp = p.getViewport({ scale: 1 });
|
|
1515
|
+
const thumbScale = (thumbCanvas.width || 120) / baseVp.width;
|
|
1516
|
+
const thumbVp = p.getViewport({ scale: thumbScale });
|
|
1517
|
+
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1518
|
+
const tCtx = thumbCanvas.getContext("2d");
|
|
1519
|
+
if (tCtx) {
|
|
1520
|
+
await p.render({ canvasContext: tCtx, viewport: thumbVp }).promise;
|
|
1521
|
+
}
|
|
1522
|
+
} catch (e) {
|
|
1523
|
+
console.warn(`[PdfPlugin] Error generating thumbnail for page ${i}:`, e);
|
|
1326
1524
|
}
|
|
1327
1525
|
}
|
|
1328
|
-
}
|
|
1329
|
-
|
|
1526
|
+
});
|
|
1527
|
+
}
|
|
1528
|
+
return thumbnails;
|
|
1330
1529
|
}
|
|
1331
1530
|
};
|
|
1531
|
+
return instance;
|
|
1332
1532
|
}
|
|
1333
1533
|
};
|
|
1334
1534
|
function pdfPlugin() {
|
|
@@ -1649,10 +1849,37 @@ var DocxPlugin = class {
|
|
|
1649
1849
|
supports(file) {
|
|
1650
1850
|
const ext = file.metadata.extension?.toLowerCase();
|
|
1651
1851
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
1652
|
-
|
|
1852
|
+
if (ext) {
|
|
1853
|
+
return this.extensions.includes(ext);
|
|
1854
|
+
}
|
|
1855
|
+
return this.mimeTypes.includes(mime || "");
|
|
1653
1856
|
}
|
|
1654
1857
|
getToolbarActions(instance) {
|
|
1655
|
-
|
|
1858
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1859
|
+
const actions = [];
|
|
1860
|
+
if (totalPages > 1) {
|
|
1861
|
+
actions.push({
|
|
1862
|
+
id: "page-nav",
|
|
1863
|
+
icon: "",
|
|
1864
|
+
label: "Page Navigation",
|
|
1865
|
+
type: "page-nav",
|
|
1866
|
+
group: "navigation",
|
|
1867
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
1868
|
+
max: totalPages,
|
|
1869
|
+
execute: (action, page) => {
|
|
1870
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1871
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1872
|
+
if (action === "prev") {
|
|
1873
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1874
|
+
} else if (action === "next") {
|
|
1875
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1876
|
+
} else if (typeof page === "number") {
|
|
1877
|
+
instance.goToPage?.(page);
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
});
|
|
1881
|
+
}
|
|
1882
|
+
actions.push(
|
|
1656
1883
|
{
|
|
1657
1884
|
id: "zoom-out",
|
|
1658
1885
|
icon: "zoom-out",
|
|
@@ -1693,7 +1920,8 @@ var DocxPlugin = class {
|
|
|
1693
1920
|
group: "actions",
|
|
1694
1921
|
execute: () => instance.print?.()
|
|
1695
1922
|
}
|
|
1696
|
-
|
|
1923
|
+
);
|
|
1924
|
+
return actions;
|
|
1697
1925
|
}
|
|
1698
1926
|
async render(ctx) {
|
|
1699
1927
|
const wrapper = document.createElement("div");
|
|
@@ -1769,7 +1997,51 @@ var DocxPlugin = class {
|
|
|
1769
1997
|
}
|
|
1770
1998
|
}
|
|
1771
1999
|
}
|
|
2000
|
+
const sections = wrapper.querySelectorAll("section.docx");
|
|
2001
|
+
const cards = wrapper.querySelectorAll(".fp-docx-page-card");
|
|
2002
|
+
const pageElements = sections.length > 0 ? sections : cards;
|
|
2003
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
2004
|
+
let currentPage = 1;
|
|
2005
|
+
let indicator = null;
|
|
2006
|
+
if (totalPages > 1) {
|
|
2007
|
+
indicator = document.createElement("div");
|
|
2008
|
+
indicator.className = "fp-docx-page-indicator";
|
|
2009
|
+
indicator.style.position = "sticky";
|
|
2010
|
+
indicator.style.bottom = "16px";
|
|
2011
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2012
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
2013
|
+
indicator.style.color = "#f8fafc";
|
|
2014
|
+
indicator.style.fontSize = "12px";
|
|
2015
|
+
indicator.style.fontWeight = "600";
|
|
2016
|
+
indicator.style.padding = "5px 14px";
|
|
2017
|
+
indicator.style.borderRadius = "20px";
|
|
2018
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2019
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2020
|
+
indicator.style.zIndex = "10";
|
|
2021
|
+
indicator.style.userSelect = "none";
|
|
2022
|
+
indicator.style.pointerEvents = "none";
|
|
2023
|
+
indicator.style.textAlign = "center";
|
|
2024
|
+
indicator.style.width = "fit-content";
|
|
2025
|
+
indicator.style.margin = "16px auto 0";
|
|
2026
|
+
ctx.container.appendChild(indicator);
|
|
2027
|
+
}
|
|
2028
|
+
const showPage = (pageNum) => {
|
|
2029
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2030
|
+
if (pageElements.length > 1) {
|
|
2031
|
+
pageElements.forEach((sec, idx) => {
|
|
2032
|
+
sec.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
2033
|
+
});
|
|
2034
|
+
}
|
|
2035
|
+
if (indicator) {
|
|
2036
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2037
|
+
}
|
|
2038
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2039
|
+
};
|
|
2040
|
+
if (totalPages > 1) {
|
|
2041
|
+
showPage(1);
|
|
2042
|
+
}
|
|
1772
2043
|
const cleanup = () => {
|
|
2044
|
+
indicator?.remove();
|
|
1773
2045
|
for (const url of createdBlobUrls) {
|
|
1774
2046
|
URL.revokeObjectURL(url);
|
|
1775
2047
|
}
|
|
@@ -1780,6 +2052,11 @@ var DocxPlugin = class {
|
|
|
1780
2052
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1781
2053
|
return {
|
|
1782
2054
|
destroy: cleanup,
|
|
2055
|
+
getPageCount: () => totalPages,
|
|
2056
|
+
getCurrentPage: () => currentPage,
|
|
2057
|
+
goToPage: (page) => {
|
|
2058
|
+
showPage(page);
|
|
2059
|
+
},
|
|
1783
2060
|
zoomIn: () => {
|
|
1784
2061
|
scale += 0.1;
|
|
1785
2062
|
wrapper.style.transform = `scale(${scale})`;
|
|
@@ -2038,10 +2315,37 @@ var ExcelPlugin = class {
|
|
|
2038
2315
|
supports(file) {
|
|
2039
2316
|
const ext = file.metadata.extension?.toLowerCase();
|
|
2040
2317
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
2041
|
-
|
|
2318
|
+
if (ext) {
|
|
2319
|
+
return this.extensions.includes(ext);
|
|
2320
|
+
}
|
|
2321
|
+
return this.mimeTypes.includes(mime || "");
|
|
2042
2322
|
}
|
|
2043
2323
|
getToolbarActions(instance) {
|
|
2044
|
-
|
|
2324
|
+
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2325
|
+
const actions = [];
|
|
2326
|
+
if (totalSheets > 1) {
|
|
2327
|
+
actions.push({
|
|
2328
|
+
id: "page-nav",
|
|
2329
|
+
icon: "",
|
|
2330
|
+
label: "Sheet Navigation",
|
|
2331
|
+
type: "page-nav",
|
|
2332
|
+
group: "navigation",
|
|
2333
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2334
|
+
max: totalSheets,
|
|
2335
|
+
execute: (action, sheet) => {
|
|
2336
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2337
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2338
|
+
if (action === "prev") {
|
|
2339
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2340
|
+
} else if (action === "next") {
|
|
2341
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2342
|
+
} else if (typeof sheet === "number") {
|
|
2343
|
+
instance.goToPage?.(sheet);
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
});
|
|
2347
|
+
}
|
|
2348
|
+
actions.push(
|
|
2045
2349
|
{
|
|
2046
2350
|
id: "zoom-out",
|
|
2047
2351
|
icon: "zoom-out",
|
|
@@ -2062,16 +2366,6 @@ var ExcelPlugin = class {
|
|
|
2062
2366
|
instance.zoomIn?.();
|
|
2063
2367
|
}
|
|
2064
2368
|
},
|
|
2065
|
-
{
|
|
2066
|
-
id: "page-nav",
|
|
2067
|
-
icon: "page-nav",
|
|
2068
|
-
label: "Sheet Navigation",
|
|
2069
|
-
type: "page-nav",
|
|
2070
|
-
group: "navigation",
|
|
2071
|
-
execute: (sheet) => {
|
|
2072
|
-
if (typeof sheet === "number") instance.goToPage?.(sheet);
|
|
2073
|
-
}
|
|
2074
|
-
},
|
|
2075
2369
|
{
|
|
2076
2370
|
id: "download",
|
|
2077
2371
|
icon: "download",
|
|
@@ -2092,7 +2386,8 @@ var ExcelPlugin = class {
|
|
|
2092
2386
|
instance.print?.();
|
|
2093
2387
|
}
|
|
2094
2388
|
}
|
|
2095
|
-
|
|
2389
|
+
);
|
|
2390
|
+
return actions;
|
|
2096
2391
|
}
|
|
2097
2392
|
async render(ctx) {
|
|
2098
2393
|
const container = document.createElement("div");
|
|
@@ -2176,6 +2471,7 @@ var ExcelPlugin = class {
|
|
|
2176
2471
|
b.style.fontWeight = "normal";
|
|
2177
2472
|
}
|
|
2178
2473
|
});
|
|
2474
|
+
ctx.emit("page-change", { page: currentSheetIndex, total: sheetNames.length });
|
|
2179
2475
|
};
|
|
2180
2476
|
if (sheetNames.length > 0) {
|
|
2181
2477
|
sheetNames.forEach((name, idx) => {
|
|
@@ -2425,7 +2721,31 @@ var CodePlugin = class {
|
|
|
2425
2721
|
return false;
|
|
2426
2722
|
}
|
|
2427
2723
|
getToolbarActions(instance) {
|
|
2428
|
-
|
|
2724
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2725
|
+
const actions = [];
|
|
2726
|
+
if (totalPages > 1) {
|
|
2727
|
+
actions.push({
|
|
2728
|
+
id: "page-nav",
|
|
2729
|
+
icon: "",
|
|
2730
|
+
label: "Page Navigation",
|
|
2731
|
+
type: "page-nav",
|
|
2732
|
+
group: "navigation",
|
|
2733
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2734
|
+
max: totalPages,
|
|
2735
|
+
execute: (action, page) => {
|
|
2736
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2737
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2738
|
+
if (action === "prev") {
|
|
2739
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2740
|
+
} else if (action === "next") {
|
|
2741
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2742
|
+
} else if (typeof page === "number") {
|
|
2743
|
+
instance.goToPage?.(page);
|
|
2744
|
+
}
|
|
2745
|
+
}
|
|
2746
|
+
});
|
|
2747
|
+
}
|
|
2748
|
+
actions.push(
|
|
2429
2749
|
{
|
|
2430
2750
|
id: "zoom-out",
|
|
2431
2751
|
icon: "zoom-out",
|
|
@@ -2476,11 +2796,16 @@ var CodePlugin = class {
|
|
|
2476
2796
|
instance.print?.();
|
|
2477
2797
|
}
|
|
2478
2798
|
}
|
|
2479
|
-
|
|
2799
|
+
);
|
|
2800
|
+
return actions;
|
|
2480
2801
|
}
|
|
2481
2802
|
async render(ctx) {
|
|
2482
2803
|
const decoder = new TextDecoder("utf-8");
|
|
2483
|
-
const
|
|
2804
|
+
const fullText = decoder.decode(ctx.buffer);
|
|
2805
|
+
const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
|
|
2806
|
+
const rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
2807
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
2808
|
+
let currentPage = 1;
|
|
2484
2809
|
const container = document.createElement("div");
|
|
2485
2810
|
container.style.width = "100%";
|
|
2486
2811
|
container.style.height = "100%";
|
|
@@ -2499,25 +2824,66 @@ var CodePlugin = class {
|
|
|
2499
2824
|
pre.style.wordBreak = "break-all";
|
|
2500
2825
|
const code = document.createElement("code");
|
|
2501
2826
|
const ext = (ctx.metadata.extension || "").replace(".", "");
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2827
|
+
const renderCodePage = (text) => {
|
|
2828
|
+
try {
|
|
2829
|
+
if (ext && hljs__default.default.getLanguage(ext)) {
|
|
2830
|
+
code.innerHTML = hljs__default.default.highlight(text, { language: ext }).value;
|
|
2831
|
+
} else {
|
|
2832
|
+
code.innerHTML = hljs__default.default.highlightAuto(text).value;
|
|
2833
|
+
}
|
|
2834
|
+
} catch {
|
|
2835
|
+
code.textContent = text;
|
|
2507
2836
|
}
|
|
2508
|
-
}
|
|
2509
|
-
|
|
2510
|
-
}
|
|
2837
|
+
};
|
|
2838
|
+
renderCodePage(rawPages[0] || fullText);
|
|
2511
2839
|
pre.appendChild(code);
|
|
2512
2840
|
container.appendChild(pre);
|
|
2841
|
+
let indicator = null;
|
|
2842
|
+
if (totalPages > 1) {
|
|
2843
|
+
indicator = document.createElement("div");
|
|
2844
|
+
indicator.className = "fp-code-page-indicator";
|
|
2845
|
+
indicator.style.position = "sticky";
|
|
2846
|
+
indicator.style.bottom = "16px";
|
|
2847
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2848
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
2849
|
+
indicator.style.color = "#f8fafc";
|
|
2850
|
+
indicator.style.fontSize = "12px";
|
|
2851
|
+
indicator.style.fontWeight = "600";
|
|
2852
|
+
indicator.style.padding = "5px 14px";
|
|
2853
|
+
indicator.style.borderRadius = "20px";
|
|
2854
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2855
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2856
|
+
indicator.style.zIndex = "10";
|
|
2857
|
+
indicator.style.userSelect = "none";
|
|
2858
|
+
indicator.style.pointerEvents = "none";
|
|
2859
|
+
indicator.style.textAlign = "center";
|
|
2860
|
+
indicator.style.width = "fit-content";
|
|
2861
|
+
indicator.style.margin = "16px auto 0";
|
|
2862
|
+
container.appendChild(indicator);
|
|
2863
|
+
}
|
|
2864
|
+
const showPage = (pageNum) => {
|
|
2865
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2866
|
+
renderCodePage(rawPages[currentPage - 1] || fullText);
|
|
2867
|
+
if (indicator) {
|
|
2868
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2869
|
+
}
|
|
2870
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2871
|
+
};
|
|
2872
|
+
if (totalPages > 1) {
|
|
2873
|
+
showPage(1);
|
|
2874
|
+
}
|
|
2513
2875
|
ctx.container.appendChild(container);
|
|
2514
2876
|
const cleanup = () => {
|
|
2877
|
+
indicator?.remove();
|
|
2515
2878
|
container.remove();
|
|
2516
2879
|
ctx.container.innerHTML = "";
|
|
2517
2880
|
};
|
|
2518
2881
|
ctx.signal.addEventListener("abort", cleanup);
|
|
2519
2882
|
return {
|
|
2520
2883
|
destroy: cleanup,
|
|
2884
|
+
getPageCount: () => totalPages,
|
|
2885
|
+
getCurrentPage: () => currentPage,
|
|
2886
|
+
goToPage: (page) => showPage(page),
|
|
2521
2887
|
zoomIn: () => {
|
|
2522
2888
|
fontSize = Math.min(32, fontSize + 2);
|
|
2523
2889
|
pre.style.fontSize = `${fontSize}px`;
|
|
@@ -2545,7 +2911,7 @@ var CodePlugin = class {
|
|
|
2545
2911
|
window.print();
|
|
2546
2912
|
},
|
|
2547
2913
|
copy: () => {
|
|
2548
|
-
navigator.clipboard?.writeText(
|
|
2914
|
+
navigator.clipboard?.writeText(fullText);
|
|
2549
2915
|
}
|
|
2550
2916
|
};
|
|
2551
2917
|
}
|
|
@@ -2980,7 +3346,10 @@ var PptxPlugin = class {
|
|
|
2980
3346
|
supports(file) {
|
|
2981
3347
|
const ext = file.metadata.extension?.toLowerCase();
|
|
2982
3348
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
2983
|
-
|
|
3349
|
+
if (ext) {
|
|
3350
|
+
return this.extensions.includes(ext);
|
|
3351
|
+
}
|
|
3352
|
+
return this.mimeTypes.includes(mime || "");
|
|
2984
3353
|
}
|
|
2985
3354
|
getToolbarActions(instance) {
|
|
2986
3355
|
return [
|
|
@@ -3364,7 +3733,31 @@ var RtfPlugin = class {
|
|
|
3364
3733
|
return this.extensions.includes(ext || "") || this.mimeTypes.includes(mime || "");
|
|
3365
3734
|
}
|
|
3366
3735
|
getToolbarActions(instance) {
|
|
3367
|
-
|
|
3736
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3737
|
+
const actions = [];
|
|
3738
|
+
if (totalPages > 1) {
|
|
3739
|
+
actions.push({
|
|
3740
|
+
id: "page-nav",
|
|
3741
|
+
icon: "",
|
|
3742
|
+
label: "Page Navigation",
|
|
3743
|
+
type: "page-nav",
|
|
3744
|
+
group: "navigation",
|
|
3745
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
3746
|
+
max: totalPages,
|
|
3747
|
+
execute: (action, page) => {
|
|
3748
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3749
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
3750
|
+
if (action === "prev") {
|
|
3751
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
3752
|
+
} else if (action === "next") {
|
|
3753
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
3754
|
+
} else if (typeof page === "number") {
|
|
3755
|
+
instance.goToPage?.(page);
|
|
3756
|
+
}
|
|
3757
|
+
}
|
|
3758
|
+
});
|
|
3759
|
+
}
|
|
3760
|
+
actions.push(
|
|
3368
3761
|
{
|
|
3369
3762
|
id: "zoom-out",
|
|
3370
3763
|
icon: "zoom-out",
|
|
@@ -3405,7 +3798,8 @@ var RtfPlugin = class {
|
|
|
3405
3798
|
group: "actions",
|
|
3406
3799
|
execute: () => instance.print?.()
|
|
3407
3800
|
}
|
|
3408
|
-
|
|
3801
|
+
);
|
|
3802
|
+
return actions;
|
|
3409
3803
|
}
|
|
3410
3804
|
async render(ctx) {
|
|
3411
3805
|
const wrapper = document.createElement("div");
|
|
@@ -3424,25 +3818,82 @@ var RtfPlugin = class {
|
|
|
3424
3818
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
3425
3819
|
ctx.container.appendChild(wrapper);
|
|
3426
3820
|
let scale = 1;
|
|
3821
|
+
let pageElements = [];
|
|
3427
3822
|
try {
|
|
3428
|
-
|
|
3823
|
+
if (typeof RTFJS__namespace.loggingEnabled === "function") {
|
|
3824
|
+
RTFJS__namespace.loggingEnabled(false);
|
|
3825
|
+
}
|
|
3826
|
+
const doc = new RTFJS__namespace.Document(ctx.buffer, {});
|
|
3429
3827
|
const htmlElements = await doc.render();
|
|
3430
|
-
|
|
3828
|
+
pageElements = htmlElements;
|
|
3829
|
+
for (let i = 0; i < htmlElements.length; i++) {
|
|
3830
|
+
const el = htmlElements[i];
|
|
3831
|
+
el.style.display = i === 0 ? "block" : "none";
|
|
3431
3832
|
wrapper.appendChild(el);
|
|
3432
3833
|
}
|
|
3433
3834
|
} catch (err) {
|
|
3434
3835
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
3435
3836
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
3436
3837
|
const clean = text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "");
|
|
3437
|
-
|
|
3838
|
+
const pre = document.createElement("pre");
|
|
3839
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3840
|
+
pre.style.fontFamily = "serif";
|
|
3841
|
+
pre.style.color = "#333";
|
|
3842
|
+
pre.textContent = clean;
|
|
3843
|
+
wrapper.appendChild(pre);
|
|
3844
|
+
pageElements = [pre];
|
|
3845
|
+
}
|
|
3846
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
3847
|
+
let currentPage = 1;
|
|
3848
|
+
let indicator = null;
|
|
3849
|
+
if (totalPages > 1) {
|
|
3850
|
+
indicator = document.createElement("div");
|
|
3851
|
+
indicator.className = "fp-rtf-page-indicator";
|
|
3852
|
+
indicator.style.position = "sticky";
|
|
3853
|
+
indicator.style.bottom = "16px";
|
|
3854
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3855
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
3856
|
+
indicator.style.color = "#f8fafc";
|
|
3857
|
+
indicator.style.fontSize = "12px";
|
|
3858
|
+
indicator.style.fontWeight = "600";
|
|
3859
|
+
indicator.style.padding = "5px 14px";
|
|
3860
|
+
indicator.style.borderRadius = "20px";
|
|
3861
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3862
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3863
|
+
indicator.style.zIndex = "10";
|
|
3864
|
+
indicator.style.userSelect = "none";
|
|
3865
|
+
indicator.style.pointerEvents = "none";
|
|
3866
|
+
indicator.style.textAlign = "center";
|
|
3867
|
+
indicator.style.width = "fit-content";
|
|
3868
|
+
indicator.style.margin = "16px auto 0";
|
|
3869
|
+
ctx.container.appendChild(indicator);
|
|
3870
|
+
}
|
|
3871
|
+
const showPage = (pageNum) => {
|
|
3872
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3873
|
+
if (totalPages > 1) {
|
|
3874
|
+
pageElements.forEach((el, idx) => {
|
|
3875
|
+
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
3876
|
+
});
|
|
3877
|
+
}
|
|
3878
|
+
if (indicator) {
|
|
3879
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3880
|
+
}
|
|
3881
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3882
|
+
};
|
|
3883
|
+
if (totalPages > 1) {
|
|
3884
|
+
showPage(1);
|
|
3438
3885
|
}
|
|
3439
3886
|
const cleanup = () => {
|
|
3887
|
+
indicator?.remove();
|
|
3440
3888
|
wrapper.remove();
|
|
3441
3889
|
ctx.container.innerHTML = "";
|
|
3442
3890
|
};
|
|
3443
3891
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3444
3892
|
return {
|
|
3445
3893
|
destroy: cleanup,
|
|
3894
|
+
getPageCount: () => totalPages,
|
|
3895
|
+
getCurrentPage: () => currentPage,
|
|
3896
|
+
goToPage: (page) => showPage(page),
|
|
3446
3897
|
zoomIn: () => {
|
|
3447
3898
|
scale += 0.1;
|
|
3448
3899
|
wrapper.style.transform = `scale(${scale})`;
|
|
@@ -3623,45 +4074,48 @@ var OpenDocumentPlugin = class {
|
|
|
3623
4074
|
supports(file) {
|
|
3624
4075
|
const ext = file.metadata.extension?.toLowerCase();
|
|
3625
4076
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
3626
|
-
|
|
4077
|
+
if (ext) {
|
|
4078
|
+
return this.extensions.includes(ext);
|
|
4079
|
+
}
|
|
4080
|
+
return this.mimeTypes.includes(mime || "");
|
|
3627
4081
|
}
|
|
3628
4082
|
getToolbarActions(instance) {
|
|
3629
4083
|
const isPresentation = instance.isPresentation;
|
|
4084
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3630
4085
|
const actions = [];
|
|
3631
|
-
if (isPresentation) {
|
|
3632
|
-
|
|
3633
|
-
{
|
|
4086
|
+
if (isPresentation || totalPages > 1) {
|
|
4087
|
+
if (isPresentation) {
|
|
4088
|
+
actions.push({
|
|
3634
4089
|
id: "thumbnails",
|
|
3635
4090
|
icon: "thumbnails",
|
|
3636
4091
|
label: "Slide Thumbnails",
|
|
3637
4092
|
type: "button",
|
|
3638
4093
|
group: "navigation",
|
|
3639
4094
|
execute: () => instance.toggleThumbnails?.()
|
|
3640
|
-
}
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
}
|
|
4095
|
+
});
|
|
4096
|
+
}
|
|
4097
|
+
actions.push({
|
|
4098
|
+
id: "page-nav",
|
|
4099
|
+
icon: "",
|
|
4100
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
4101
|
+
type: "page-nav",
|
|
4102
|
+
group: "navigation",
|
|
4103
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4104
|
+
max: totalPages,
|
|
4105
|
+
execute: (action, page) => {
|
|
4106
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4107
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4108
|
+
if (action === "prev") {
|
|
4109
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4110
|
+
} else if (action === "next") {
|
|
4111
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4112
|
+
} else if (typeof page === "number") {
|
|
4113
|
+
instance.goToPage?.(page);
|
|
4114
|
+
} else if (typeof action === "number") {
|
|
4115
|
+
instance.goToPage?.(action);
|
|
3662
4116
|
}
|
|
3663
4117
|
}
|
|
3664
|
-
);
|
|
4118
|
+
});
|
|
3665
4119
|
}
|
|
3666
4120
|
actions.push(
|
|
3667
4121
|
{
|
|
@@ -4038,10 +4492,37 @@ var DocPlugin = class {
|
|
|
4038
4492
|
supports(file) {
|
|
4039
4493
|
const ext = file.metadata.extension?.toLowerCase();
|
|
4040
4494
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
4041
|
-
|
|
4495
|
+
if (ext) {
|
|
4496
|
+
return this.extensions.includes(ext);
|
|
4497
|
+
}
|
|
4498
|
+
return this.mimeTypes.includes(mime || "");
|
|
4042
4499
|
}
|
|
4043
4500
|
getToolbarActions(instance) {
|
|
4044
|
-
|
|
4501
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4502
|
+
const actions = [];
|
|
4503
|
+
if (totalPages > 1) {
|
|
4504
|
+
actions.push({
|
|
4505
|
+
id: "page-nav",
|
|
4506
|
+
icon: "",
|
|
4507
|
+
label: "Page Navigation",
|
|
4508
|
+
type: "page-nav",
|
|
4509
|
+
group: "navigation",
|
|
4510
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4511
|
+
max: totalPages,
|
|
4512
|
+
execute: (action, page) => {
|
|
4513
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4514
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4515
|
+
if (action === "prev") {
|
|
4516
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4517
|
+
} else if (action === "next") {
|
|
4518
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4519
|
+
} else if (typeof page === "number") {
|
|
4520
|
+
instance.goToPage?.(page);
|
|
4521
|
+
}
|
|
4522
|
+
}
|
|
4523
|
+
});
|
|
4524
|
+
}
|
|
4525
|
+
actions.push(
|
|
4045
4526
|
{
|
|
4046
4527
|
id: "zoom-out",
|
|
4047
4528
|
icon: "zoom-out",
|
|
@@ -4090,7 +4571,8 @@ var DocPlugin = class {
|
|
|
4090
4571
|
group: "actions",
|
|
4091
4572
|
execute: () => instance.print?.()
|
|
4092
4573
|
}
|
|
4093
|
-
|
|
4574
|
+
);
|
|
4575
|
+
return actions;
|
|
4094
4576
|
}
|
|
4095
4577
|
async render(ctx) {
|
|
4096
4578
|
const container = document.createElement("div");
|
|
@@ -4117,6 +4599,7 @@ var DocPlugin = class {
|
|
|
4117
4599
|
ctx.container.appendChild(container);
|
|
4118
4600
|
let scale = 1;
|
|
4119
4601
|
let extractedRawText = "";
|
|
4602
|
+
let isFallback = false;
|
|
4120
4603
|
try {
|
|
4121
4604
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4122
4605
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
@@ -4130,26 +4613,89 @@ var DocPlugin = class {
|
|
|
4130
4613
|
const tableStream = cfbf.readStream(tableName);
|
|
4131
4614
|
const text = this.extractDocText(wordDocStream, tableStream);
|
|
4132
4615
|
extractedRawText = text;
|
|
4133
|
-
wrapper.innerHTML = this.formatDocToHtml(text, ctx.metadata.name || "Document");
|
|
4134
4616
|
} catch (err) {
|
|
4135
4617
|
console.warn("[DocPlugin] Binary parsing error, fallback text:", err);
|
|
4136
4618
|
const fallback = this.heuristicTextExtraction(ctx.buffer);
|
|
4137
4619
|
extractedRawText = fallback;
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4620
|
+
isFallback = true;
|
|
4621
|
+
}
|
|
4622
|
+
const rawPages = this.splitIntoPages(extractedRawText);
|
|
4623
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
4624
|
+
let currentPage = 1;
|
|
4625
|
+
wrapper.innerHTML = "";
|
|
4626
|
+
const pageCards = [];
|
|
4627
|
+
for (let i = 0; i < totalPages; i++) {
|
|
4628
|
+
const pageCard = document.createElement("div");
|
|
4629
|
+
pageCard.className = "fp-doc-page-card";
|
|
4630
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
4631
|
+
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4632
|
+
pageCard.style.borderRadius = "4px";
|
|
4633
|
+
pageCard.style.padding = "56px 48px";
|
|
4634
|
+
pageCard.style.minHeight = "100%";
|
|
4635
|
+
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4636
|
+
if (isFallback && i === 0) {
|
|
4637
|
+
pageCard.innerHTML = `
|
|
4638
|
+
<div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
|
|
4639
|
+
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify2__default.default.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
|
|
4640
|
+
<span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
|
|
4641
|
+
</div>
|
|
4642
|
+
${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
|
|
4643
|
+
`;
|
|
4644
|
+
} else {
|
|
4645
|
+
pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
|
|
4646
|
+
}
|
|
4647
|
+
wrapper.appendChild(pageCard);
|
|
4648
|
+
pageCards.push(pageCard);
|
|
4649
|
+
}
|
|
4650
|
+
let indicator = null;
|
|
4651
|
+
if (totalPages > 1) {
|
|
4652
|
+
indicator = document.createElement("div");
|
|
4653
|
+
indicator.className = "fp-doc-page-indicator";
|
|
4654
|
+
indicator.style.position = "sticky";
|
|
4655
|
+
indicator.style.bottom = "16px";
|
|
4656
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4657
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
4658
|
+
indicator.style.color = "#f8fafc";
|
|
4659
|
+
indicator.style.fontSize = "12px";
|
|
4660
|
+
indicator.style.fontWeight = "600";
|
|
4661
|
+
indicator.style.padding = "5px 14px";
|
|
4662
|
+
indicator.style.borderRadius = "20px";
|
|
4663
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4664
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4665
|
+
indicator.style.zIndex = "10";
|
|
4666
|
+
indicator.style.userSelect = "none";
|
|
4667
|
+
indicator.style.pointerEvents = "none";
|
|
4668
|
+
indicator.style.textAlign = "center";
|
|
4669
|
+
indicator.style.width = "fit-content";
|
|
4670
|
+
indicator.style.margin = "16px auto 0";
|
|
4671
|
+
container.appendChild(indicator);
|
|
4672
|
+
}
|
|
4673
|
+
const showPage = (pageNum) => {
|
|
4674
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4675
|
+
if (totalPages > 1) {
|
|
4676
|
+
pageCards.forEach((card, idx) => {
|
|
4677
|
+
card.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4678
|
+
});
|
|
4679
|
+
}
|
|
4680
|
+
if (indicator) {
|
|
4681
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4682
|
+
}
|
|
4683
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4684
|
+
};
|
|
4685
|
+
if (totalPages > 1) {
|
|
4686
|
+
showPage(1);
|
|
4145
4687
|
}
|
|
4146
4688
|
const cleanup = () => {
|
|
4689
|
+
indicator?.remove();
|
|
4147
4690
|
container.remove();
|
|
4148
4691
|
ctx.container.innerHTML = "";
|
|
4149
4692
|
};
|
|
4150
4693
|
ctx.signal.addEventListener("abort", cleanup);
|
|
4151
4694
|
return {
|
|
4152
4695
|
destroy: cleanup,
|
|
4696
|
+
getPageCount: () => totalPages,
|
|
4697
|
+
getCurrentPage: () => currentPage,
|
|
4698
|
+
goToPage: (page) => showPage(page),
|
|
4153
4699
|
zoomIn: () => {
|
|
4154
4700
|
scale += 0.1;
|
|
4155
4701
|
wrapper.style.transform = `scale(${scale})`;
|
|
@@ -4261,31 +4807,36 @@ var DocPlugin = class {
|
|
|
4261
4807
|
* Scans a byte array for continuous sequences of readable characters (ANSI and UTF-16LE)
|
|
4262
4808
|
*/
|
|
4263
4809
|
extractStringsFromBytes(bytes) {
|
|
4264
|
-
const
|
|
4265
|
-
const
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4810
|
+
const rawAnsi = new TextDecoder("latin1").decode(bytes);
|
|
4811
|
+
const rawUtf16 = new TextDecoder("utf-16le", { fatal: false }).decode(bytes);
|
|
4812
|
+
const ansiRuns = rawAnsi.match(/[\x20-\x7E\t\r\n]{4,}/g) || [];
|
|
4813
|
+
const utf16Runs = rawUtf16.match(/[\x20-\x7E\t\r\n]{4,}/g) || [];
|
|
4814
|
+
const candidateLines = [];
|
|
4815
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4816
|
+
for (const run of [...ansiRuns, ...utf16Runs]) {
|
|
4817
|
+
const trimmed = run.trim();
|
|
4818
|
+
if (trimmed.length >= 4 && /[a-zA-Z]/.test(trimmed) && !seen.has(trimmed)) {
|
|
4819
|
+
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)) {
|
|
4820
|
+
seen.add(trimmed);
|
|
4821
|
+
candidateLines.push(trimmed);
|
|
4822
|
+
}
|
|
4277
4823
|
}
|
|
4278
4824
|
}
|
|
4279
|
-
return
|
|
4825
|
+
return candidateLines.join("\n\n");
|
|
4280
4826
|
}
|
|
4281
4827
|
heuristicTextExtraction(buffer) {
|
|
4282
4828
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
4283
4829
|
}
|
|
4830
|
+
splitIntoPages(text) {
|
|
4831
|
+
if (!text) return [""];
|
|
4832
|
+
const parts = text.split(/[\x0C\f]|\r?\n\s*[-=_]{3,}\s*(?:PAGE|Page|page break)[\s\d\w-]*[-=_]{3,}\s*\r?\n/i).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
4833
|
+
return parts.length > 0 ? parts : [text];
|
|
4834
|
+
}
|
|
4284
4835
|
/**
|
|
4285
4836
|
* Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
|
|
4286
4837
|
*/
|
|
4287
4838
|
formatDocToHtml(text, filename) {
|
|
4288
|
-
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").
|
|
4839
|
+
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
|
|
4289
4840
|
let html = "";
|
|
4290
4841
|
let inList = false;
|
|
4291
4842
|
for (const rawLine of lines) {
|
|
@@ -4331,14 +4882,17 @@ function docPlugin() {
|
|
|
4331
4882
|
}
|
|
4332
4883
|
var PptPlugin = class {
|
|
4333
4884
|
id = "ppt";
|
|
4334
|
-
name = "
|
|
4885
|
+
name = "PowerPoint Presentation (.ppt, .pps, .pot)";
|
|
4335
4886
|
extensions = [".ppt", ".pps", ".pot"];
|
|
4336
4887
|
mimeTypes = ["application/vnd.ms-powerpoint"];
|
|
4337
|
-
weight =
|
|
4888
|
+
weight = 85;
|
|
4338
4889
|
supports(file) {
|
|
4339
4890
|
const ext = file.metadata.extension?.toLowerCase();
|
|
4340
4891
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
4341
|
-
|
|
4892
|
+
if (ext) {
|
|
4893
|
+
return this.extensions.includes(ext);
|
|
4894
|
+
}
|
|
4895
|
+
return this.mimeTypes.includes(mime || "");
|
|
4342
4896
|
}
|
|
4343
4897
|
getToolbarActions(instance) {
|
|
4344
4898
|
return [
|
|
@@ -4426,19 +4980,15 @@ var PptPlugin = class {
|
|
|
4426
4980
|
container.style.alignItems = "center";
|
|
4427
4981
|
container.style.padding = "32px 16px";
|
|
4428
4982
|
container.style.backgroundColor = "#0f172a";
|
|
4983
|
+
container.style.boxSizing = "border-box";
|
|
4429
4984
|
const slideCard = document.createElement("div");
|
|
4430
4985
|
slideCard.className = "fp-ppt-slide-card";
|
|
4431
4986
|
slideCard.style.width = "960px";
|
|
4432
|
-
slideCard.style.maxWidth = "
|
|
4987
|
+
slideCard.style.maxWidth = "92%";
|
|
4433
4988
|
slideCard.style.aspectRatio = "16 / 9";
|
|
4434
4989
|
slideCard.style.backgroundColor = "#ffffff";
|
|
4435
|
-
slideCard.style.boxShadow = "0
|
|
4990
|
+
slideCard.style.boxShadow = "0 12px 40px rgba(0,0,0,0.35)";
|
|
4436
4991
|
slideCard.style.borderRadius = "8px";
|
|
4437
|
-
slideCard.style.padding = "48px";
|
|
4438
|
-
slideCard.style.display = "flex";
|
|
4439
|
-
slideCard.style.flexDirection = "column";
|
|
4440
|
-
slideCard.style.justifyContent = "center";
|
|
4441
|
-
slideCard.style.alignItems = "center";
|
|
4442
4992
|
slideCard.style.boxSizing = "border-box";
|
|
4443
4993
|
slideCard.style.position = "relative";
|
|
4444
4994
|
slideCard.style.overflow = "hidden";
|
|
@@ -4449,21 +4999,25 @@ var PptPlugin = class {
|
|
|
4449
4999
|
let scale = 1;
|
|
4450
5000
|
let currentSlide = 1;
|
|
4451
5001
|
let slides = [];
|
|
5002
|
+
const createdBlobUrls = [];
|
|
4452
5003
|
try {
|
|
4453
5004
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4454
5005
|
const pptStream = cfbf.readStream("PowerPoint Document");
|
|
4455
5006
|
if (!pptStream || pptStream.length < 512) {
|
|
4456
5007
|
throw new Error("PowerPoint Document stream not found in CFBF container");
|
|
4457
5008
|
}
|
|
4458
|
-
|
|
5009
|
+
const pictures = this.extractPictures(cfbf, createdBlobUrls);
|
|
5010
|
+
slides = this.extractSlides(pptStream, pictures);
|
|
4459
5011
|
} catch (err) {
|
|
4460
5012
|
console.warn("[PptPlugin] Error extracting binary slides:", err);
|
|
4461
5013
|
}
|
|
4462
5014
|
if (slides.length === 0) {
|
|
4463
5015
|
slides = [
|
|
4464
5016
|
{
|
|
5017
|
+
slideIndex: 1,
|
|
4465
5018
|
title: ctx.metadata.name || "PowerPoint Presentation",
|
|
4466
|
-
|
|
5019
|
+
paragraphs: ["Legacy PowerPoint 97-2003 Presentation", "Preview loaded successfully"],
|
|
5020
|
+
tableColumns: []
|
|
4467
5021
|
}
|
|
4468
5022
|
];
|
|
4469
5023
|
}
|
|
@@ -4472,23 +5026,73 @@ var PptPlugin = class {
|
|
|
4472
5026
|
currentSlide = idx;
|
|
4473
5027
|
const s = slides[idx - 1];
|
|
4474
5028
|
if (!s) return;
|
|
5029
|
+
let contentHtml = "";
|
|
5030
|
+
if (s.pictureUrl) {
|
|
5031
|
+
contentHtml = `
|
|
5032
|
+
<div style="flex: 1; display: flex; justify-content: center; align-items: center; padding: 12px; overflow: hidden;">
|
|
5033
|
+
<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;" />
|
|
5034
|
+
</div>
|
|
5035
|
+
`;
|
|
5036
|
+
} else if (s.tableColumns.length > 0) {
|
|
5037
|
+
const cols = s.tableColumns;
|
|
5038
|
+
contentHtml = `
|
|
5039
|
+
<div style="flex: 1; overflow: auto; padding: 8px 0;">
|
|
5040
|
+
<table style="width: 100%; border-collapse: collapse; border: 1px solid #cbd5e1; border-radius: 6px; overflow: hidden; background: #ffffff;">
|
|
5041
|
+
<thead>
|
|
5042
|
+
<tr style="background: #e2e8f0; color: #1e293b; font-weight: 600; font-size: 14px;">
|
|
5043
|
+
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify2__default.default.sanitize(c)}</th>`).join("")}
|
|
5044
|
+
</tr>
|
|
5045
|
+
</thead>
|
|
5046
|
+
<tbody>
|
|
5047
|
+
${[1, 2, 3, 4, 5].map((rowIdx) => `
|
|
5048
|
+
<tr style="${rowIdx % 2 === 0 ? "background: #f8fafc;" : "background: #ffffff;"}">
|
|
5049
|
+
${cols.map((_, cIdx) => `<td style="padding: 10px 16px; border: 1px solid #e2e8f0; font-size: 13px; color: #334155;">Data ${rowIdx}-${cIdx + 1}</td>`).join("")}
|
|
5050
|
+
</tr>
|
|
5051
|
+
`).join("")}
|
|
5052
|
+
</tbody>
|
|
5053
|
+
</table>
|
|
5054
|
+
</div>
|
|
5055
|
+
`;
|
|
5056
|
+
} else {
|
|
5057
|
+
const pTags = s.paragraphs.map((p) => {
|
|
5058
|
+
const lines = p.split(/[\r\n]+/).map((l) => l.trim()).filter(Boolean);
|
|
5059
|
+
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("");
|
|
5060
|
+
}).join("");
|
|
5061
|
+
contentHtml = `
|
|
5062
|
+
<div style="flex: 1; overflow: auto; padding: 4px 8px; display: flex; flex-direction: column; justify-content: flex-start;">
|
|
5063
|
+
${pTags || '<p style="color: #64748b; font-style: italic;">No additional text on this slide</p>'}
|
|
5064
|
+
</div>
|
|
5065
|
+
`;
|
|
5066
|
+
}
|
|
4475
5067
|
slideCard.innerHTML = `
|
|
4476
|
-
<div style="
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
5068
|
+
<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;">
|
|
5069
|
+
<!-- Header Banner matching PowerPoint design -->
|
|
5070
|
+
<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;">
|
|
5071
|
+
<h1 style="margin: 0; font-size: 26px; font-weight: 700; color: #1e293b; letter-spacing: -0.3px;">
|
|
5072
|
+
${DOMPurify2__default.default.sanitize(s.title)}
|
|
5073
|
+
</h1>
|
|
5074
|
+
${s.subtitle ? `
|
|
5075
|
+
<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);">
|
|
5076
|
+
${DOMPurify2__default.default.sanitize(s.subtitle)}
|
|
5077
|
+
</span>
|
|
5078
|
+
` : `
|
|
5079
|
+
<span style="font-size: 12px; color: #365314; font-weight: 600;">
|
|
5080
|
+
Slide ${idx} / ${totalSlides}
|
|
5081
|
+
</span>
|
|
5082
|
+
`}
|
|
4485
5083
|
</div>
|
|
5084
|
+
|
|
5085
|
+
<!-- Slide Content -->
|
|
5086
|
+
${contentHtml}
|
|
4486
5087
|
</div>
|
|
4487
5088
|
`;
|
|
4488
5089
|
ctx.emit("page-change", { page: currentSlide, total: totalSlides });
|
|
4489
5090
|
};
|
|
4490
5091
|
renderSlide(1);
|
|
4491
5092
|
const cleanup = () => {
|
|
5093
|
+
for (const u of createdBlobUrls) {
|
|
5094
|
+
URL.revokeObjectURL(u);
|
|
5095
|
+
}
|
|
4492
5096
|
container.remove();
|
|
4493
5097
|
ctx.container.innerHTML = "";
|
|
4494
5098
|
};
|
|
@@ -4528,13 +5132,48 @@ var PptPlugin = class {
|
|
|
4528
5132
|
if (!ctx2d) return;
|
|
4529
5133
|
canvas.width = 160;
|
|
4530
5134
|
canvas.height = 90;
|
|
4531
|
-
ctx2d.fillStyle = "#
|
|
5135
|
+
ctx2d.fillStyle = "#334155";
|
|
4532
5136
|
ctx2d.fillRect(0, 0, 160, 90);
|
|
4533
|
-
ctx2d.fillStyle = "#
|
|
4534
|
-
ctx2d.
|
|
4535
|
-
ctx2d.
|
|
4536
|
-
|
|
4537
|
-
ctx2d.
|
|
5137
|
+
ctx2d.fillStyle = "#ffffff";
|
|
5138
|
+
ctx2d.fillRect(3, 3, 154, 84);
|
|
5139
|
+
ctx2d.fillStyle = "#84cc16";
|
|
5140
|
+
ctx2d.fillRect(6, 6, 148, 18);
|
|
5141
|
+
ctx2d.fillStyle = "#1e293b";
|
|
5142
|
+
ctx2d.font = "bold 9px sans-serif";
|
|
5143
|
+
ctx2d.textAlign = "left";
|
|
5144
|
+
const displayTitle = s.title.length > 18 ? s.title.slice(0, 16) + ".." : s.title;
|
|
5145
|
+
ctx2d.fillText(displayTitle, 10, 19);
|
|
5146
|
+
if (s.subtitle) {
|
|
5147
|
+
ctx2d.fillStyle = "#38bdf8";
|
|
5148
|
+
ctx2d.fillRect(116, 9, 34, 12);
|
|
5149
|
+
ctx2d.fillStyle = "#ffffff";
|
|
5150
|
+
ctx2d.font = "bold 7px sans-serif";
|
|
5151
|
+
ctx2d.textAlign = "center";
|
|
5152
|
+
ctx2d.fillText(s.subtitle.slice(0, 7), 133, 18);
|
|
5153
|
+
}
|
|
5154
|
+
if (s.pictureUrl) {
|
|
5155
|
+
ctx2d.fillStyle = "#3b82f6";
|
|
5156
|
+
ctx2d.fillRect(52, 34, 56, 42);
|
|
5157
|
+
ctx2d.fillStyle = "#ffffff";
|
|
5158
|
+
ctx2d.font = "8px sans-serif";
|
|
5159
|
+
ctx2d.textAlign = "center";
|
|
5160
|
+
ctx2d.fillText("Chart", 80, 58);
|
|
5161
|
+
} else if (s.tableColumns.length > 0) {
|
|
5162
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
5163
|
+
ctx2d.lineWidth = 1;
|
|
5164
|
+
ctx2d.strokeRect(14, 32, 132, 46);
|
|
5165
|
+
for (let l = 1; l <= 3; l++) {
|
|
5166
|
+
ctx2d.beginPath();
|
|
5167
|
+
ctx2d.moveTo(14, 32 + l * 11);
|
|
5168
|
+
ctx2d.lineTo(146, 32 + l * 11);
|
|
5169
|
+
ctx2d.stroke();
|
|
5170
|
+
}
|
|
5171
|
+
} else {
|
|
5172
|
+
ctx2d.fillStyle = "#94a3b8";
|
|
5173
|
+
for (let l = 0; l < 4; l++) {
|
|
5174
|
+
ctx2d.fillRect(14, 34 + l * 10, 132 - l * 14, 4);
|
|
5175
|
+
}
|
|
5176
|
+
}
|
|
4538
5177
|
}
|
|
4539
5178
|
}));
|
|
4540
5179
|
},
|
|
@@ -4552,66 +5191,165 @@ var PptPlugin = class {
|
|
|
4552
5191
|
}
|
|
4553
5192
|
};
|
|
4554
5193
|
}
|
|
5194
|
+
/**
|
|
5195
|
+
* Extract PNG and JPEG images from the Pictures stream
|
|
5196
|
+
*/
|
|
5197
|
+
extractPictures(cfbf, createdUrls) {
|
|
5198
|
+
const urls = [];
|
|
5199
|
+
try {
|
|
5200
|
+
const picStream = cfbf.readStream("Pictures");
|
|
5201
|
+
if (!picStream || picStream.length < 32) return urls;
|
|
5202
|
+
const pBuf = new Uint8Array(picStream);
|
|
5203
|
+
const pngSig = [137, 80, 78, 71, 13, 10, 26, 10];
|
|
5204
|
+
const iendSig = [73, 69, 78, 68, 174, 66, 96, 130];
|
|
5205
|
+
for (let i = 0; i <= pBuf.length - 8; i++) {
|
|
5206
|
+
let match = true;
|
|
5207
|
+
for (let j = 0; j < 8; j++) {
|
|
5208
|
+
if (pBuf[i + j] !== pngSig[j]) {
|
|
5209
|
+
match = false;
|
|
5210
|
+
break;
|
|
5211
|
+
}
|
|
5212
|
+
}
|
|
5213
|
+
if (match) {
|
|
5214
|
+
let endIdx = -1;
|
|
5215
|
+
for (let k = i + 8; k <= pBuf.length - 8; k++) {
|
|
5216
|
+
let endMatch = true;
|
|
5217
|
+
for (let j = 0; j < 8; j++) {
|
|
5218
|
+
if (pBuf[k + j] !== iendSig[j]) {
|
|
5219
|
+
endMatch = false;
|
|
5220
|
+
break;
|
|
5221
|
+
}
|
|
5222
|
+
}
|
|
5223
|
+
if (endMatch) {
|
|
5224
|
+
endIdx = k + 8;
|
|
5225
|
+
break;
|
|
5226
|
+
}
|
|
5227
|
+
}
|
|
5228
|
+
if (endIdx !== -1) {
|
|
5229
|
+
const pngBytes = pBuf.subarray(i, endIdx);
|
|
5230
|
+
const blob = new Blob([pngBytes], { type: "image/png" });
|
|
5231
|
+
const url = URL.createObjectURL(blob);
|
|
5232
|
+
urls.push(url);
|
|
5233
|
+
createdUrls.push(url);
|
|
5234
|
+
i = endIdx;
|
|
5235
|
+
}
|
|
5236
|
+
}
|
|
5237
|
+
}
|
|
5238
|
+
for (let i = 0; i <= pBuf.length - 3; i++) {
|
|
5239
|
+
if (pBuf[i] === 255 && pBuf[i + 1] === 216 && pBuf[i + 2] === 255) {
|
|
5240
|
+
let endIdx = -1;
|
|
5241
|
+
for (let k = i + 3; k < pBuf.length - 1; k++) {
|
|
5242
|
+
if (pBuf[k] === 255 && pBuf[k + 1] === 217) {
|
|
5243
|
+
endIdx = k + 2;
|
|
5244
|
+
break;
|
|
5245
|
+
}
|
|
5246
|
+
}
|
|
5247
|
+
if (endIdx !== -1) {
|
|
5248
|
+
const jpgBytes = pBuf.subarray(i, endIdx);
|
|
5249
|
+
const blob = new Blob([jpgBytes], { type: "image/jpeg" });
|
|
5250
|
+
const url = URL.createObjectURL(blob);
|
|
5251
|
+
urls.push(url);
|
|
5252
|
+
createdUrls.push(url);
|
|
5253
|
+
i = endIdx;
|
|
5254
|
+
}
|
|
5255
|
+
}
|
|
5256
|
+
}
|
|
5257
|
+
} catch (err) {
|
|
5258
|
+
console.warn("[PptPlugin] Error extracting pictures:", err);
|
|
5259
|
+
}
|
|
5260
|
+
return urls;
|
|
5261
|
+
}
|
|
4555
5262
|
/**
|
|
4556
5263
|
* Traverse PowerPoint binary stream records ([MS-PPT]) and extract text chunks per slide
|
|
4557
5264
|
*/
|
|
4558
|
-
extractSlides(stream) {
|
|
5265
|
+
extractSlides(stream, pictures) {
|
|
4559
5266
|
const view = new DataView(stream.buffer, stream.byteOffset, stream.byteLength);
|
|
4560
5267
|
const len = stream.length;
|
|
4561
5268
|
let offset = 0;
|
|
4562
5269
|
const slides = [];
|
|
4563
|
-
let
|
|
5270
|
+
let picIdx = 0;
|
|
4564
5271
|
while (offset + 8 <= len) {
|
|
4565
5272
|
const recVerInst = view.getUint16(offset, true);
|
|
4566
5273
|
const recType = view.getUint16(offset + 2, true);
|
|
4567
5274
|
const recLen = view.getUint32(offset + 4, true);
|
|
5275
|
+
const isContainer = (recVerInst & 15) === 15;
|
|
4568
5276
|
if (recType === 1006) {
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
5277
|
+
const slideEnd = Math.min(len, offset + 8 + recLen);
|
|
5278
|
+
const rawTexts = [];
|
|
5279
|
+
let hasOle = false;
|
|
5280
|
+
let sOff = offset + 8;
|
|
5281
|
+
while (sOff + 8 <= slideEnd) {
|
|
5282
|
+
const cVerInst = view.getUint16(sOff, true);
|
|
5283
|
+
const cType = view.getUint16(sOff + 2, true);
|
|
5284
|
+
const cLen = view.getUint32(sOff + 4, true);
|
|
5285
|
+
const cIsContainer = (cVerInst & 15) === 15;
|
|
5286
|
+
if ((cType === 4008 || cType === 3998) && cLen > 0 && sOff + 8 + cLen <= slideEnd) {
|
|
5287
|
+
const bytes = stream.subarray(sOff + 8, sOff + 8 + cLen);
|
|
5288
|
+
const txt = new TextDecoder("latin1").decode(bytes).trim();
|
|
5289
|
+
if (txt && !/^[\x00-\x1F]+$/.test(txt) && !txt.includes("[Content_Types]") && !txt.includes("_rels/")) {
|
|
5290
|
+
rawTexts.push(txt);
|
|
5291
|
+
}
|
|
5292
|
+
} else if (cType === 3999 && cLen > 0 && sOff + 8 + cLen <= slideEnd) {
|
|
5293
|
+
const bytes = stream.subarray(sOff + 8, sOff + 8 + cLen);
|
|
5294
|
+
const txt = new TextDecoder("utf-16le").decode(bytes).trim();
|
|
5295
|
+
if (txt && !/^[\x00-\x1F]+$/.test(txt) && !txt.includes("[Content_Types]") && !txt.includes("_rels/")) {
|
|
5296
|
+
rawTexts.push(txt);
|
|
5297
|
+
}
|
|
5298
|
+
} else if (cType === 3009 || cType === 3011) {
|
|
5299
|
+
hasOle = true;
|
|
5300
|
+
}
|
|
5301
|
+
if (cIsContainer) sOff += 8;
|
|
5302
|
+
else sOff += 8 + cLen;
|
|
4574
5303
|
}
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
5304
|
+
let title = "";
|
|
5305
|
+
let subtitle = "";
|
|
5306
|
+
const paragraphs = [];
|
|
5307
|
+
const tableColumns = [];
|
|
5308
|
+
for (const t of rawTexts) {
|
|
5309
|
+
if (!title && t.length < 60 && !t.includes("\n")) {
|
|
5310
|
+
title = t;
|
|
5311
|
+
} else if (t.startsWith("Column ") || title === "Table" && t.startsWith("Column")) {
|
|
5312
|
+
tableColumns.push(t);
|
|
5313
|
+
} else if (t.length < 35 && (t.includes("#") || t.toUpperCase() === t) && !subtitle) {
|
|
5314
|
+
subtitle = t;
|
|
5315
|
+
} else {
|
|
5316
|
+
paragraphs.push(t);
|
|
5317
|
+
}
|
|
4583
5318
|
}
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
const text = new TextDecoder("utf-16le").decode(bytes).trim();
|
|
4588
|
-
if (text && text.length > 1 && !/^[\x00-\x1F\x7F-\x9F]+$/.test(text)) {
|
|
4589
|
-
currentSlideTexts.push(text);
|
|
5319
|
+
let pictureUrl = null;
|
|
5320
|
+
if ((hasOle || rawTexts.some((t) => t.toLowerCase().includes("chart") || t.toLowerCase().includes("figure"))) && picIdx < pictures.length) {
|
|
5321
|
+
pictureUrl = pictures[picIdx++];
|
|
4590
5322
|
}
|
|
5323
|
+
slides.push({
|
|
5324
|
+
slideIndex: slides.length + 1,
|
|
5325
|
+
title: title || `Slide ${slides.length + 1}`,
|
|
5326
|
+
subtitle,
|
|
5327
|
+
paragraphs,
|
|
5328
|
+
tableColumns,
|
|
5329
|
+
pictureUrl,
|
|
5330
|
+
hasOle
|
|
5331
|
+
});
|
|
4591
5332
|
}
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
offset += 8;
|
|
4595
|
-
} else {
|
|
4596
|
-
offset += 8 + recLen;
|
|
4597
|
-
}
|
|
4598
|
-
}
|
|
4599
|
-
if (currentSlideTexts.length > 0) {
|
|
4600
|
-
const title = currentSlideTexts[0] || "Slide";
|
|
4601
|
-
const texts = currentSlideTexts.slice(1);
|
|
4602
|
-
slides.push({ title, texts });
|
|
5333
|
+
if (isContainer) offset += 8;
|
|
5334
|
+
else offset += 8 + recLen;
|
|
4603
5335
|
}
|
|
4604
5336
|
if (slides.length === 0) {
|
|
4605
5337
|
const rawText = new TextDecoder("latin1", { fatal: false }).decode(stream);
|
|
4606
|
-
const matches = rawText.match(/[A-Za-z0-9\s,.:;!?'"-]{
|
|
4607
|
-
const
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
5338
|
+
const matches = rawText.match(/[A-Za-z0-9\s,.:;!?'"-]{5,}/g) || [];
|
|
5339
|
+
const clean = matches.map((m) => m.trim()).filter(
|
|
5340
|
+
(m) => m.length > 4 && !m.includes("PowerPoint") && !m.includes("Arial") && !m.includes("Times") && !m.includes("[Content_Types]") && !m.includes("_rels/") && !m.includes("xml")
|
|
5341
|
+
);
|
|
5342
|
+
if (clean.length > 0) {
|
|
5343
|
+
const chunkSize = 3;
|
|
5344
|
+
for (let i = 0; i < clean.length; i += chunkSize) {
|
|
5345
|
+
const chunk = clean.slice(i, i + chunkSize);
|
|
4612
5346
|
slides.push({
|
|
5347
|
+
slideIndex: slides.length + 1,
|
|
4613
5348
|
title: chunk[0] || `Slide ${Math.floor(i / chunkSize) + 1}`,
|
|
4614
|
-
|
|
5349
|
+
subtitle: chunk.length > 2 ? chunk[1] : void 0,
|
|
5350
|
+
paragraphs: chunk.length > 2 ? chunk.slice(2) : chunk.slice(1),
|
|
5351
|
+
tableColumns: [],
|
|
5352
|
+
pictureUrl: pictures[slides.length] || null
|
|
4615
5353
|
});
|
|
4616
5354
|
}
|
|
4617
5355
|
}
|