@files-preview-app/preview-file 1.2.5 → 1.2.7
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 +933 -208
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.js +932 -207
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +934 -209
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +933 -208
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +933 -208
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +932 -207
- package/dist/react.js.map +1 -1
- package/dist/styles.css +28 -1
- package/dist/vue.cjs +933 -208
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +932 -207
- package/dist/vue.js.map +1 -1
- package/package.json +179 -169
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var DOMPurify6 = require('dompurify');
|
|
4
4
|
var pdfjsLib = require('pdfjs-dist');
|
|
5
5
|
var docx = require('docx-preview');
|
|
6
6
|
var fflate = require('fflate');
|
|
@@ -34,7 +34,7 @@ function _interopNamespace(e) {
|
|
|
34
34
|
return Object.freeze(n);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
var
|
|
37
|
+
var DOMPurify6__default = /*#__PURE__*/_interopDefault(DOMPurify6);
|
|
38
38
|
var pdfjsLib__namespace = /*#__PURE__*/_interopNamespace(pdfjsLib);
|
|
39
39
|
var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
|
|
40
40
|
var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
|
|
@@ -386,7 +386,7 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
386
386
|
if (magicMime === "application/zip") {
|
|
387
387
|
const ooxmlMime = detectOoxmlType(buffer);
|
|
388
388
|
if (ooxmlMime && ooxmlMime !== "application/zip") {
|
|
389
|
-
metadata.mimeType = ooxmlMime;
|
|
389
|
+
metadata.mimeType = metadata.mimeType ?? ooxmlMime;
|
|
390
390
|
if (ooxmlMime.includes("wordprocessing")) metadata.extension = metadata.extension ?? ".docx";
|
|
391
391
|
else if (ooxmlMime.includes("spreadsheet")) metadata.extension = metadata.extension ?? ".xlsx";
|
|
392
392
|
else if (ooxmlMime.includes("presentation")) metadata.extension = metadata.extension ?? ".pptx";
|
|
@@ -415,12 +415,12 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
415
415
|
return { buffer, metadata };
|
|
416
416
|
}
|
|
417
417
|
function sanitizeHTML(html) {
|
|
418
|
-
return
|
|
418
|
+
return DOMPurify6__default.default.sanitize(html, {
|
|
419
419
|
USE_PROFILES: { html: true }
|
|
420
420
|
});
|
|
421
421
|
}
|
|
422
422
|
function sanitizeSVG(svg) {
|
|
423
|
-
return
|
|
423
|
+
return DOMPurify6__default.default.sanitize(svg, {
|
|
424
424
|
USE_PROFILES: { svg: true, svgFilters: true }
|
|
425
425
|
});
|
|
426
426
|
}
|
|
@@ -778,6 +778,8 @@ var FilePreviewViewer = class {
|
|
|
778
778
|
keyHandler = null;
|
|
779
779
|
currentContainer = null;
|
|
780
780
|
currentOptions = {};
|
|
781
|
+
resizeObserver = null;
|
|
782
|
+
fullscreenHandler = null;
|
|
781
783
|
/**
|
|
782
784
|
* Register a preview plugin.
|
|
783
785
|
*/
|
|
@@ -850,12 +852,31 @@ var FilePreviewViewer = class {
|
|
|
850
852
|
label: "Toggle Fullscreen",
|
|
851
853
|
type: "button",
|
|
852
854
|
group: "view",
|
|
853
|
-
execute: () => {
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
855
|
+
execute: async () => {
|
|
856
|
+
try {
|
|
857
|
+
const isNativeFs = !!document.fullscreenElement;
|
|
858
|
+
const isCssFs = this.wrapperEl?.classList.contains("fp-fullscreen-active");
|
|
859
|
+
if (!isNativeFs && !isCssFs) {
|
|
860
|
+
if (this.wrapperEl?.requestFullscreen) {
|
|
861
|
+
await this.wrapperEl.requestFullscreen().catch(() => {
|
|
862
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
863
|
+
});
|
|
864
|
+
} else {
|
|
865
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
866
|
+
}
|
|
867
|
+
} else {
|
|
868
|
+
if (document.fullscreenElement) {
|
|
869
|
+
await document.exitFullscreen().catch(() => {
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
873
|
+
}
|
|
874
|
+
} catch {
|
|
875
|
+
this.wrapperEl?.classList.toggle("fp-fullscreen-active");
|
|
858
876
|
}
|
|
877
|
+
setTimeout(() => {
|
|
878
|
+
this.activeInstance?.fitToPage?.();
|
|
879
|
+
}, 120);
|
|
859
880
|
}
|
|
860
881
|
});
|
|
861
882
|
}
|
|
@@ -905,6 +926,15 @@ var FilePreviewViewer = class {
|
|
|
905
926
|
window.removeEventListener("keydown", this.keyHandler);
|
|
906
927
|
this.keyHandler = null;
|
|
907
928
|
}
|
|
929
|
+
if (this.resizeObserver) {
|
|
930
|
+
this.resizeObserver.disconnect();
|
|
931
|
+
this.resizeObserver = null;
|
|
932
|
+
}
|
|
933
|
+
if (this.fullscreenHandler) {
|
|
934
|
+
document.removeEventListener("fullscreenchange", this.fullscreenHandler);
|
|
935
|
+
document.removeEventListener("webkitfullscreenchange", this.fullscreenHandler);
|
|
936
|
+
this.fullscreenHandler = null;
|
|
937
|
+
}
|
|
908
938
|
this.abort();
|
|
909
939
|
this.destroyInstance();
|
|
910
940
|
this.toolbar?.destroy();
|
|
@@ -984,6 +1014,25 @@ var FilePreviewViewer = class {
|
|
|
984
1014
|
this.thumbnailPanel = new ThumbnailPanel(thumbnailEl);
|
|
985
1015
|
this.setupKeyboardShortcuts();
|
|
986
1016
|
this.setupDragAndDrop(container, options);
|
|
1017
|
+
this.setupResizeAndFullscreenListeners();
|
|
1018
|
+
}
|
|
1019
|
+
setupResizeAndFullscreenListeners() {
|
|
1020
|
+
if (this.fullscreenHandler) return;
|
|
1021
|
+
this.fullscreenHandler = () => {
|
|
1022
|
+
setTimeout(() => {
|
|
1023
|
+
this.activeInstance?.fitToPage?.();
|
|
1024
|
+
}, 100);
|
|
1025
|
+
};
|
|
1026
|
+
document.addEventListener("fullscreenchange", this.fullscreenHandler);
|
|
1027
|
+
document.addEventListener("webkitfullscreenchange", this.fullscreenHandler);
|
|
1028
|
+
if (typeof ResizeObserver !== "undefined" && this.contentEl) {
|
|
1029
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
1030
|
+
if (this.activeInstance && (!this.activeInstance.getZoom || Math.abs((this.activeInstance.getZoom?.() ?? 1) - 1) < 0.05)) {
|
|
1031
|
+
this.activeInstance.fitToPage?.();
|
|
1032
|
+
}
|
|
1033
|
+
});
|
|
1034
|
+
this.resizeObserver.observe(this.contentEl);
|
|
1035
|
+
}
|
|
987
1036
|
}
|
|
988
1037
|
setupKeyboardShortcuts() {
|
|
989
1038
|
if (this.keyHandler) return;
|
|
@@ -1375,7 +1424,8 @@ var PdfPlugin = class {
|
|
|
1375
1424
|
container.style.display = "flex";
|
|
1376
1425
|
container.style.flexDirection = "column";
|
|
1377
1426
|
container.style.alignItems = "center";
|
|
1378
|
-
container.style.
|
|
1427
|
+
container.style.justifyContent = "flex-start";
|
|
1428
|
+
container.style.padding = "20px 16px";
|
|
1379
1429
|
container.style.backgroundColor = "#0f172a";
|
|
1380
1430
|
container.style.boxSizing = "border-box";
|
|
1381
1431
|
container.style.position = "relative";
|
|
@@ -1388,7 +1438,8 @@ var PdfPlugin = class {
|
|
|
1388
1438
|
pageCard.style.lineHeight = "0";
|
|
1389
1439
|
pageCard.style.transition = "transform 0.15s ease";
|
|
1390
1440
|
pageCard.style.position = "relative";
|
|
1391
|
-
|
|
1441
|
+
pageCard.style.flexShrink = "0";
|
|
1442
|
+
let canvas = document.createElement("canvas");
|
|
1392
1443
|
pageCard.appendChild(canvas);
|
|
1393
1444
|
container.appendChild(pageCard);
|
|
1394
1445
|
const indicator = document.createElement("div");
|
|
@@ -1430,14 +1481,22 @@ var PdfPlugin = class {
|
|
|
1430
1481
|
}
|
|
1431
1482
|
currentRenderTask = null;
|
|
1432
1483
|
}
|
|
1484
|
+
const newCanvas = document.createElement("canvas");
|
|
1485
|
+
pageCard.replaceChild(newCanvas, canvas);
|
|
1486
|
+
canvas = newCanvas;
|
|
1433
1487
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1434
1488
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1435
1489
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1436
1490
|
const page = await pdfDoc.getPage(currentPage);
|
|
1437
1491
|
const containerWidth = container.clientWidth || 900;
|
|
1492
|
+
const containerHeight = container.clientHeight || 700;
|
|
1438
1493
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1439
|
-
const
|
|
1440
|
-
const
|
|
1494
|
+
const availWidth = Math.max(100, containerWidth - 48);
|
|
1495
|
+
const availHeight = Math.max(100, containerHeight - 88);
|
|
1496
|
+
const scaleW = availWidth / unscaledVp.width;
|
|
1497
|
+
const scaleH = availHeight / unscaledVp.height;
|
|
1498
|
+
const fitScale = Math.min(scaleW, scaleH);
|
|
1499
|
+
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1441
1500
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
1442
1501
|
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
1443
1502
|
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
@@ -1462,7 +1521,19 @@ var PdfPlugin = class {
|
|
|
1462
1521
|
}
|
|
1463
1522
|
};
|
|
1464
1523
|
await renderPage(1);
|
|
1524
|
+
let resizeTimer = null;
|
|
1525
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
1526
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1527
|
+
resizeTimer = setTimeout(() => {
|
|
1528
|
+
if (Math.abs(zoomScale - 1) < 0.05) {
|
|
1529
|
+
renderPage(currentPage);
|
|
1530
|
+
}
|
|
1531
|
+
}, 150);
|
|
1532
|
+
});
|
|
1533
|
+
resizeObserver.observe(container);
|
|
1465
1534
|
const cleanup = () => {
|
|
1535
|
+
resizeObserver.disconnect();
|
|
1536
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1466
1537
|
if (currentRenderTask) {
|
|
1467
1538
|
try {
|
|
1468
1539
|
currentRenderTask.cancel();
|
|
@@ -1494,6 +1565,7 @@ var PdfPlugin = class {
|
|
|
1494
1565
|
},
|
|
1495
1566
|
fitToPage: () => {
|
|
1496
1567
|
zoomScale = 1;
|
|
1568
|
+
rotation = 0;
|
|
1497
1569
|
renderPage(currentPage);
|
|
1498
1570
|
},
|
|
1499
1571
|
rotateCW: () => {
|
|
@@ -1944,6 +2016,14 @@ var DocxPlugin = class {
|
|
|
1944
2016
|
group: "zoom",
|
|
1945
2017
|
execute: () => instance.fitToPage?.()
|
|
1946
2018
|
},
|
|
2019
|
+
{
|
|
2020
|
+
id: "rotate-cw",
|
|
2021
|
+
icon: "rotate-cw",
|
|
2022
|
+
label: "Rotate",
|
|
2023
|
+
type: "button",
|
|
2024
|
+
group: "view",
|
|
2025
|
+
execute: () => instance.rotateCW?.()
|
|
2026
|
+
},
|
|
1947
2027
|
{
|
|
1948
2028
|
id: "download",
|
|
1949
2029
|
icon: "download",
|
|
@@ -2080,6 +2160,26 @@ var DocxPlugin = class {
|
|
|
2080
2160
|
if (totalPages > 1) {
|
|
2081
2161
|
showPage(1);
|
|
2082
2162
|
}
|
|
2163
|
+
scale = 1;
|
|
2164
|
+
let rotation = 0;
|
|
2165
|
+
const calculateFitScale = () => {
|
|
2166
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.firstElementChild || wrapper;
|
|
2167
|
+
const elW = activeEl.offsetWidth || 816;
|
|
2168
|
+
const elH = activeEl.offsetHeight || 1056;
|
|
2169
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
2170
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
2171
|
+
const sW = availW / elW;
|
|
2172
|
+
const sH = availH / elH;
|
|
2173
|
+
return Math.min(1.1, Math.min(sW, sH));
|
|
2174
|
+
};
|
|
2175
|
+
const applyTransform = () => {
|
|
2176
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2177
|
+
wrapper.style.transformOrigin = "top center";
|
|
2178
|
+
};
|
|
2179
|
+
setTimeout(() => {
|
|
2180
|
+
scale = calculateFitScale();
|
|
2181
|
+
applyTransform();
|
|
2182
|
+
}, 60);
|
|
2083
2183
|
const cleanup = () => {
|
|
2084
2184
|
indicator?.remove();
|
|
2085
2185
|
for (const url of createdBlobUrls) {
|
|
@@ -2098,21 +2198,30 @@ var DocxPlugin = class {
|
|
|
2098
2198
|
showPage(page);
|
|
2099
2199
|
},
|
|
2100
2200
|
zoomIn: () => {
|
|
2101
|
-
scale += 0.
|
|
2102
|
-
|
|
2201
|
+
scale += 0.15;
|
|
2202
|
+
applyTransform();
|
|
2103
2203
|
},
|
|
2104
2204
|
zoomOut: () => {
|
|
2105
|
-
scale = Math.max(0.2, scale - 0.
|
|
2106
|
-
|
|
2205
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
2206
|
+
applyTransform();
|
|
2107
2207
|
},
|
|
2108
2208
|
getZoom: () => scale,
|
|
2109
2209
|
setZoom: (level) => {
|
|
2110
2210
|
scale = level;
|
|
2111
|
-
|
|
2211
|
+
applyTransform();
|
|
2112
2212
|
},
|
|
2113
2213
|
fitToPage: () => {
|
|
2114
|
-
scale =
|
|
2115
|
-
|
|
2214
|
+
scale = calculateFitScale();
|
|
2215
|
+
rotation = 0;
|
|
2216
|
+
applyTransform();
|
|
2217
|
+
},
|
|
2218
|
+
rotateCW: () => {
|
|
2219
|
+
rotation = (rotation + 90) % 360;
|
|
2220
|
+
applyTransform();
|
|
2221
|
+
},
|
|
2222
|
+
rotateCCW: () => {
|
|
2223
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
2224
|
+
applyTransform();
|
|
2116
2225
|
},
|
|
2117
2226
|
download: () => {
|
|
2118
2227
|
const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
|
|
@@ -2172,90 +2281,149 @@ var DocxPlugin = class {
|
|
|
2172
2281
|
console.warn("[DocxPlugin] Error parsing relationships:", relsErr);
|
|
2173
2282
|
}
|
|
2174
2283
|
}
|
|
2175
|
-
const
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2284
|
+
const sectPrs = Array.from(doc.getElementsByTagNameNS("*", "sectPr"));
|
|
2285
|
+
const lastSectPr = sectPrs[sectPrs.length - 1];
|
|
2286
|
+
let defaultW = 12240;
|
|
2287
|
+
let defaultH = 15840;
|
|
2288
|
+
let margins = { top: 1440, right: 1440, bottom: 1440, left: 1440 };
|
|
2289
|
+
if (lastSectPr) {
|
|
2290
|
+
const pgSz = lastSectPr.getElementsByTagNameNS("*", "pgSz")[0];
|
|
2291
|
+
if (pgSz) {
|
|
2292
|
+
defaultW = parseInt(pgSz.getAttribute("w:w") || pgSz.getAttribute("w") || "12240", 10);
|
|
2293
|
+
defaultH = parseInt(pgSz.getAttribute("w:h") || pgSz.getAttribute("h") || "15840", 10);
|
|
2294
|
+
}
|
|
2295
|
+
const pgMar = lastSectPr.getElementsByTagNameNS("*", "pgMar")[0];
|
|
2296
|
+
if (pgMar) {
|
|
2297
|
+
margins.top = parseInt(pgMar.getAttribute("w:top") || pgMar.getAttribute("top") || "1440", 10);
|
|
2298
|
+
margins.bottom = parseInt(pgMar.getAttribute("w:bottom") || pgMar.getAttribute("bottom") || "1440", 10);
|
|
2299
|
+
margins.left = parseInt(pgMar.getAttribute("w:left") || pgMar.getAttribute("left") || "1440", 10);
|
|
2300
|
+
margins.right = parseInt(pgMar.getAttribute("w:right") || pgMar.getAttribute("right") || "1440", 10);
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2303
|
+
const createPageCard = () => {
|
|
2304
|
+
const card = document.createElement("div");
|
|
2305
|
+
card.className = "fp-docx-page-card";
|
|
2306
|
+
card.style.backgroundColor = "#ffffff";
|
|
2307
|
+
card.style.borderRadius = "4px";
|
|
2308
|
+
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
2309
|
+
card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
2310
|
+
card.style.color = "#1e293b";
|
|
2311
|
+
card.style.lineHeight = "1.6";
|
|
2312
|
+
card.style.boxSizing = "border-box";
|
|
2313
|
+
card.style.overflow = "hidden";
|
|
2314
|
+
card.style.position = "relative";
|
|
2315
|
+
card.style.marginBottom = "24px";
|
|
2316
|
+
card.style.width = `${defaultW / 15}px`;
|
|
2317
|
+
card.style.height = `${defaultH / 15}px`;
|
|
2318
|
+
card.style.padding = `${margins.top / 15}px ${margins.right / 15}px ${margins.bottom / 15}px ${margins.left / 15}px`;
|
|
2319
|
+
return card;
|
|
2320
|
+
};
|
|
2321
|
+
let currentCard = createPageCard();
|
|
2322
|
+
let currentHtml = "";
|
|
2323
|
+
const pages = [{ card: currentCard, html: "" }];
|
|
2324
|
+
const flushHtml = () => {
|
|
2325
|
+
pages[pages.length - 1].html += currentHtml;
|
|
2326
|
+
currentHtml = "";
|
|
2327
|
+
};
|
|
2328
|
+
const newPage = () => {
|
|
2329
|
+
flushHtml();
|
|
2330
|
+
currentCard = createPageCard();
|
|
2331
|
+
pages.push({ card: currentCard, html: "" });
|
|
2332
|
+
};
|
|
2184
2333
|
const body = doc.getElementsByTagNameNS("*", "body")[0] || doc.documentElement;
|
|
2185
|
-
let html = "";
|
|
2186
2334
|
for (const child of Array.from(body.children)) {
|
|
2187
2335
|
const tag = child.localName || child.nodeName.split(":").pop();
|
|
2188
2336
|
if (tag === "p") {
|
|
2189
2337
|
const pStyle = child.getElementsByTagNameNS("*", "pStyle")[0];
|
|
2190
2338
|
const styleVal = pStyle?.getAttribute("w:val") || pStyle?.getAttribute("val") || "";
|
|
2191
2339
|
const numPr = child.getElementsByTagNameNS("*", "numPr")[0];
|
|
2192
|
-
const
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2340
|
+
const chunks = this.extractParagraphChunks(child, imageMap);
|
|
2341
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
2342
|
+
if (i > 0) {
|
|
2343
|
+
newPage();
|
|
2344
|
+
}
|
|
2345
|
+
const textContent = chunks[i];
|
|
2346
|
+
if (!textContent.trim() && !textContent.includes("<img")) {
|
|
2347
|
+
currentHtml += '<div style="height: 10px;"></div>';
|
|
2348
|
+
continue;
|
|
2349
|
+
}
|
|
2350
|
+
const lowerStyle = styleVal.toLowerCase();
|
|
2351
|
+
if (lowerStyle.includes("title")) {
|
|
2352
|
+
currentHtml += `<h1 style="font-size: 28px; font-weight: 700; color: #1e3a8a; margin: 24px 0 12px; border-bottom: 2px solid #e2e8f0; padding-bottom: 8px;">${textContent}</h1>`;
|
|
2353
|
+
} else if (lowerStyle.includes("heading1") || styleVal === "1") {
|
|
2354
|
+
currentHtml += `<h2 style="font-size: 22px; font-weight: 700; color: #1e40af; margin: 20px 0 10px;">${textContent}</h2>`;
|
|
2355
|
+
} else if (lowerStyle.includes("heading2") || styleVal === "2") {
|
|
2356
|
+
currentHtml += `<h3 style="font-size: 18px; font-weight: 600; color: #2563eb; margin: 16px 0 8px;">${textContent}</h3>`;
|
|
2357
|
+
} else if (lowerStyle.includes("heading3") || styleVal === "3") {
|
|
2358
|
+
currentHtml += `<h4 style="font-size: 15px; font-weight: 600; color: #334155; margin: 12px 0 6px;">${textContent}</h4>`;
|
|
2359
|
+
} else if (numPr) {
|
|
2360
|
+
currentHtml += `<div style="display: flex; gap: 8px; margin: 4px 0 4px 20px;"><span style="color: #2563eb; font-weight: bold;">\u2022</span><span>${textContent}</span></div>`;
|
|
2361
|
+
} else {
|
|
2362
|
+
currentHtml += `<p style="margin: 8px 0; font-size: 14px;">${textContent}</p>`;
|
|
2363
|
+
}
|
|
2210
2364
|
}
|
|
2211
2365
|
} else if (tag === "tbl") {
|
|
2212
|
-
|
|
2366
|
+
currentHtml += '<table style="width: 100%; border-collapse: collapse; margin: 20px 0; border: 1px solid #cbd5e1;">';
|
|
2213
2367
|
const rows = Array.from(child.getElementsByTagNameNS("*", "tr"));
|
|
2214
2368
|
rows.forEach((tr, rIdx) => {
|
|
2215
|
-
|
|
2369
|
+
currentHtml += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
|
|
2216
2370
|
const cells = Array.from(tr.getElementsByTagNameNS("*", "tc"));
|
|
2217
2371
|
cells.forEach((tc) => {
|
|
2218
2372
|
const cellText = this.extractParagraphHtml(tc, imageMap);
|
|
2219
|
-
|
|
2373
|
+
currentHtml += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || " "}</td>`;
|
|
2220
2374
|
});
|
|
2221
|
-
|
|
2375
|
+
currentHtml += "</tr>";
|
|
2222
2376
|
});
|
|
2223
|
-
|
|
2377
|
+
currentHtml += "</table>";
|
|
2224
2378
|
}
|
|
2225
2379
|
}
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2380
|
+
flushHtml();
|
|
2381
|
+
for (const page of pages) {
|
|
2382
|
+
page.card.innerHTML = DOMPurify6__default.default.sanitize(page.html, {
|
|
2383
|
+
ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "s", "strike", "img", "div", "br"],
|
|
2384
|
+
ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
|
|
2385
|
+
});
|
|
2386
|
+
wrapper.appendChild(page.card);
|
|
2387
|
+
}
|
|
2231
2388
|
}
|
|
2232
2389
|
extractParagraphHtml(pElement, imageMap = {}) {
|
|
2233
|
-
|
|
2390
|
+
return this.extractParagraphChunks(pElement, imageMap).join("<br/>");
|
|
2391
|
+
}
|
|
2392
|
+
extractParagraphChunks(pElement, imageMap = {}) {
|
|
2393
|
+
const chunks = [""];
|
|
2394
|
+
let currentChunkIndex = 0;
|
|
2234
2395
|
const drawings = Array.from(pElement.getElementsByTagNameNS("*", "drawing"));
|
|
2235
2396
|
for (const drawing of drawings) {
|
|
2236
2397
|
const blip = drawing.getElementsByTagNameNS("*", "blip")[0];
|
|
2237
2398
|
const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
|
|
2238
2399
|
if (rId && imageMap[rId]) {
|
|
2239
|
-
|
|
2400
|
+
chunks[currentChunkIndex] += `<div style="text-align:center; margin: 12px 0;"><img src="${imageMap[rId]}" style="max-width: 100%; height: auto; border-radius: 4px;" /></div>`;
|
|
2240
2401
|
}
|
|
2241
2402
|
}
|
|
2242
2403
|
const runs = Array.from(pElement.getElementsByTagNameNS("*", "r"));
|
|
2243
|
-
if (runs.length === 0 && !
|
|
2244
|
-
|
|
2404
|
+
if (runs.length === 0 && !chunks[currentChunkIndex]) {
|
|
2405
|
+
chunks[currentChunkIndex] = DOMPurify6__default.default.sanitize(pElement.textContent || "");
|
|
2406
|
+
return chunks;
|
|
2245
2407
|
}
|
|
2246
2408
|
for (const r of runs) {
|
|
2247
2409
|
const blip = r.getElementsByTagNameNS("*", "blip")[0] || r.getElementsByTagNameNS("*", "imagedata")[0];
|
|
2248
2410
|
const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
|
|
2249
2411
|
if (rId && imageMap[rId]) {
|
|
2250
|
-
|
|
2412
|
+
chunks[currentChunkIndex] += `<img src="${imageMap[rId]}" style="max-width: 100%; height: auto; display: inline-block; margin: 4px;" />`;
|
|
2251
2413
|
}
|
|
2252
|
-
const brs = r.getElementsByTagNameNS("*", "br");
|
|
2253
|
-
for (
|
|
2254
|
-
|
|
2414
|
+
const brs = Array.from(r.getElementsByTagNameNS("*", "br"));
|
|
2415
|
+
for (const br of brs) {
|
|
2416
|
+
const type = br.getAttribute("w:type") || br.getAttribute("type");
|
|
2417
|
+
if (type === "page") {
|
|
2418
|
+
chunks.push("");
|
|
2419
|
+
currentChunkIndex++;
|
|
2420
|
+
} else {
|
|
2421
|
+
chunks[currentChunkIndex] += "<br/>";
|
|
2422
|
+
}
|
|
2255
2423
|
}
|
|
2256
2424
|
const tabs = r.getElementsByTagNameNS("*", "tab");
|
|
2257
2425
|
if (tabs.length > 0) {
|
|
2258
|
-
|
|
2426
|
+
chunks[currentChunkIndex] += " ";
|
|
2259
2427
|
}
|
|
2260
2428
|
const rPr = r.getElementsByTagNameNS("*", "rPr")[0];
|
|
2261
2429
|
const isBold = !!rPr?.getElementsByTagNameNS("*", "b")[0];
|
|
@@ -2269,7 +2437,7 @@ var DocxPlugin = class {
|
|
|
2269
2437
|
const texts = Array.from(r.getElementsByTagNameNS("*", "t"));
|
|
2270
2438
|
let text = texts.map((t) => t.textContent || "").join("");
|
|
2271
2439
|
if (!text) continue;
|
|
2272
|
-
text =
|
|
2440
|
+
text = DOMPurify6__default.default.sanitize(text);
|
|
2273
2441
|
let styles = "";
|
|
2274
2442
|
if (isBold) styles += "font-weight: bold; ";
|
|
2275
2443
|
if (isItalic) styles += "font-style: italic; ";
|
|
@@ -2281,12 +2449,12 @@ var DocxPlugin = class {
|
|
|
2281
2449
|
if (!isNaN(pt) && pt > 0) styles += `font-size: ${pt}pt; `;
|
|
2282
2450
|
}
|
|
2283
2451
|
if (styles) {
|
|
2284
|
-
|
|
2452
|
+
chunks[currentChunkIndex] += `<span style="${styles}">${text}</span>`;
|
|
2285
2453
|
} else {
|
|
2286
|
-
|
|
2454
|
+
chunks[currentChunkIndex] += text;
|
|
2287
2455
|
}
|
|
2288
2456
|
}
|
|
2289
|
-
return
|
|
2457
|
+
return chunks;
|
|
2290
2458
|
}
|
|
2291
2459
|
renderBinaryDocFallback(ctx, wrapper) {
|
|
2292
2460
|
const card = document.createElement("div");
|
|
@@ -2303,14 +2471,14 @@ var DocxPlugin = class {
|
|
|
2303
2471
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
2304
2472
|
if (wordDocStream && wordDocStream.length >= 512) {
|
|
2305
2473
|
const text2 = this.extractReadableStrings(wordDocStream);
|
|
2306
|
-
card.innerHTML = `<div style="white-space: pre-wrap;">${
|
|
2474
|
+
card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6__default.default.sanitize(text2)}</div>`;
|
|
2307
2475
|
wrapper.appendChild(card);
|
|
2308
2476
|
return;
|
|
2309
2477
|
}
|
|
2310
2478
|
} catch {
|
|
2311
2479
|
}
|
|
2312
2480
|
const text = this.extractReadableStrings(new Uint8Array(ctx.buffer));
|
|
2313
|
-
card.innerHTML = `<div style="white-space: pre-wrap;">${
|
|
2481
|
+
card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6__default.default.sanitize(text)}</div>`;
|
|
2314
2482
|
wrapper.appendChild(card);
|
|
2315
2483
|
}
|
|
2316
2484
|
extractReadableStrings(bytes) {
|
|
@@ -2406,6 +2574,26 @@ var ExcelPlugin = class {
|
|
|
2406
2574
|
instance.zoomIn?.();
|
|
2407
2575
|
}
|
|
2408
2576
|
},
|
|
2577
|
+
{
|
|
2578
|
+
id: "fit-page",
|
|
2579
|
+
icon: "fit-page",
|
|
2580
|
+
label: "Fit to View",
|
|
2581
|
+
type: "button",
|
|
2582
|
+
group: "zoom",
|
|
2583
|
+
execute: () => {
|
|
2584
|
+
instance.fitToPage?.();
|
|
2585
|
+
}
|
|
2586
|
+
},
|
|
2587
|
+
{
|
|
2588
|
+
id: "rotate-cw",
|
|
2589
|
+
icon: "rotate-cw",
|
|
2590
|
+
label: "Rotate",
|
|
2591
|
+
type: "button",
|
|
2592
|
+
group: "view",
|
|
2593
|
+
execute: () => {
|
|
2594
|
+
instance.rotateCW?.();
|
|
2595
|
+
}
|
|
2596
|
+
},
|
|
2409
2597
|
{
|
|
2410
2598
|
id: "download",
|
|
2411
2599
|
icon: "download",
|
|
@@ -2456,9 +2644,23 @@ var ExcelPlugin = class {
|
|
|
2456
2644
|
container.appendChild(tabsArea);
|
|
2457
2645
|
ctx.container.appendChild(container);
|
|
2458
2646
|
let scale = 1;
|
|
2647
|
+
let rotation = 0;
|
|
2459
2648
|
let currentSheetIndex = 1;
|
|
2460
2649
|
let sheetNames = [];
|
|
2461
2650
|
let wb = null;
|
|
2651
|
+
const applyTransform = () => {
|
|
2652
|
+
contentArea.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2653
|
+
contentArea.style.transformOrigin = "top left";
|
|
2654
|
+
};
|
|
2655
|
+
const calculateFitScale = () => {
|
|
2656
|
+
const table = contentArea.querySelector("table");
|
|
2657
|
+
if (!table) return 1;
|
|
2658
|
+
const availW = Math.max(200, container.clientWidth - 48);
|
|
2659
|
+
const availH = Math.max(200, container.clientHeight - 80);
|
|
2660
|
+
const tW = table.offsetWidth || 800;
|
|
2661
|
+
const tH = table.offsetHeight || 600;
|
|
2662
|
+
return Math.min(1, Math.min(availW / tW, availH / tH));
|
|
2663
|
+
};
|
|
2462
2664
|
try {
|
|
2463
2665
|
wb = XLSX__namespace.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
|
|
2464
2666
|
sheetNames = wb.SheetNames || [];
|
|
@@ -2546,17 +2748,30 @@ var ExcelPlugin = class {
|
|
|
2546
2748
|
return {
|
|
2547
2749
|
destroy: cleanup,
|
|
2548
2750
|
zoomIn: () => {
|
|
2549
|
-
scale += 0.
|
|
2550
|
-
|
|
2751
|
+
scale += 0.15;
|
|
2752
|
+
applyTransform();
|
|
2551
2753
|
},
|
|
2552
2754
|
zoomOut: () => {
|
|
2553
|
-
scale = Math.max(0.2, scale - 0.
|
|
2554
|
-
|
|
2755
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
2756
|
+
applyTransform();
|
|
2555
2757
|
},
|
|
2556
2758
|
getZoom: () => scale,
|
|
2557
2759
|
setZoom: (level) => {
|
|
2558
2760
|
scale = level;
|
|
2559
|
-
|
|
2761
|
+
applyTransform();
|
|
2762
|
+
},
|
|
2763
|
+
fitToPage: () => {
|
|
2764
|
+
scale = calculateFitScale();
|
|
2765
|
+
rotation = 0;
|
|
2766
|
+
applyTransform();
|
|
2767
|
+
},
|
|
2768
|
+
rotateCW: () => {
|
|
2769
|
+
rotation = (rotation + 90) % 360;
|
|
2770
|
+
applyTransform();
|
|
2771
|
+
},
|
|
2772
|
+
rotateCCW: () => {
|
|
2773
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
2774
|
+
applyTransform();
|
|
2560
2775
|
},
|
|
2561
2776
|
goToPage: (page) => {
|
|
2562
2777
|
if (page > 0 && page <= sheetNames.length) {
|
|
@@ -2806,6 +3021,26 @@ var CodePlugin = class {
|
|
|
2806
3021
|
instance.zoomIn?.();
|
|
2807
3022
|
}
|
|
2808
3023
|
},
|
|
3024
|
+
{
|
|
3025
|
+
id: "fit-page",
|
|
3026
|
+
icon: "fit-page",
|
|
3027
|
+
label: "Fit to View",
|
|
3028
|
+
type: "button",
|
|
3029
|
+
group: "zoom",
|
|
3030
|
+
execute: () => {
|
|
3031
|
+
instance.fitToPage?.();
|
|
3032
|
+
}
|
|
3033
|
+
},
|
|
3034
|
+
{
|
|
3035
|
+
id: "rotate-cw",
|
|
3036
|
+
icon: "rotate-cw",
|
|
3037
|
+
label: "Rotate",
|
|
3038
|
+
type: "button",
|
|
3039
|
+
group: "view",
|
|
3040
|
+
execute: () => {
|
|
3041
|
+
instance.rotateCW?.();
|
|
3042
|
+
}
|
|
3043
|
+
},
|
|
2809
3044
|
{
|
|
2810
3045
|
id: "copy",
|
|
2811
3046
|
icon: "copy",
|
|
@@ -2842,40 +3077,94 @@ var CodePlugin = class {
|
|
|
2842
3077
|
async render(ctx) {
|
|
2843
3078
|
const decoder = new TextDecoder("utf-8");
|
|
2844
3079
|
const fullText = decoder.decode(ctx.buffer);
|
|
2845
|
-
const
|
|
2846
|
-
const
|
|
3080
|
+
const extRaw = ctx.metadata.extension?.toLowerCase();
|
|
3081
|
+
const mimeRaw = ctx.metadata.mimeType?.toLowerCase();
|
|
3082
|
+
const isTxt = extRaw === ".txt" || mimeRaw === "text/plain" && (!extRaw || !this.extensions.filter((e) => e !== ".txt").includes(extRaw));
|
|
3083
|
+
let rawPages = [];
|
|
3084
|
+
if (isTxt) {
|
|
3085
|
+
const explicitPages = fullText.split(/(?:\f|\x0C)/);
|
|
3086
|
+
for (const ep of explicitPages) {
|
|
3087
|
+
const lines = ep.split(/\r?\n/);
|
|
3088
|
+
let currentChunk = [];
|
|
3089
|
+
for (let i = 0; i < lines.length; i++) {
|
|
3090
|
+
currentChunk.push(lines[i]);
|
|
3091
|
+
if (currentChunk.length >= 46) {
|
|
3092
|
+
rawPages.push(currentChunk.join("\n"));
|
|
3093
|
+
currentChunk = [];
|
|
3094
|
+
}
|
|
3095
|
+
}
|
|
3096
|
+
if (currentChunk.length > 0 || lines.length === 0) {
|
|
3097
|
+
rawPages.push(currentChunk.join("\n"));
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
3100
|
+
if (rawPages.length === 0) rawPages = [""];
|
|
3101
|
+
} else {
|
|
3102
|
+
const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
|
|
3103
|
+
rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
3104
|
+
}
|
|
2847
3105
|
const totalPages = Math.max(1, rawPages.length);
|
|
2848
3106
|
let currentPage = 1;
|
|
2849
3107
|
const container = document.createElement("div");
|
|
2850
3108
|
container.style.width = "100%";
|
|
2851
3109
|
container.style.height = "100%";
|
|
2852
3110
|
container.style.overflow = "auto";
|
|
2853
|
-
container.style.backgroundColor = "#1e1e1e";
|
|
2854
|
-
container.style.color = "#d4d4d4";
|
|
2855
|
-
container.style.padding = "16px";
|
|
2856
|
-
container.style.boxSizing = "border-box";
|
|
2857
3111
|
let fontSize = 13;
|
|
3112
|
+
let rotation = 0;
|
|
3113
|
+
let zoomLevel = 1;
|
|
2858
3114
|
const pre = document.createElement("pre");
|
|
2859
|
-
pre.style.margin = "0";
|
|
2860
|
-
pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
|
|
2861
|
-
pre.style.fontSize = `${fontSize}px`;
|
|
2862
|
-
pre.style.lineHeight = "1.5";
|
|
2863
|
-
pre.style.whiteSpace = "pre-wrap";
|
|
2864
|
-
pre.style.wordBreak = "break-all";
|
|
2865
3115
|
const code = document.createElement("code");
|
|
3116
|
+
if (isTxt) {
|
|
3117
|
+
container.style.backgroundColor = "#f1f5f9";
|
|
3118
|
+
container.style.padding = "32px";
|
|
3119
|
+
container.style.boxSizing = "border-box";
|
|
3120
|
+
container.style.display = "flex";
|
|
3121
|
+
container.style.flexDirection = "column";
|
|
3122
|
+
container.style.alignItems = "center";
|
|
3123
|
+
pre.style.margin = "0";
|
|
3124
|
+
pre.style.fontFamily = "Consolas, 'Courier New', monospace";
|
|
3125
|
+
pre.style.fontSize = "13px";
|
|
3126
|
+
pre.style.color = "#1e293b";
|
|
3127
|
+
pre.style.lineHeight = "1.5";
|
|
3128
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3129
|
+
pre.style.wordBreak = "break-word";
|
|
3130
|
+
pre.style.backgroundColor = "#ffffff";
|
|
3131
|
+
pre.style.width = "816px";
|
|
3132
|
+
pre.style.minHeight = "1056px";
|
|
3133
|
+
pre.style.padding = "72px 56px";
|
|
3134
|
+
pre.style.boxSizing = "border-box";
|
|
3135
|
+
pre.style.boxShadow = "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)";
|
|
3136
|
+
pre.style.borderRadius = "4px";
|
|
3137
|
+
pre.style.transformOrigin = "top center";
|
|
3138
|
+
} else {
|
|
3139
|
+
container.style.backgroundColor = "#1e1e1e";
|
|
3140
|
+
container.style.color = "#d4d4d4";
|
|
3141
|
+
container.style.padding = "16px";
|
|
3142
|
+
container.style.boxSizing = "border-box";
|
|
3143
|
+
pre.style.margin = "0";
|
|
3144
|
+
pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
|
|
3145
|
+
pre.style.fontSize = `${fontSize}px`;
|
|
3146
|
+
pre.style.lineHeight = "1.5";
|
|
3147
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3148
|
+
pre.style.wordBreak = "break-all";
|
|
3149
|
+
pre.style.transformOrigin = "top left";
|
|
3150
|
+
}
|
|
2866
3151
|
const ext = (ctx.metadata.extension || "").replace(".", "");
|
|
2867
3152
|
const renderCodePage = (text) => {
|
|
2868
|
-
|
|
2869
|
-
if (ext && hljs__default.default.getLanguage(ext)) {
|
|
2870
|
-
code.innerHTML = hljs__default.default.highlight(text, { language: ext }).value;
|
|
2871
|
-
} else {
|
|
2872
|
-
code.innerHTML = hljs__default.default.highlightAuto(text).value;
|
|
2873
|
-
}
|
|
2874
|
-
} catch {
|
|
3153
|
+
if (isTxt) {
|
|
2875
3154
|
code.textContent = text;
|
|
3155
|
+
} else {
|
|
3156
|
+
try {
|
|
3157
|
+
if (ext && hljs__default.default.getLanguage(ext)) {
|
|
3158
|
+
code.innerHTML = hljs__default.default.highlight(text, { language: ext }).value;
|
|
3159
|
+
} else {
|
|
3160
|
+
code.innerHTML = hljs__default.default.highlightAuto(text).value;
|
|
3161
|
+
}
|
|
3162
|
+
} catch {
|
|
3163
|
+
code.textContent = text;
|
|
3164
|
+
}
|
|
2876
3165
|
}
|
|
2877
3166
|
};
|
|
2878
|
-
renderCodePage(rawPages[0] || fullText);
|
|
3167
|
+
renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
|
|
2879
3168
|
pre.appendChild(code);
|
|
2880
3169
|
container.appendChild(pre);
|
|
2881
3170
|
let indicator = null;
|
|
@@ -2884,15 +3173,22 @@ var CodePlugin = class {
|
|
|
2884
3173
|
indicator.className = "fp-code-page-indicator";
|
|
2885
3174
|
indicator.style.position = "sticky";
|
|
2886
3175
|
indicator.style.bottom = "16px";
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
3176
|
+
if (isTxt) {
|
|
3177
|
+
indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
|
|
3178
|
+
indicator.style.color = "#334155";
|
|
3179
|
+
indicator.style.border = "1px solid #e2e8f0";
|
|
3180
|
+
indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
|
|
3181
|
+
} else {
|
|
3182
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3183
|
+
indicator.style.color = "#f8fafc";
|
|
3184
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3185
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3186
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
3187
|
+
}
|
|
2890
3188
|
indicator.style.fontSize = "12px";
|
|
2891
3189
|
indicator.style.fontWeight = "600";
|
|
2892
3190
|
indicator.style.padding = "5px 14px";
|
|
2893
3191
|
indicator.style.borderRadius = "20px";
|
|
2894
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2895
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2896
3192
|
indicator.style.zIndex = "10";
|
|
2897
3193
|
indicator.style.userSelect = "none";
|
|
2898
3194
|
indicator.style.pointerEvents = "none";
|
|
@@ -2903,7 +3199,7 @@ var CodePlugin = class {
|
|
|
2903
3199
|
}
|
|
2904
3200
|
const showPage = (pageNum) => {
|
|
2905
3201
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2906
|
-
renderCodePage(rawPages[currentPage - 1] || fullText);
|
|
3202
|
+
renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
|
|
2907
3203
|
if (indicator) {
|
|
2908
3204
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2909
3205
|
}
|
|
@@ -2919,23 +3215,57 @@ var CodePlugin = class {
|
|
|
2919
3215
|
ctx.container.innerHTML = "";
|
|
2920
3216
|
};
|
|
2921
3217
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3218
|
+
const updateTransform = () => {
|
|
3219
|
+
if (isTxt) {
|
|
3220
|
+
pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
|
|
3221
|
+
} else {
|
|
3222
|
+
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3223
|
+
pre.style.fontSize = `${fontSize}px`;
|
|
3224
|
+
}
|
|
3225
|
+
};
|
|
2922
3226
|
return {
|
|
2923
3227
|
destroy: cleanup,
|
|
2924
3228
|
getPageCount: () => totalPages,
|
|
2925
3229
|
getCurrentPage: () => currentPage,
|
|
2926
3230
|
goToPage: (page) => showPage(page),
|
|
2927
3231
|
zoomIn: () => {
|
|
2928
|
-
|
|
2929
|
-
|
|
3232
|
+
if (isTxt) {
|
|
3233
|
+
zoomLevel = Math.min(3, zoomLevel + 0.1);
|
|
3234
|
+
} else {
|
|
3235
|
+
fontSize = Math.min(32, fontSize + 2);
|
|
3236
|
+
}
|
|
3237
|
+
updateTransform();
|
|
2930
3238
|
},
|
|
2931
3239
|
zoomOut: () => {
|
|
2932
|
-
|
|
2933
|
-
|
|
3240
|
+
if (isTxt) {
|
|
3241
|
+
zoomLevel = Math.max(0.1, zoomLevel - 0.1);
|
|
3242
|
+
} else {
|
|
3243
|
+
fontSize = Math.max(8, fontSize - 2);
|
|
3244
|
+
}
|
|
3245
|
+
updateTransform();
|
|
2934
3246
|
},
|
|
2935
|
-
getZoom: () => fontSize / 13,
|
|
3247
|
+
getZoom: () => isTxt ? zoomLevel : fontSize / 13,
|
|
2936
3248
|
setZoom: (level) => {
|
|
2937
|
-
|
|
2938
|
-
|
|
3249
|
+
if (isTxt) {
|
|
3250
|
+
zoomLevel = level;
|
|
3251
|
+
} else {
|
|
3252
|
+
fontSize = Math.round(13 * level);
|
|
3253
|
+
}
|
|
3254
|
+
updateTransform();
|
|
3255
|
+
},
|
|
3256
|
+
fitToPage: () => {
|
|
3257
|
+
fontSize = 13;
|
|
3258
|
+
rotation = 0;
|
|
3259
|
+
zoomLevel = 1;
|
|
3260
|
+
updateTransform();
|
|
3261
|
+
},
|
|
3262
|
+
rotateCW: () => {
|
|
3263
|
+
rotation = (rotation + 90) % 360;
|
|
3264
|
+
updateTransform();
|
|
3265
|
+
},
|
|
3266
|
+
rotateCCW: () => {
|
|
3267
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
3268
|
+
updateTransform();
|
|
2939
3269
|
},
|
|
2940
3270
|
download: () => {
|
|
2941
3271
|
const mimeType = ctx.metadata.mimeType || "text/plain";
|
|
@@ -3234,7 +3564,7 @@ var MarkdownPlugin = class {
|
|
|
3234
3564
|
gfm: true,
|
|
3235
3565
|
breaks: true
|
|
3236
3566
|
});
|
|
3237
|
-
const cleanHtml =
|
|
3567
|
+
const cleanHtml = DOMPurify6__default.default.sanitize(rawHtml, {
|
|
3238
3568
|
USE_PROFILES: { html: true }
|
|
3239
3569
|
});
|
|
3240
3570
|
const wrapper = document.createElement("div");
|
|
@@ -3448,6 +3778,14 @@ var PptxPlugin = class {
|
|
|
3448
3778
|
group: "zoom",
|
|
3449
3779
|
execute: () => instance.fitToPage?.()
|
|
3450
3780
|
},
|
|
3781
|
+
{
|
|
3782
|
+
id: "rotate-cw",
|
|
3783
|
+
icon: "rotate-cw",
|
|
3784
|
+
label: "Rotate",
|
|
3785
|
+
type: "button",
|
|
3786
|
+
group: "view",
|
|
3787
|
+
execute: () => instance.rotateCW?.()
|
|
3788
|
+
},
|
|
3451
3789
|
{
|
|
3452
3790
|
id: "download",
|
|
3453
3791
|
icon: "download",
|
|
@@ -3472,6 +3810,7 @@ var PptxPlugin = class {
|
|
|
3472
3810
|
const slideCount = renderer.slidePaths?.length || 1;
|
|
3473
3811
|
let currentSlide = 1;
|
|
3474
3812
|
let scale = 1;
|
|
3813
|
+
let rotation = 0;
|
|
3475
3814
|
const wrapper = document.createElement("div");
|
|
3476
3815
|
wrapper.className = "fp-pptx-wrapper";
|
|
3477
3816
|
wrapper.style.cssText = `
|
|
@@ -3494,6 +3833,8 @@ var PptxPlugin = class {
|
|
|
3494
3833
|
background: #ffffff;
|
|
3495
3834
|
transform-origin: top center;
|
|
3496
3835
|
transition: transform 0.2s ease;
|
|
3836
|
+
max-width: calc(100% - 32px);
|
|
3837
|
+
max-height: calc(100% - 48px);
|
|
3497
3838
|
`;
|
|
3498
3839
|
const canvas = document.createElement("canvas");
|
|
3499
3840
|
slideContainer.appendChild(canvas);
|
|
@@ -3501,10 +3842,22 @@ var PptxPlugin = class {
|
|
|
3501
3842
|
ctx.container.innerHTML = "";
|
|
3502
3843
|
ctx.container.style.overflow = "auto";
|
|
3503
3844
|
ctx.container.appendChild(wrapper);
|
|
3845
|
+
const calculateFitScale = () => {
|
|
3846
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
3847
|
+
const availH = Math.max(200, ctx.container.clientHeight - 72);
|
|
3848
|
+
const cW = canvas.offsetWidth || 1280;
|
|
3849
|
+
const cH = canvas.offsetHeight || 720;
|
|
3850
|
+
return Math.min(1, Math.min(availW / cW, availH / cH));
|
|
3851
|
+
};
|
|
3852
|
+
const applyTransform = () => {
|
|
3853
|
+
slideContainer.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
3854
|
+
};
|
|
3504
3855
|
const renderCurrentSlide = async () => {
|
|
3505
3856
|
try {
|
|
3506
3857
|
await renderer.renderSlide(currentSlide - 1, canvas, 1280);
|
|
3507
3858
|
ctx.emit("page-change", { page: currentSlide, totalPages: slideCount });
|
|
3859
|
+
scale = calculateFitScale();
|
|
3860
|
+
applyTransform();
|
|
3508
3861
|
} catch (err) {
|
|
3509
3862
|
console.error("[PptxPlugin] Failed to render slide:", err);
|
|
3510
3863
|
}
|
|
@@ -3527,21 +3880,30 @@ var PptxPlugin = class {
|
|
|
3527
3880
|
getPageCount: () => slideCount,
|
|
3528
3881
|
getCurrentPage: () => currentSlide,
|
|
3529
3882
|
zoomIn: () => {
|
|
3530
|
-
scale += 0.
|
|
3531
|
-
|
|
3883
|
+
scale += 0.15;
|
|
3884
|
+
applyTransform();
|
|
3532
3885
|
},
|
|
3533
3886
|
zoomOut: () => {
|
|
3534
|
-
scale = Math.max(0.2, scale - 0.
|
|
3535
|
-
|
|
3887
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
3888
|
+
applyTransform();
|
|
3536
3889
|
},
|
|
3537
3890
|
getZoom: () => scale,
|
|
3538
3891
|
setZoom: (level) => {
|
|
3539
3892
|
scale = level;
|
|
3540
|
-
|
|
3893
|
+
applyTransform();
|
|
3541
3894
|
},
|
|
3542
3895
|
fitToPage: () => {
|
|
3543
|
-
scale =
|
|
3544
|
-
|
|
3896
|
+
scale = calculateFitScale();
|
|
3897
|
+
rotation = 0;
|
|
3898
|
+
applyTransform();
|
|
3899
|
+
},
|
|
3900
|
+
rotateCW: () => {
|
|
3901
|
+
rotation = (rotation + 90) % 360;
|
|
3902
|
+
applyTransform();
|
|
3903
|
+
},
|
|
3904
|
+
rotateCCW: () => {
|
|
3905
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
3906
|
+
applyTransform();
|
|
3545
3907
|
},
|
|
3546
3908
|
getThumbnails: () => {
|
|
3547
3909
|
const list = [];
|
|
@@ -3822,6 +4184,14 @@ var RtfPlugin = class {
|
|
|
3822
4184
|
group: "zoom",
|
|
3823
4185
|
execute: () => instance.fitToPage?.()
|
|
3824
4186
|
},
|
|
4187
|
+
{
|
|
4188
|
+
id: "rotate-cw",
|
|
4189
|
+
icon: "rotate-cw",
|
|
4190
|
+
label: "Rotate",
|
|
4191
|
+
type: "button",
|
|
4192
|
+
group: "view",
|
|
4193
|
+
execute: () => instance.rotateCW?.()
|
|
4194
|
+
},
|
|
3825
4195
|
{
|
|
3826
4196
|
id: "download",
|
|
3827
4197
|
icon: "download",
|
|
@@ -3830,6 +4200,14 @@ var RtfPlugin = class {
|
|
|
3830
4200
|
group: "actions",
|
|
3831
4201
|
execute: () => instance.download?.()
|
|
3832
4202
|
},
|
|
4203
|
+
{
|
|
4204
|
+
id: "copy",
|
|
4205
|
+
icon: "copy",
|
|
4206
|
+
label: "Copy Text",
|
|
4207
|
+
type: "button",
|
|
4208
|
+
group: "actions",
|
|
4209
|
+
execute: () => instance.copy?.()
|
|
4210
|
+
},
|
|
3833
4211
|
{
|
|
3834
4212
|
id: "print",
|
|
3835
4213
|
icon: "print",
|
|
@@ -3858,7 +4236,24 @@ var RtfPlugin = class {
|
|
|
3858
4236
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
3859
4237
|
ctx.container.appendChild(wrapper);
|
|
3860
4238
|
let scale = 1;
|
|
4239
|
+
let rotation = 0;
|
|
3861
4240
|
let pageElements = [];
|
|
4241
|
+
const calculateFitScale = () => {
|
|
4242
|
+
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4243
|
+
const elW = activeEl.offsetWidth || 850;
|
|
4244
|
+
const elH = activeEl.offsetHeight || 1e3;
|
|
4245
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
4246
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
4247
|
+
return Math.min(1.1, Math.min(availW / elW, availH / elH));
|
|
4248
|
+
};
|
|
4249
|
+
const applyTransform = () => {
|
|
4250
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4251
|
+
wrapper.style.transformOrigin = "top center";
|
|
4252
|
+
};
|
|
4253
|
+
setTimeout(() => {
|
|
4254
|
+
scale = calculateFitScale();
|
|
4255
|
+
applyTransform();
|
|
4256
|
+
}, 60);
|
|
3862
4257
|
try {
|
|
3863
4258
|
if (typeof RTFJS__namespace.loggingEnabled === "function") {
|
|
3864
4259
|
RTFJS__namespace.loggingEnabled(false);
|
|
@@ -3874,14 +4269,31 @@ var RtfPlugin = class {
|
|
|
3874
4269
|
} catch (err) {
|
|
3875
4270
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
3876
4271
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
3877
|
-
const
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
4272
|
+
const rawPages = text.split(/\\page\b/).map((segment) => {
|
|
4273
|
+
return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
|
|
4274
|
+
}).filter((p) => p.length > 0);
|
|
4275
|
+
const pages = rawPages.length > 0 ? rawPages : [text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim()];
|
|
4276
|
+
for (let i = 0; i < pages.length; i++) {
|
|
4277
|
+
const pageCard = document.createElement("div");
|
|
4278
|
+
pageCard.className = "fp-rtf-page-card";
|
|
4279
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
4280
|
+
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4281
|
+
pageCard.style.borderRadius = "4px";
|
|
4282
|
+
pageCard.style.padding = "72px 56px";
|
|
4283
|
+
pageCard.style.width = "816px";
|
|
4284
|
+
pageCard.style.minHeight = "1056px";
|
|
4285
|
+
pageCard.style.maxWidth = "100%";
|
|
4286
|
+
pageCard.style.boxSizing = "border-box";
|
|
4287
|
+
pageCard.style.fontFamily = "serif";
|
|
4288
|
+
pageCard.style.fontSize = "12pt";
|
|
4289
|
+
pageCard.style.lineHeight = "1.6";
|
|
4290
|
+
pageCard.style.color = "#1e293b";
|
|
4291
|
+
pageCard.style.whiteSpace = "pre-wrap";
|
|
4292
|
+
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4293
|
+
pageCard.textContent = pages[i];
|
|
4294
|
+
wrapper.appendChild(pageCard);
|
|
4295
|
+
pageElements.push(pageCard);
|
|
4296
|
+
}
|
|
3885
4297
|
}
|
|
3886
4298
|
const totalPages = Math.max(1, pageElements.length);
|
|
3887
4299
|
let currentPage = 1;
|
|
@@ -3935,21 +4347,30 @@ var RtfPlugin = class {
|
|
|
3935
4347
|
getCurrentPage: () => currentPage,
|
|
3936
4348
|
goToPage: (page) => showPage(page),
|
|
3937
4349
|
zoomIn: () => {
|
|
3938
|
-
scale += 0.
|
|
3939
|
-
|
|
4350
|
+
scale += 0.15;
|
|
4351
|
+
applyTransform();
|
|
3940
4352
|
},
|
|
3941
4353
|
zoomOut: () => {
|
|
3942
|
-
scale = Math.max(0.2, scale - 0.
|
|
3943
|
-
|
|
4354
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
4355
|
+
applyTransform();
|
|
3944
4356
|
},
|
|
3945
4357
|
getZoom: () => scale,
|
|
3946
4358
|
setZoom: (level) => {
|
|
3947
4359
|
scale = level;
|
|
3948
|
-
|
|
4360
|
+
applyTransform();
|
|
3949
4361
|
},
|
|
3950
4362
|
fitToPage: () => {
|
|
3951
|
-
scale =
|
|
3952
|
-
|
|
4363
|
+
scale = calculateFitScale();
|
|
4364
|
+
rotation = 0;
|
|
4365
|
+
applyTransform();
|
|
4366
|
+
},
|
|
4367
|
+
rotateCW: () => {
|
|
4368
|
+
rotation = (rotation + 90) % 360;
|
|
4369
|
+
applyTransform();
|
|
4370
|
+
},
|
|
4371
|
+
rotateCCW: () => {
|
|
4372
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
4373
|
+
applyTransform();
|
|
3953
4374
|
},
|
|
3954
4375
|
download: () => {
|
|
3955
4376
|
const blob = new Blob([ctx.buffer], { type: "application/rtf" });
|
|
@@ -3960,6 +4381,10 @@ var RtfPlugin = class {
|
|
|
3960
4381
|
a.click();
|
|
3961
4382
|
URL.revokeObjectURL(url);
|
|
3962
4383
|
},
|
|
4384
|
+
copy: () => {
|
|
4385
|
+
const text = wrapper.textContent || "";
|
|
4386
|
+
navigator.clipboard?.writeText(text);
|
|
4387
|
+
},
|
|
3963
4388
|
print: () => {
|
|
3964
4389
|
window.print();
|
|
3965
4390
|
}
|
|
@@ -4034,7 +4459,7 @@ var HtmlPreviewPlugin = class {
|
|
|
4034
4459
|
}
|
|
4035
4460
|
async render(ctx) {
|
|
4036
4461
|
const rawHtml = new TextDecoder("utf-8").decode(ctx.buffer);
|
|
4037
|
-
const sanitized =
|
|
4462
|
+
const sanitized = DOMPurify6__default.default.sanitize(rawHtml, {
|
|
4038
4463
|
WHOLE_DOCUMENT: true,
|
|
4039
4464
|
ADD_TAGS: ["style", "link"],
|
|
4040
4465
|
ADD_ATTR: ["target", "rel"]
|
|
@@ -4177,11 +4602,19 @@ var OpenDocumentPlugin = class {
|
|
|
4177
4602
|
{
|
|
4178
4603
|
id: "fit-page",
|
|
4179
4604
|
icon: "fit-page",
|
|
4180
|
-
label: "Fit to Page",
|
|
4605
|
+
label: isPresentation ? "Fit to Slide" : "Fit to Page",
|
|
4181
4606
|
type: "button",
|
|
4182
4607
|
group: "zoom",
|
|
4183
4608
|
execute: () => instance.fitToPage?.()
|
|
4184
4609
|
},
|
|
4610
|
+
{
|
|
4611
|
+
id: "rotate-cw",
|
|
4612
|
+
icon: "rotate-cw",
|
|
4613
|
+
label: "Rotate",
|
|
4614
|
+
type: "button",
|
|
4615
|
+
group: "view",
|
|
4616
|
+
execute: () => instance.rotateCW?.()
|
|
4617
|
+
},
|
|
4185
4618
|
{
|
|
4186
4619
|
id: "download",
|
|
4187
4620
|
icon: "download",
|
|
@@ -4245,6 +4678,22 @@ var OpenDocumentPlugin = class {
|
|
|
4245
4678
|
container.appendChild(wrapper);
|
|
4246
4679
|
ctx.container.appendChild(container);
|
|
4247
4680
|
let scale = 1;
|
|
4681
|
+
let rotation = 0;
|
|
4682
|
+
const calculateFitScale = () => {
|
|
4683
|
+
const elW = wrapper.offsetWidth || 850;
|
|
4684
|
+
const elH = wrapper.offsetHeight || (isPresentation ? 540 : 1e3);
|
|
4685
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
4686
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
4687
|
+
return Math.min(1, Math.min(availW / elW, availH / elH));
|
|
4688
|
+
};
|
|
4689
|
+
const applyTransform = () => {
|
|
4690
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4691
|
+
wrapper.style.transformOrigin = "top center";
|
|
4692
|
+
};
|
|
4693
|
+
setTimeout(() => {
|
|
4694
|
+
scale = calculateFitScale();
|
|
4695
|
+
applyTransform();
|
|
4696
|
+
}, 60);
|
|
4248
4697
|
let currentPage = 1;
|
|
4249
4698
|
let totalPages = 1;
|
|
4250
4699
|
let slides = [];
|
|
@@ -4276,14 +4725,97 @@ var OpenDocumentPlugin = class {
|
|
|
4276
4725
|
wrapper.textContent = contentDoc.documentElement.textContent || "Formula content";
|
|
4277
4726
|
}
|
|
4278
4727
|
} else {
|
|
4279
|
-
wrapper.style.maxWidth = "
|
|
4280
|
-
wrapper.style.padding = "
|
|
4728
|
+
wrapper.style.maxWidth = "none";
|
|
4729
|
+
wrapper.style.padding = "0";
|
|
4281
4730
|
wrapper.style.minHeight = "100%";
|
|
4731
|
+
wrapper.style.backgroundColor = "transparent";
|
|
4732
|
+
wrapper.style.boxShadow = "none";
|
|
4733
|
+
wrapper.style.position = "relative";
|
|
4734
|
+
const dims = this.getPageDimensions(stylesDoc, contentDoc);
|
|
4282
4735
|
const bodyHtml = this.renderOdfBody(contentDoc, styleMap, imageUrls);
|
|
4283
|
-
|
|
4284
|
-
|
|
4736
|
+
const tempDiv = document.createElement("div");
|
|
4737
|
+
tempDiv.style.width = `${dims.width - dims.marginLeft - dims.marginRight}px`;
|
|
4738
|
+
tempDiv.style.position = "absolute";
|
|
4739
|
+
tempDiv.style.visibility = "hidden";
|
|
4740
|
+
tempDiv.innerHTML = DOMPurify6__default.default.sanitize(bodyHtml, {
|
|
4741
|
+
ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub", "hr"],
|
|
4285
4742
|
ADD_ATTR: ["style", "colspan", "rowspan"]
|
|
4286
4743
|
});
|
|
4744
|
+
document.body.appendChild(tempDiv);
|
|
4745
|
+
const contentHeight = dims.height - dims.marginTop - dims.marginBottom;
|
|
4746
|
+
const pageElements = [[]];
|
|
4747
|
+
let currentHeight = 0;
|
|
4748
|
+
let currentPageIdx = 0;
|
|
4749
|
+
Array.from(tempDiv.children).forEach((child) => {
|
|
4750
|
+
const el = child;
|
|
4751
|
+
const style = el.getAttribute("style") || "";
|
|
4752
|
+
const isBreakBefore = style.includes("page-break-before: always");
|
|
4753
|
+
const isBreakAfter = style.includes("page-break-after: always");
|
|
4754
|
+
const isSoftBreak = el.classList.contains("odf-page-break");
|
|
4755
|
+
if (isBreakBefore) {
|
|
4756
|
+
if (pageElements[currentPageIdx].length > 0) {
|
|
4757
|
+
currentPageIdx++;
|
|
4758
|
+
pageElements.push([]);
|
|
4759
|
+
currentHeight = 0;
|
|
4760
|
+
}
|
|
4761
|
+
}
|
|
4762
|
+
const h = el.offsetHeight || 0;
|
|
4763
|
+
if (currentHeight + h > contentHeight && pageElements[currentPageIdx].length > 0 && !isSoftBreak) {
|
|
4764
|
+
currentPageIdx++;
|
|
4765
|
+
pageElements.push([]);
|
|
4766
|
+
currentHeight = 0;
|
|
4767
|
+
}
|
|
4768
|
+
if (!isSoftBreak) {
|
|
4769
|
+
pageElements[currentPageIdx].push(el.cloneNode(true));
|
|
4770
|
+
currentHeight += h;
|
|
4771
|
+
}
|
|
4772
|
+
if (isBreakAfter || isSoftBreak) {
|
|
4773
|
+
currentPageIdx++;
|
|
4774
|
+
pageElements.push([]);
|
|
4775
|
+
currentHeight = 0;
|
|
4776
|
+
}
|
|
4777
|
+
});
|
|
4778
|
+
document.body.removeChild(tempDiv);
|
|
4779
|
+
if (pageElements.length > 1 && pageElements[pageElements.length - 1].length === 0) {
|
|
4780
|
+
pageElements.pop();
|
|
4781
|
+
}
|
|
4782
|
+
totalPages = Math.max(1, pageElements.length);
|
|
4783
|
+
pageElements.forEach((elements, idx) => {
|
|
4784
|
+
const page = document.createElement("div");
|
|
4785
|
+
page.className = `fp-odt-page fp-odt-page-${idx + 1}`;
|
|
4786
|
+
page.style.width = `${dims.width}px`;
|
|
4787
|
+
page.style.minHeight = `${dims.height}px`;
|
|
4788
|
+
page.style.padding = `${dims.marginTop}px ${dims.marginRight}px ${dims.marginBottom}px ${dims.marginLeft}px`;
|
|
4789
|
+
page.style.margin = "0 auto";
|
|
4790
|
+
page.style.backgroundColor = "#ffffff";
|
|
4791
|
+
page.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
|
|
4792
|
+
page.style.borderRadius = "4px";
|
|
4793
|
+
page.style.boxSizing = "border-box";
|
|
4794
|
+
page.style.display = idx === 0 ? "block" : "none";
|
|
4795
|
+
page.style.position = "absolute";
|
|
4796
|
+
page.style.top = "0";
|
|
4797
|
+
page.style.left = "50%";
|
|
4798
|
+
page.style.transform = "translateX(-50%)";
|
|
4799
|
+
elements.forEach((el) => page.appendChild(el));
|
|
4800
|
+
wrapper.appendChild(page);
|
|
4801
|
+
slides.push(page);
|
|
4802
|
+
});
|
|
4803
|
+
const pageIndicator = document.createElement("div");
|
|
4804
|
+
pageIndicator.className = "fp-odt-page-indicator";
|
|
4805
|
+
pageIndicator.style.position = "sticky";
|
|
4806
|
+
pageIndicator.style.bottom = "16px";
|
|
4807
|
+
pageIndicator.style.left = "50%";
|
|
4808
|
+
pageIndicator.style.transform = "translateX(-50%)";
|
|
4809
|
+
pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
|
4810
|
+
pageIndicator.style.color = "#fff";
|
|
4811
|
+
pageIndicator.style.padding = "6px 12px";
|
|
4812
|
+
pageIndicator.style.borderRadius = "16px";
|
|
4813
|
+
pageIndicator.style.fontSize = "12px";
|
|
4814
|
+
pageIndicator.style.zIndex = "100";
|
|
4815
|
+
pageIndicator.style.display = "inline-block";
|
|
4816
|
+
pageIndicator.style.width = "fit-content";
|
|
4817
|
+
pageIndicator.textContent = `Page 1 of ${totalPages}`;
|
|
4818
|
+
container.appendChild(pageIndicator);
|
|
4287
4819
|
}
|
|
4288
4820
|
const cleanup = () => {
|
|
4289
4821
|
imageUrls.forEach((url) => URL.revokeObjectURL(url));
|
|
@@ -4292,32 +4824,45 @@ var OpenDocumentPlugin = class {
|
|
|
4292
4824
|
};
|
|
4293
4825
|
ctx.signal.addEventListener("abort", cleanup);
|
|
4294
4826
|
const goToPage = (page) => {
|
|
4295
|
-
if (
|
|
4827
|
+
if (page < 1 || page > totalPages) return;
|
|
4296
4828
|
currentPage = page;
|
|
4297
4829
|
slides.forEach((s, idx) => {
|
|
4298
4830
|
s.style.display = idx === page - 1 ? "block" : "none";
|
|
4299
4831
|
});
|
|
4832
|
+
const indicator = container.querySelector(".fp-odt-page-indicator");
|
|
4833
|
+
if (indicator) {
|
|
4834
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4835
|
+
}
|
|
4300
4836
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4301
4837
|
};
|
|
4302
4838
|
return {
|
|
4303
4839
|
destroy: cleanup,
|
|
4304
4840
|
isPresentation,
|
|
4305
4841
|
zoomIn: () => {
|
|
4306
|
-
scale += 0.
|
|
4307
|
-
|
|
4842
|
+
scale += 0.15;
|
|
4843
|
+
applyTransform();
|
|
4308
4844
|
},
|
|
4309
4845
|
zoomOut: () => {
|
|
4310
|
-
scale = Math.max(0.2, scale - 0.
|
|
4311
|
-
|
|
4846
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
4847
|
+
applyTransform();
|
|
4312
4848
|
},
|
|
4313
4849
|
getZoom: () => scale,
|
|
4314
4850
|
setZoom: (level) => {
|
|
4315
4851
|
scale = level;
|
|
4316
|
-
|
|
4852
|
+
applyTransform();
|
|
4317
4853
|
},
|
|
4318
4854
|
fitToPage: () => {
|
|
4319
|
-
scale =
|
|
4320
|
-
|
|
4855
|
+
scale = calculateFitScale();
|
|
4856
|
+
rotation = 0;
|
|
4857
|
+
applyTransform();
|
|
4858
|
+
},
|
|
4859
|
+
rotateCW: () => {
|
|
4860
|
+
rotation = (rotation + 90) % 360;
|
|
4861
|
+
applyTransform();
|
|
4862
|
+
},
|
|
4863
|
+
rotateCCW: () => {
|
|
4864
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
4865
|
+
applyTransform();
|
|
4321
4866
|
},
|
|
4322
4867
|
goToPage,
|
|
4323
4868
|
getPageCount: () => totalPages,
|
|
@@ -4356,6 +4901,43 @@ var OpenDocumentPlugin = class {
|
|
|
4356
4901
|
}
|
|
4357
4902
|
};
|
|
4358
4903
|
}
|
|
4904
|
+
getPageDimensions(stylesDoc, contentDoc) {
|
|
4905
|
+
let width = 850;
|
|
4906
|
+
let height = 1123;
|
|
4907
|
+
let marginTop = 48;
|
|
4908
|
+
let marginBottom = 48;
|
|
4909
|
+
let marginLeft = 48;
|
|
4910
|
+
let marginRight = 48;
|
|
4911
|
+
const parseUnit = (val) => {
|
|
4912
|
+
if (!val) return null;
|
|
4913
|
+
if (val.endsWith("cm")) return parseFloat(val) * 37.8;
|
|
4914
|
+
if (val.endsWith("mm")) return parseFloat(val) * 3.78;
|
|
4915
|
+
if (val.endsWith("in")) return parseFloat(val) * 96;
|
|
4916
|
+
if (val.endsWith("pt")) return parseFloat(val) * 1.33;
|
|
4917
|
+
if (val.endsWith("px")) return parseFloat(val);
|
|
4918
|
+
return parseFloat(val);
|
|
4919
|
+
};
|
|
4920
|
+
const docs = [stylesDoc, contentDoc].filter(Boolean);
|
|
4921
|
+
for (const doc of docs) {
|
|
4922
|
+
const pageLayout = doc.querySelector("page-layout-properties, [page-width]");
|
|
4923
|
+
if (pageLayout) {
|
|
4924
|
+
const w = parseUnit(pageLayout.getAttribute("fo:page-width") || pageLayout.getAttribute("page-width"));
|
|
4925
|
+
const h = parseUnit(pageLayout.getAttribute("fo:page-height") || pageLayout.getAttribute("page-height"));
|
|
4926
|
+
const mt = parseUnit(pageLayout.getAttribute("fo:margin-top") || pageLayout.getAttribute("margin-top"));
|
|
4927
|
+
const mb = parseUnit(pageLayout.getAttribute("fo:margin-bottom") || pageLayout.getAttribute("margin-bottom"));
|
|
4928
|
+
const ml = parseUnit(pageLayout.getAttribute("fo:margin-left") || pageLayout.getAttribute("margin-left"));
|
|
4929
|
+
const mr = parseUnit(pageLayout.getAttribute("fo:margin-right") || pageLayout.getAttribute("margin-right"));
|
|
4930
|
+
if (w !== null) width = w;
|
|
4931
|
+
if (h !== null) height = h;
|
|
4932
|
+
if (mt !== null) marginTop = mt;
|
|
4933
|
+
if (mb !== null) marginBottom = mb;
|
|
4934
|
+
if (ml !== null) marginLeft = ml;
|
|
4935
|
+
if (mr !== null) marginRight = mr;
|
|
4936
|
+
break;
|
|
4937
|
+
}
|
|
4938
|
+
}
|
|
4939
|
+
return { width, height, marginTop, marginBottom, marginLeft, marginRight };
|
|
4940
|
+
}
|
|
4359
4941
|
extractStyles(stylesDoc, contentDoc) {
|
|
4360
4942
|
const map = /* @__PURE__ */ new Map();
|
|
4361
4943
|
const styleNodes = [];
|
|
@@ -4378,14 +4960,21 @@ var OpenDocumentPlugin = class {
|
|
|
4378
4960
|
if (color) css += `color: ${color}; `;
|
|
4379
4961
|
if (size) css += `font-size: ${size}; `;
|
|
4380
4962
|
}
|
|
4381
|
-
|
|
4963
|
+
let paraProp = node.querySelector("paragraph-properties, [text-align]");
|
|
4964
|
+
if (!paraProp) {
|
|
4965
|
+
paraProp = Array.from(node.children).find((c) => c.tagName.includes("paragraph-properties")) || null;
|
|
4966
|
+
}
|
|
4382
4967
|
if (paraProp) {
|
|
4383
4968
|
const align = paraProp.getAttribute("fo:text-align") || paraProp.getAttribute("text-align");
|
|
4384
4969
|
const mt = paraProp.getAttribute("fo:margin-top") || paraProp.getAttribute("margin-top");
|
|
4385
4970
|
const mb = paraProp.getAttribute("fo:margin-bottom") || paraProp.getAttribute("margin-bottom");
|
|
4971
|
+
const breakBefore = paraProp.getAttribute("fo:break-before") || paraProp.getAttribute("break-before");
|
|
4972
|
+
const breakAfter = paraProp.getAttribute("fo:break-after") || paraProp.getAttribute("break-after");
|
|
4386
4973
|
if (align) css += `text-align: ${align}; `;
|
|
4387
4974
|
if (mt) css += `margin-top: ${mt}; `;
|
|
4388
4975
|
if (mb) css += `margin-bottom: ${mb}; `;
|
|
4976
|
+
if (breakBefore === "page") css += "page-break-before: always; ";
|
|
4977
|
+
if (breakAfter === "page") css += "page-break-after: always; ";
|
|
4389
4978
|
}
|
|
4390
4979
|
if (css) map.set(name, css);
|
|
4391
4980
|
}
|
|
@@ -4470,6 +5059,8 @@ var OpenDocumentPlugin = class {
|
|
|
4470
5059
|
result += " ";
|
|
4471
5060
|
} else if (tag === "line-break") {
|
|
4472
5061
|
result += "<br/>";
|
|
5062
|
+
} else if (tag === "soft-page-break") {
|
|
5063
|
+
result += '<hr class="odf-page-break" style="page-break-after: always; border: none; margin: 0; padding: 0; height: 0;" />';
|
|
4473
5064
|
} else {
|
|
4474
5065
|
result += el.textContent || "";
|
|
4475
5066
|
}
|
|
@@ -4587,6 +5178,14 @@ var DocPlugin = class {
|
|
|
4587
5178
|
group: "zoom",
|
|
4588
5179
|
execute: () => instance.fitToPage?.()
|
|
4589
5180
|
},
|
|
5181
|
+
{
|
|
5182
|
+
id: "rotate-cw",
|
|
5183
|
+
icon: "rotate-cw",
|
|
5184
|
+
label: "Rotate",
|
|
5185
|
+
type: "button",
|
|
5186
|
+
group: "view",
|
|
5187
|
+
execute: () => instance.rotateCW?.()
|
|
5188
|
+
},
|
|
4590
5189
|
{
|
|
4591
5190
|
id: "copy",
|
|
4592
5191
|
icon: "copy",
|
|
@@ -4622,20 +5221,9 @@ var DocPlugin = class {
|
|
|
4622
5221
|
container.style.overflow = "auto";
|
|
4623
5222
|
container.style.padding = "32px 16px";
|
|
4624
5223
|
container.style.backgroundColor = "#f1f5f9";
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
wrapper.style.margin = "0 auto";
|
|
4629
|
-
wrapper.style.backgroundColor = "#ffffff";
|
|
4630
|
-
wrapper.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4631
|
-
wrapper.style.borderRadius = "4px";
|
|
4632
|
-
wrapper.style.padding = "56px 48px";
|
|
4633
|
-
wrapper.style.minHeight = "100%";
|
|
4634
|
-
wrapper.style.transformOrigin = "top center";
|
|
4635
|
-
wrapper.style.transition = "transform 0.2s ease";
|
|
4636
|
-
wrapper.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4637
|
-
wrapper.style.color = "#1e293b";
|
|
4638
|
-
container.appendChild(wrapper);
|
|
5224
|
+
container.style.display = "flex";
|
|
5225
|
+
container.style.justifyContent = "center";
|
|
5226
|
+
container.style.alignItems = "flex-start";
|
|
4639
5227
|
ctx.container.appendChild(container);
|
|
4640
5228
|
let scale = 1;
|
|
4641
5229
|
let extractedRawText = "";
|
|
@@ -4662,21 +5250,27 @@ var DocPlugin = class {
|
|
|
4662
5250
|
const rawPages = this.splitIntoPages(extractedRawText);
|
|
4663
5251
|
const totalPages = Math.max(1, rawPages.length);
|
|
4664
5252
|
let currentPage = 1;
|
|
4665
|
-
wrapper.innerHTML = "";
|
|
4666
5253
|
const pageCards = [];
|
|
4667
5254
|
for (let i = 0; i < totalPages; i++) {
|
|
4668
5255
|
const pageCard = document.createElement("div");
|
|
4669
5256
|
pageCard.className = "fp-doc-page-card";
|
|
5257
|
+
pageCard.style.width = "816px";
|
|
5258
|
+
pageCard.style.height = "1056px";
|
|
4670
5259
|
pageCard.style.backgroundColor = "#ffffff";
|
|
4671
5260
|
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4672
5261
|
pageCard.style.borderRadius = "4px";
|
|
4673
|
-
pageCard.style.padding = "
|
|
4674
|
-
pageCard.style.
|
|
5262
|
+
pageCard.style.padding = "96px 72px";
|
|
5263
|
+
pageCard.style.boxSizing = "border-box";
|
|
5264
|
+
pageCard.style.overflow = "hidden";
|
|
4675
5265
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
5266
|
+
pageCard.style.transformOrigin = "top center";
|
|
5267
|
+
pageCard.style.transition = "transform 0.2s ease";
|
|
5268
|
+
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
5269
|
+
pageCard.style.color = "#1e293b";
|
|
4676
5270
|
if (isFallback && i === 0) {
|
|
4677
5271
|
pageCard.innerHTML = `
|
|
4678
5272
|
<div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
|
|
4679
|
-
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${
|
|
5273
|
+
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify6__default.default.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
|
|
4680
5274
|
<span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
|
|
4681
5275
|
</div>
|
|
4682
5276
|
${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
|
|
@@ -4684,15 +5278,17 @@ var DocPlugin = class {
|
|
|
4684
5278
|
} else {
|
|
4685
5279
|
pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
|
|
4686
5280
|
}
|
|
4687
|
-
|
|
5281
|
+
container.appendChild(pageCard);
|
|
4688
5282
|
pageCards.push(pageCard);
|
|
4689
5283
|
}
|
|
4690
5284
|
let indicator = null;
|
|
4691
5285
|
if (totalPages > 1) {
|
|
4692
5286
|
indicator = document.createElement("div");
|
|
4693
5287
|
indicator.className = "fp-doc-page-indicator";
|
|
4694
|
-
indicator.style.position = "
|
|
5288
|
+
indicator.style.position = "fixed";
|
|
4695
5289
|
indicator.style.bottom = "16px";
|
|
5290
|
+
indicator.style.left = "50%";
|
|
5291
|
+
indicator.style.transform = "translateX(-50%)";
|
|
4696
5292
|
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4697
5293
|
indicator.style.backdropFilter = "blur(8px)";
|
|
4698
5294
|
indicator.style.color = "#f8fafc";
|
|
@@ -4706,17 +5302,25 @@ var DocPlugin = class {
|
|
|
4706
5302
|
indicator.style.userSelect = "none";
|
|
4707
5303
|
indicator.style.pointerEvents = "none";
|
|
4708
5304
|
indicator.style.textAlign = "center";
|
|
4709
|
-
indicator.style.width = "fit-content";
|
|
4710
|
-
indicator.style.margin = "16px auto 0";
|
|
4711
5305
|
container.appendChild(indicator);
|
|
4712
5306
|
}
|
|
5307
|
+
let rotation = 0;
|
|
5308
|
+
const applyTransform = () => {
|
|
5309
|
+
const activeCard = pageCards[currentPage - 1];
|
|
5310
|
+
if (activeCard) {
|
|
5311
|
+
activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5312
|
+
}
|
|
5313
|
+
};
|
|
4713
5314
|
const showPage = (pageNum) => {
|
|
4714
5315
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
card.style.display =
|
|
4718
|
-
|
|
4719
|
-
|
|
5316
|
+
pageCards.forEach((card, idx) => {
|
|
5317
|
+
if (idx + 1 === currentPage) {
|
|
5318
|
+
card.style.display = "block";
|
|
5319
|
+
card.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5320
|
+
} else {
|
|
5321
|
+
card.style.display = "none";
|
|
5322
|
+
}
|
|
5323
|
+
});
|
|
4720
5324
|
if (indicator) {
|
|
4721
5325
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4722
5326
|
}
|
|
@@ -4725,6 +5329,17 @@ var DocPlugin = class {
|
|
|
4725
5329
|
if (totalPages > 1) {
|
|
4726
5330
|
showPage(1);
|
|
4727
5331
|
}
|
|
5332
|
+
const calculateFitScale = () => {
|
|
5333
|
+
const elW = 816;
|
|
5334
|
+
const elH = 1056;
|
|
5335
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
5336
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
5337
|
+
return Math.min(1.1, Math.min(availW / elW, availH / elH));
|
|
5338
|
+
};
|
|
5339
|
+
setTimeout(() => {
|
|
5340
|
+
scale = calculateFitScale();
|
|
5341
|
+
applyTransform();
|
|
5342
|
+
}, 60);
|
|
4728
5343
|
const cleanup = () => {
|
|
4729
5344
|
indicator?.remove();
|
|
4730
5345
|
container.remove();
|
|
@@ -4737,21 +5352,30 @@ var DocPlugin = class {
|
|
|
4737
5352
|
getCurrentPage: () => currentPage,
|
|
4738
5353
|
goToPage: (page) => showPage(page),
|
|
4739
5354
|
zoomIn: () => {
|
|
4740
|
-
scale += 0.
|
|
4741
|
-
|
|
5355
|
+
scale += 0.15;
|
|
5356
|
+
applyTransform();
|
|
4742
5357
|
},
|
|
4743
5358
|
zoomOut: () => {
|
|
4744
|
-
scale = Math.max(0.2, scale - 0.
|
|
4745
|
-
|
|
5359
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
5360
|
+
applyTransform();
|
|
4746
5361
|
},
|
|
4747
5362
|
getZoom: () => scale,
|
|
4748
5363
|
setZoom: (level) => {
|
|
4749
5364
|
scale = level;
|
|
4750
|
-
|
|
5365
|
+
applyTransform();
|
|
4751
5366
|
},
|
|
4752
5367
|
fitToPage: () => {
|
|
4753
|
-
scale =
|
|
4754
|
-
|
|
5368
|
+
scale = calculateFitScale();
|
|
5369
|
+
rotation = 0;
|
|
5370
|
+
applyTransform();
|
|
5371
|
+
},
|
|
5372
|
+
rotateCW: () => {
|
|
5373
|
+
rotation = (rotation + 90) % 360;
|
|
5374
|
+
applyTransform();
|
|
5375
|
+
},
|
|
5376
|
+
rotateCCW: () => {
|
|
5377
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
5378
|
+
applyTransform();
|
|
4755
5379
|
},
|
|
4756
5380
|
copy: () => {
|
|
4757
5381
|
navigator.clipboard.writeText(extractedRawText);
|
|
@@ -4869,8 +5493,28 @@ var DocPlugin = class {
|
|
|
4869
5493
|
}
|
|
4870
5494
|
splitIntoPages(text) {
|
|
4871
5495
|
if (!text) return [""];
|
|
4872
|
-
const
|
|
4873
|
-
|
|
5496
|
+
const explicitParts = 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);
|
|
5497
|
+
if (explicitParts.length === 0) explicitParts.push(text);
|
|
5498
|
+
const maxLinesPerPage = 48;
|
|
5499
|
+
const finalPages = [];
|
|
5500
|
+
for (const part of explicitParts) {
|
|
5501
|
+
const lines = part.split(/\r?\n/);
|
|
5502
|
+
let currentLines = [];
|
|
5503
|
+
let count = 0;
|
|
5504
|
+
for (const line of lines) {
|
|
5505
|
+
currentLines.push(line);
|
|
5506
|
+
count++;
|
|
5507
|
+
if (count >= maxLinesPerPage) {
|
|
5508
|
+
finalPages.push(currentLines.join("\n"));
|
|
5509
|
+
currentLines = [];
|
|
5510
|
+
count = 0;
|
|
5511
|
+
}
|
|
5512
|
+
}
|
|
5513
|
+
if (currentLines.length > 0) {
|
|
5514
|
+
finalPages.push(currentLines.join("\n"));
|
|
5515
|
+
}
|
|
5516
|
+
}
|
|
5517
|
+
return finalPages.length > 0 ? finalPages : [text];
|
|
4874
5518
|
}
|
|
4875
5519
|
/**
|
|
4876
5520
|
* Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
|
|
@@ -4879,17 +5523,65 @@ var DocPlugin = class {
|
|
|
4879
5523
|
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
|
|
4880
5524
|
let html = "";
|
|
4881
5525
|
let inList = false;
|
|
4882
|
-
|
|
4883
|
-
|
|
5526
|
+
let tableLines = [];
|
|
5527
|
+
const flushTable = () => {
|
|
5528
|
+
if (tableLines.length > 0) {
|
|
5529
|
+
html += '<table style="width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 12px;">';
|
|
5530
|
+
for (const tLine of tableLines) {
|
|
5531
|
+
html += "<tr>";
|
|
5532
|
+
const cols = tLine.split(" ");
|
|
5533
|
+
for (const col of cols) {
|
|
5534
|
+
html += `<td style="border: 1px solid #cbd5e1; padding: 6px 8px;">${DOMPurify6__default.default.sanitize(col.trim())}</td>`;
|
|
5535
|
+
}
|
|
5536
|
+
html += "</tr>";
|
|
5537
|
+
}
|
|
5538
|
+
html += "</table>";
|
|
5539
|
+
tableLines = [];
|
|
5540
|
+
}
|
|
5541
|
+
};
|
|
5542
|
+
let i = 0;
|
|
5543
|
+
while (i < lines.length) {
|
|
5544
|
+
let line = lines[i];
|
|
5545
|
+
let tabCount = (line.match(/\t/g) || []).length;
|
|
5546
|
+
if (tabCount > 0) {
|
|
5547
|
+
let consecutiveTableLines = 1;
|
|
5548
|
+
let j = i + 1;
|
|
5549
|
+
while (j < lines.length) {
|
|
5550
|
+
const nextTabCount = (lines[j].match(/\t/g) || []).length;
|
|
5551
|
+
if (nextTabCount === tabCount) {
|
|
5552
|
+
consecutiveTableLines++;
|
|
5553
|
+
j++;
|
|
5554
|
+
} else {
|
|
5555
|
+
break;
|
|
5556
|
+
}
|
|
5557
|
+
}
|
|
5558
|
+
if (consecutiveTableLines >= 3) {
|
|
5559
|
+
if (inList) {
|
|
5560
|
+
html += "</ul>";
|
|
5561
|
+
inList = false;
|
|
5562
|
+
}
|
|
5563
|
+
tableLines = lines.slice(i, j);
|
|
5564
|
+
flushTable();
|
|
5565
|
+
i = j;
|
|
5566
|
+
continue;
|
|
5567
|
+
}
|
|
5568
|
+
}
|
|
5569
|
+
line = line.trim();
|
|
4884
5570
|
if (!line) {
|
|
4885
5571
|
if (inList) {
|
|
4886
5572
|
html += "</ul>";
|
|
4887
5573
|
inList = false;
|
|
4888
5574
|
}
|
|
5575
|
+
html += '<div style="height: 1.15em;"></div>';
|
|
5576
|
+
i++;
|
|
4889
5577
|
continue;
|
|
4890
5578
|
}
|
|
4891
|
-
if (/^[\x00-\x1F\x7F-\x9F]+$/.test(line))
|
|
4892
|
-
|
|
5579
|
+
if (/^[\x00-\x1F\x7F-\x9F]+$/.test(line)) {
|
|
5580
|
+
i++;
|
|
5581
|
+
continue;
|
|
5582
|
+
}
|
|
5583
|
+
if ((line.includes("Normal.dot") || line.includes("Microsoft Word") || line.includes("Times New Roman")) && line.length < 30) {
|
|
5584
|
+
i++;
|
|
4893
5585
|
continue;
|
|
4894
5586
|
}
|
|
4895
5587
|
if (line.length < 60 && !line.endsWith(".") && (/^[A-Z0-9\s:_-]+$/.test(line) || line.startsWith("#"))) {
|
|
@@ -4897,24 +5589,26 @@ var DocPlugin = class {
|
|
|
4897
5589
|
html += "</ul>";
|
|
4898
5590
|
inList = false;
|
|
4899
5591
|
}
|
|
4900
|
-
html += `<h2 style="font-size:
|
|
5592
|
+
html += `<h2 style="font-size: 16px; font-weight: 700; color: #1e3a8a; margin: 16px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify6__default.default.sanitize(line)}</h2>`;
|
|
4901
5593
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
4902
5594
|
if (!inList) {
|
|
4903
5595
|
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
4904
5596
|
inList = true;
|
|
4905
5597
|
}
|
|
4906
5598
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
4907
|
-
html += `<li style="margin: 4px 0; line-height: 1.
|
|
5599
|
+
html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6__default.default.sanitize(bulletText)}</li>`;
|
|
4908
5600
|
} else {
|
|
4909
5601
|
if (inList) {
|
|
4910
5602
|
html += "</ul>";
|
|
4911
5603
|
inList = false;
|
|
4912
5604
|
}
|
|
4913
|
-
html += `<p style="line-height: 1.
|
|
5605
|
+
html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6__default.default.sanitize(line)}</p>`;
|
|
4914
5606
|
}
|
|
5607
|
+
i++;
|
|
4915
5608
|
}
|
|
4916
5609
|
if (inList) html += "</ul>";
|
|
4917
|
-
|
|
5610
|
+
flushTable();
|
|
5611
|
+
return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify6__default.default.sanitize(filename)})</p>`;
|
|
4918
5612
|
}
|
|
4919
5613
|
};
|
|
4920
5614
|
function docPlugin() {
|
|
@@ -4991,6 +5685,14 @@ var PptPlugin = class {
|
|
|
4991
5685
|
group: "zoom",
|
|
4992
5686
|
execute: () => instance.fitToPage?.()
|
|
4993
5687
|
},
|
|
5688
|
+
{
|
|
5689
|
+
id: "rotate-cw",
|
|
5690
|
+
icon: "rotate-cw",
|
|
5691
|
+
label: "Rotate",
|
|
5692
|
+
type: "button",
|
|
5693
|
+
group: "view",
|
|
5694
|
+
execute: () => instance.rotateCW?.()
|
|
5695
|
+
},
|
|
4994
5696
|
{
|
|
4995
5697
|
id: "download",
|
|
4996
5698
|
icon: "download",
|
|
@@ -5024,22 +5726,36 @@ var PptPlugin = class {
|
|
|
5024
5726
|
const slideCard = document.createElement("div");
|
|
5025
5727
|
slideCard.className = "fp-ppt-slide-card";
|
|
5026
5728
|
slideCard.style.width = "960px";
|
|
5027
|
-
slideCard.style.maxWidth = "
|
|
5729
|
+
slideCard.style.maxWidth = "calc(100% - 32px)";
|
|
5730
|
+
slideCard.style.maxHeight = "calc(100% - 48px)";
|
|
5028
5731
|
slideCard.style.aspectRatio = "16 / 9";
|
|
5029
5732
|
slideCard.style.backgroundColor = "#ffffff";
|
|
5030
5733
|
slideCard.style.boxShadow = "0 12px 40px rgba(0,0,0,0.35)";
|
|
5031
5734
|
slideCard.style.borderRadius = "8px";
|
|
5032
5735
|
slideCard.style.boxSizing = "border-box";
|
|
5033
5736
|
slideCard.style.position = "relative";
|
|
5034
|
-
slideCard.style.overflow = "hidden";
|
|
5035
|
-
slideCard.style.transformOrigin = "center center";
|
|
5036
5737
|
slideCard.style.transition = "transform 0.2s ease";
|
|
5738
|
+
slideCard.style.transformOrigin = "center center";
|
|
5739
|
+
slideCard.style.flexShrink = "0";
|
|
5037
5740
|
container.appendChild(slideCard);
|
|
5038
5741
|
ctx.container.appendChild(container);
|
|
5039
5742
|
let scale = 1;
|
|
5743
|
+
let rotation = 0;
|
|
5040
5744
|
let currentSlide = 1;
|
|
5041
5745
|
let slides = [];
|
|
5042
5746
|
const createdBlobUrls = [];
|
|
5747
|
+
const calculateFitScale = () => {
|
|
5748
|
+
const availW = Math.max(200, container.clientWidth - 48);
|
|
5749
|
+
const availH = Math.max(200, container.clientHeight - 72);
|
|
5750
|
+
return Math.min(1, Math.min(availW / 960, availH / 540));
|
|
5751
|
+
};
|
|
5752
|
+
const applyTransform = () => {
|
|
5753
|
+
slideCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5754
|
+
};
|
|
5755
|
+
setTimeout(() => {
|
|
5756
|
+
scale = calculateFitScale();
|
|
5757
|
+
applyTransform();
|
|
5758
|
+
}, 60);
|
|
5043
5759
|
try {
|
|
5044
5760
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
5045
5761
|
const pptStream = cfbf.readStream("PowerPoint Document");
|
|
@@ -5070,7 +5786,7 @@ var PptPlugin = class {
|
|
|
5070
5786
|
if (s.pictureUrl) {
|
|
5071
5787
|
contentHtml = `
|
|
5072
5788
|
<div style="flex: 1; display: flex; justify-content: center; align-items: center; padding: 12px; overflow: hidden;">
|
|
5073
|
-
<img src="${s.pictureUrl}" alt="${
|
|
5789
|
+
<img src="${s.pictureUrl}" alt="${DOMPurify6__default.default.sanitize(s.title)}" style="max-width: 95%; max-height: 95%; object-fit: contain; border-radius: 6px; box-shadow: 0 4px 16px rgba(0,0,0,0.1); background: #ffffff;" />
|
|
5074
5790
|
</div>
|
|
5075
5791
|
`;
|
|
5076
5792
|
} else if (s.tableColumns.length > 0) {
|
|
@@ -5080,7 +5796,7 @@ var PptPlugin = class {
|
|
|
5080
5796
|
<table style="width: 100%; border-collapse: collapse; border: 1px solid #cbd5e1; border-radius: 6px; overflow: hidden; background: #ffffff;">
|
|
5081
5797
|
<thead>
|
|
5082
5798
|
<tr style="background: #e2e8f0; color: #1e293b; font-weight: 600; font-size: 14px;">
|
|
5083
|
-
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${
|
|
5799
|
+
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify6__default.default.sanitize(c)}</th>`).join("")}
|
|
5084
5800
|
</tr>
|
|
5085
5801
|
</thead>
|
|
5086
5802
|
<tbody>
|
|
@@ -5096,7 +5812,7 @@ var PptPlugin = class {
|
|
|
5096
5812
|
} else {
|
|
5097
5813
|
const pTags = s.paragraphs.map((p) => {
|
|
5098
5814
|
const lines = p.split(/[\r\n]+/).map((l) => l.trim()).filter(Boolean);
|
|
5099
|
-
return lines.map((l) => `<p style="margin: 0 0 14px; font-size: 14px; line-height: 1.65; color: #334155; text-align: justify;">${
|
|
5815
|
+
return lines.map((l) => `<p style="margin: 0 0 14px; font-size: 14px; line-height: 1.65; color: #334155; text-align: justify;">${DOMPurify6__default.default.sanitize(l)}</p>`).join("");
|
|
5100
5816
|
}).join("");
|
|
5101
5817
|
contentHtml = `
|
|
5102
5818
|
<div style="flex: 1; overflow: auto; padding: 4px 8px; display: flex; flex-direction: column; justify-content: flex-start;">
|
|
@@ -5109,11 +5825,11 @@ var PptPlugin = class {
|
|
|
5109
5825
|
<!-- Header Banner matching PowerPoint design -->
|
|
5110
5826
|
<div style="background: linear-gradient(90deg, #a3e635 0%, #84cc16 100%); padding: 12px 24px; border-radius: 4px; display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.08); flex-shrink: 0;">
|
|
5111
5827
|
<h1 style="margin: 0; font-size: 26px; font-weight: 700; color: #1e293b; letter-spacing: -0.3px;">
|
|
5112
|
-
${
|
|
5828
|
+
${DOMPurify6__default.default.sanitize(s.title)}
|
|
5113
5829
|
</h1>
|
|
5114
5830
|
${s.subtitle ? `
|
|
5115
5831
|
<span style="background: #38bdf8; color: #ffffff; padding: 4px 14px; border-radius: 4px; font-weight: 700; font-size: 13px; letter-spacing: 0.5px; box-shadow: 0 1px 4px rgba(0,0,0,0.15);">
|
|
5116
|
-
${
|
|
5832
|
+
${DOMPurify6__default.default.sanitize(s.subtitle)}
|
|
5117
5833
|
</span>
|
|
5118
5834
|
` : `
|
|
5119
5835
|
<span style="font-size: 12px; color: #365314; font-weight: 600;">
|
|
@@ -5140,21 +5856,30 @@ var PptPlugin = class {
|
|
|
5140
5856
|
return {
|
|
5141
5857
|
destroy: cleanup,
|
|
5142
5858
|
zoomIn: () => {
|
|
5143
|
-
scale += 0.
|
|
5144
|
-
|
|
5859
|
+
scale += 0.15;
|
|
5860
|
+
applyTransform();
|
|
5145
5861
|
},
|
|
5146
5862
|
zoomOut: () => {
|
|
5147
|
-
scale = Math.max(0.
|
|
5148
|
-
|
|
5863
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
5864
|
+
applyTransform();
|
|
5149
5865
|
},
|
|
5150
5866
|
getZoom: () => scale,
|
|
5151
5867
|
setZoom: (level) => {
|
|
5152
5868
|
scale = level;
|
|
5153
|
-
|
|
5869
|
+
applyTransform();
|
|
5154
5870
|
},
|
|
5155
5871
|
fitToPage: () => {
|
|
5156
|
-
scale =
|
|
5157
|
-
|
|
5872
|
+
scale = calculateFitScale();
|
|
5873
|
+
rotation = 0;
|
|
5874
|
+
applyTransform();
|
|
5875
|
+
},
|
|
5876
|
+
rotateCW: () => {
|
|
5877
|
+
rotation = (rotation + 90) % 360;
|
|
5878
|
+
applyTransform();
|
|
5879
|
+
},
|
|
5880
|
+
rotateCCW: () => {
|
|
5881
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
5882
|
+
applyTransform();
|
|
5158
5883
|
},
|
|
5159
5884
|
goToPage: (page) => {
|
|
5160
5885
|
if (page >= 1 && page <= totalSlides) {
|