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