@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/react.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { memo, forwardRef, useRef, useImperativeHandle, useEffect } from 'react';
|
|
2
|
-
import
|
|
2
|
+
import DOMPurify6 from 'dompurify';
|
|
3
3
|
import * as pdfjsLib from 'pdfjs-dist';
|
|
4
4
|
import * as docx from 'docx-preview';
|
|
5
5
|
import { unzipSync, strFromU8, unzip } from 'fflate';
|
|
@@ -358,7 +358,7 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
358
358
|
if (magicMime === "application/zip") {
|
|
359
359
|
const ooxmlMime = detectOoxmlType(buffer);
|
|
360
360
|
if (ooxmlMime && ooxmlMime !== "application/zip") {
|
|
361
|
-
metadata.mimeType = ooxmlMime;
|
|
361
|
+
metadata.mimeType = metadata.mimeType ?? ooxmlMime;
|
|
362
362
|
if (ooxmlMime.includes("wordprocessing")) metadata.extension = metadata.extension ?? ".docx";
|
|
363
363
|
else if (ooxmlMime.includes("spreadsheet")) metadata.extension = metadata.extension ?? ".xlsx";
|
|
364
364
|
else if (ooxmlMime.includes("presentation")) metadata.extension = metadata.extension ?? ".pptx";
|
|
@@ -387,7 +387,7 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
387
387
|
return { buffer, metadata };
|
|
388
388
|
}
|
|
389
389
|
function sanitizeSVG(svg) {
|
|
390
|
-
return
|
|
390
|
+
return DOMPurify6.sanitize(svg, {
|
|
391
391
|
USE_PROFILES: { svg: true, svgFilters: true }
|
|
392
392
|
});
|
|
393
393
|
}
|
|
@@ -706,6 +706,8 @@ var FilePreviewViewer = class {
|
|
|
706
706
|
keyHandler = null;
|
|
707
707
|
currentContainer = null;
|
|
708
708
|
currentOptions = {};
|
|
709
|
+
resizeObserver = null;
|
|
710
|
+
fullscreenHandler = null;
|
|
709
711
|
/**
|
|
710
712
|
* Register a preview plugin.
|
|
711
713
|
*/
|
|
@@ -778,12 +780,31 @@ var FilePreviewViewer = class {
|
|
|
778
780
|
label: "Toggle Fullscreen",
|
|
779
781
|
type: "button",
|
|
780
782
|
group: "view",
|
|
781
|
-
execute: () => {
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
783
|
+
execute: async () => {
|
|
784
|
+
try {
|
|
785
|
+
const isNativeFs = !!document.fullscreenElement;
|
|
786
|
+
const isCssFs = this.wrapperEl?.classList.contains("fp-fullscreen-active");
|
|
787
|
+
if (!isNativeFs && !isCssFs) {
|
|
788
|
+
if (this.wrapperEl?.requestFullscreen) {
|
|
789
|
+
await this.wrapperEl.requestFullscreen().catch(() => {
|
|
790
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
791
|
+
});
|
|
792
|
+
} else {
|
|
793
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
794
|
+
}
|
|
795
|
+
} else {
|
|
796
|
+
if (document.fullscreenElement) {
|
|
797
|
+
await document.exitFullscreen().catch(() => {
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
801
|
+
}
|
|
802
|
+
} catch {
|
|
803
|
+
this.wrapperEl?.classList.toggle("fp-fullscreen-active");
|
|
786
804
|
}
|
|
805
|
+
setTimeout(() => {
|
|
806
|
+
this.activeInstance?.fitToPage?.();
|
|
807
|
+
}, 120);
|
|
787
808
|
}
|
|
788
809
|
});
|
|
789
810
|
}
|
|
@@ -833,6 +854,15 @@ var FilePreviewViewer = class {
|
|
|
833
854
|
window.removeEventListener("keydown", this.keyHandler);
|
|
834
855
|
this.keyHandler = null;
|
|
835
856
|
}
|
|
857
|
+
if (this.resizeObserver) {
|
|
858
|
+
this.resizeObserver.disconnect();
|
|
859
|
+
this.resizeObserver = null;
|
|
860
|
+
}
|
|
861
|
+
if (this.fullscreenHandler) {
|
|
862
|
+
document.removeEventListener("fullscreenchange", this.fullscreenHandler);
|
|
863
|
+
document.removeEventListener("webkitfullscreenchange", this.fullscreenHandler);
|
|
864
|
+
this.fullscreenHandler = null;
|
|
865
|
+
}
|
|
836
866
|
this.abort();
|
|
837
867
|
this.destroyInstance();
|
|
838
868
|
this.toolbar?.destroy();
|
|
@@ -912,6 +942,25 @@ var FilePreviewViewer = class {
|
|
|
912
942
|
this.thumbnailPanel = new ThumbnailPanel(thumbnailEl);
|
|
913
943
|
this.setupKeyboardShortcuts();
|
|
914
944
|
this.setupDragAndDrop(container, options);
|
|
945
|
+
this.setupResizeAndFullscreenListeners();
|
|
946
|
+
}
|
|
947
|
+
setupResizeAndFullscreenListeners() {
|
|
948
|
+
if (this.fullscreenHandler) return;
|
|
949
|
+
this.fullscreenHandler = () => {
|
|
950
|
+
setTimeout(() => {
|
|
951
|
+
this.activeInstance?.fitToPage?.();
|
|
952
|
+
}, 100);
|
|
953
|
+
};
|
|
954
|
+
document.addEventListener("fullscreenchange", this.fullscreenHandler);
|
|
955
|
+
document.addEventListener("webkitfullscreenchange", this.fullscreenHandler);
|
|
956
|
+
if (typeof ResizeObserver !== "undefined" && this.contentEl) {
|
|
957
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
958
|
+
if (this.activeInstance && (!this.activeInstance.getZoom || Math.abs((this.activeInstance.getZoom?.() ?? 1) - 1) < 0.05)) {
|
|
959
|
+
this.activeInstance.fitToPage?.();
|
|
960
|
+
}
|
|
961
|
+
});
|
|
962
|
+
this.resizeObserver.observe(this.contentEl);
|
|
963
|
+
}
|
|
915
964
|
}
|
|
916
965
|
setupKeyboardShortcuts() {
|
|
917
966
|
if (this.keyHandler) return;
|
|
@@ -1303,7 +1352,8 @@ var PdfPlugin = class {
|
|
|
1303
1352
|
container.style.display = "flex";
|
|
1304
1353
|
container.style.flexDirection = "column";
|
|
1305
1354
|
container.style.alignItems = "center";
|
|
1306
|
-
container.style.
|
|
1355
|
+
container.style.justifyContent = "flex-start";
|
|
1356
|
+
container.style.padding = "20px 16px";
|
|
1307
1357
|
container.style.backgroundColor = "#0f172a";
|
|
1308
1358
|
container.style.boxSizing = "border-box";
|
|
1309
1359
|
container.style.position = "relative";
|
|
@@ -1316,7 +1366,8 @@ var PdfPlugin = class {
|
|
|
1316
1366
|
pageCard.style.lineHeight = "0";
|
|
1317
1367
|
pageCard.style.transition = "transform 0.15s ease";
|
|
1318
1368
|
pageCard.style.position = "relative";
|
|
1319
|
-
|
|
1369
|
+
pageCard.style.flexShrink = "0";
|
|
1370
|
+
let canvas = document.createElement("canvas");
|
|
1320
1371
|
pageCard.appendChild(canvas);
|
|
1321
1372
|
container.appendChild(pageCard);
|
|
1322
1373
|
const indicator = document.createElement("div");
|
|
@@ -1358,14 +1409,22 @@ var PdfPlugin = class {
|
|
|
1358
1409
|
}
|
|
1359
1410
|
currentRenderTask = null;
|
|
1360
1411
|
}
|
|
1412
|
+
const newCanvas = document.createElement("canvas");
|
|
1413
|
+
pageCard.replaceChild(newCanvas, canvas);
|
|
1414
|
+
canvas = newCanvas;
|
|
1361
1415
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1362
1416
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1363
1417
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1364
1418
|
const page = await pdfDoc.getPage(currentPage);
|
|
1365
1419
|
const containerWidth = container.clientWidth || 900;
|
|
1420
|
+
const containerHeight = container.clientHeight || 700;
|
|
1366
1421
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1367
|
-
const
|
|
1368
|
-
const
|
|
1422
|
+
const availWidth = Math.max(100, containerWidth - 48);
|
|
1423
|
+
const availHeight = Math.max(100, containerHeight - 88);
|
|
1424
|
+
const scaleW = availWidth / unscaledVp.width;
|
|
1425
|
+
const scaleH = availHeight / unscaledVp.height;
|
|
1426
|
+
const fitScale = Math.min(scaleW, scaleH);
|
|
1427
|
+
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1369
1428
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
1370
1429
|
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
1371
1430
|
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
@@ -1390,7 +1449,19 @@ var PdfPlugin = class {
|
|
|
1390
1449
|
}
|
|
1391
1450
|
};
|
|
1392
1451
|
await renderPage(1);
|
|
1452
|
+
let resizeTimer = null;
|
|
1453
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
1454
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1455
|
+
resizeTimer = setTimeout(() => {
|
|
1456
|
+
if (Math.abs(zoomScale - 1) < 0.05) {
|
|
1457
|
+
renderPage(currentPage);
|
|
1458
|
+
}
|
|
1459
|
+
}, 150);
|
|
1460
|
+
});
|
|
1461
|
+
resizeObserver.observe(container);
|
|
1393
1462
|
const cleanup = () => {
|
|
1463
|
+
resizeObserver.disconnect();
|
|
1464
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1394
1465
|
if (currentRenderTask) {
|
|
1395
1466
|
try {
|
|
1396
1467
|
currentRenderTask.cancel();
|
|
@@ -1422,6 +1493,7 @@ var PdfPlugin = class {
|
|
|
1422
1493
|
},
|
|
1423
1494
|
fitToPage: () => {
|
|
1424
1495
|
zoomScale = 1;
|
|
1496
|
+
rotation = 0;
|
|
1425
1497
|
renderPage(currentPage);
|
|
1426
1498
|
},
|
|
1427
1499
|
rotateCW: () => {
|
|
@@ -1872,6 +1944,14 @@ var DocxPlugin = class {
|
|
|
1872
1944
|
group: "zoom",
|
|
1873
1945
|
execute: () => instance.fitToPage?.()
|
|
1874
1946
|
},
|
|
1947
|
+
{
|
|
1948
|
+
id: "rotate-cw",
|
|
1949
|
+
icon: "rotate-cw",
|
|
1950
|
+
label: "Rotate",
|
|
1951
|
+
type: "button",
|
|
1952
|
+
group: "view",
|
|
1953
|
+
execute: () => instance.rotateCW?.()
|
|
1954
|
+
},
|
|
1875
1955
|
{
|
|
1876
1956
|
id: "download",
|
|
1877
1957
|
icon: "download",
|
|
@@ -2008,6 +2088,26 @@ var DocxPlugin = class {
|
|
|
2008
2088
|
if (totalPages > 1) {
|
|
2009
2089
|
showPage(1);
|
|
2010
2090
|
}
|
|
2091
|
+
scale = 1;
|
|
2092
|
+
let rotation = 0;
|
|
2093
|
+
const calculateFitScale = () => {
|
|
2094
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.firstElementChild || wrapper;
|
|
2095
|
+
const elW = activeEl.offsetWidth || 816;
|
|
2096
|
+
const elH = activeEl.offsetHeight || 1056;
|
|
2097
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
2098
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
2099
|
+
const sW = availW / elW;
|
|
2100
|
+
const sH = availH / elH;
|
|
2101
|
+
return Math.min(1.1, Math.min(sW, sH));
|
|
2102
|
+
};
|
|
2103
|
+
const applyTransform = () => {
|
|
2104
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2105
|
+
wrapper.style.transformOrigin = "top center";
|
|
2106
|
+
};
|
|
2107
|
+
setTimeout(() => {
|
|
2108
|
+
scale = calculateFitScale();
|
|
2109
|
+
applyTransform();
|
|
2110
|
+
}, 60);
|
|
2011
2111
|
const cleanup = () => {
|
|
2012
2112
|
indicator?.remove();
|
|
2013
2113
|
for (const url of createdBlobUrls) {
|
|
@@ -2026,21 +2126,30 @@ var DocxPlugin = class {
|
|
|
2026
2126
|
showPage(page);
|
|
2027
2127
|
},
|
|
2028
2128
|
zoomIn: () => {
|
|
2029
|
-
scale += 0.
|
|
2030
|
-
|
|
2129
|
+
scale += 0.15;
|
|
2130
|
+
applyTransform();
|
|
2031
2131
|
},
|
|
2032
2132
|
zoomOut: () => {
|
|
2033
|
-
scale = Math.max(0.2, scale - 0.
|
|
2034
|
-
|
|
2133
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
2134
|
+
applyTransform();
|
|
2035
2135
|
},
|
|
2036
2136
|
getZoom: () => scale,
|
|
2037
2137
|
setZoom: (level) => {
|
|
2038
2138
|
scale = level;
|
|
2039
|
-
|
|
2139
|
+
applyTransform();
|
|
2040
2140
|
},
|
|
2041
2141
|
fitToPage: () => {
|
|
2042
|
-
scale =
|
|
2043
|
-
|
|
2142
|
+
scale = calculateFitScale();
|
|
2143
|
+
rotation = 0;
|
|
2144
|
+
applyTransform();
|
|
2145
|
+
},
|
|
2146
|
+
rotateCW: () => {
|
|
2147
|
+
rotation = (rotation + 90) % 360;
|
|
2148
|
+
applyTransform();
|
|
2149
|
+
},
|
|
2150
|
+
rotateCCW: () => {
|
|
2151
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
2152
|
+
applyTransform();
|
|
2044
2153
|
},
|
|
2045
2154
|
download: () => {
|
|
2046
2155
|
const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
|
|
@@ -2100,90 +2209,149 @@ var DocxPlugin = class {
|
|
|
2100
2209
|
console.warn("[DocxPlugin] Error parsing relationships:", relsErr);
|
|
2101
2210
|
}
|
|
2102
2211
|
}
|
|
2103
|
-
const
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2212
|
+
const sectPrs = Array.from(doc.getElementsByTagNameNS("*", "sectPr"));
|
|
2213
|
+
const lastSectPr = sectPrs[sectPrs.length - 1];
|
|
2214
|
+
let defaultW = 12240;
|
|
2215
|
+
let defaultH = 15840;
|
|
2216
|
+
let margins = { top: 1440, right: 1440, bottom: 1440, left: 1440 };
|
|
2217
|
+
if (lastSectPr) {
|
|
2218
|
+
const pgSz = lastSectPr.getElementsByTagNameNS("*", "pgSz")[0];
|
|
2219
|
+
if (pgSz) {
|
|
2220
|
+
defaultW = parseInt(pgSz.getAttribute("w:w") || pgSz.getAttribute("w") || "12240", 10);
|
|
2221
|
+
defaultH = parseInt(pgSz.getAttribute("w:h") || pgSz.getAttribute("h") || "15840", 10);
|
|
2222
|
+
}
|
|
2223
|
+
const pgMar = lastSectPr.getElementsByTagNameNS("*", "pgMar")[0];
|
|
2224
|
+
if (pgMar) {
|
|
2225
|
+
margins.top = parseInt(pgMar.getAttribute("w:top") || pgMar.getAttribute("top") || "1440", 10);
|
|
2226
|
+
margins.bottom = parseInt(pgMar.getAttribute("w:bottom") || pgMar.getAttribute("bottom") || "1440", 10);
|
|
2227
|
+
margins.left = parseInt(pgMar.getAttribute("w:left") || pgMar.getAttribute("left") || "1440", 10);
|
|
2228
|
+
margins.right = parseInt(pgMar.getAttribute("w:right") || pgMar.getAttribute("right") || "1440", 10);
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
const createPageCard = () => {
|
|
2232
|
+
const card = document.createElement("div");
|
|
2233
|
+
card.className = "fp-docx-page-card";
|
|
2234
|
+
card.style.backgroundColor = "#ffffff";
|
|
2235
|
+
card.style.borderRadius = "4px";
|
|
2236
|
+
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
2237
|
+
card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
2238
|
+
card.style.color = "#1e293b";
|
|
2239
|
+
card.style.lineHeight = "1.6";
|
|
2240
|
+
card.style.boxSizing = "border-box";
|
|
2241
|
+
card.style.overflow = "hidden";
|
|
2242
|
+
card.style.position = "relative";
|
|
2243
|
+
card.style.marginBottom = "24px";
|
|
2244
|
+
card.style.width = `${defaultW / 15}px`;
|
|
2245
|
+
card.style.height = `${defaultH / 15}px`;
|
|
2246
|
+
card.style.padding = `${margins.top / 15}px ${margins.right / 15}px ${margins.bottom / 15}px ${margins.left / 15}px`;
|
|
2247
|
+
return card;
|
|
2248
|
+
};
|
|
2249
|
+
let currentCard = createPageCard();
|
|
2250
|
+
let currentHtml = "";
|
|
2251
|
+
const pages = [{ card: currentCard, html: "" }];
|
|
2252
|
+
const flushHtml = () => {
|
|
2253
|
+
pages[pages.length - 1].html += currentHtml;
|
|
2254
|
+
currentHtml = "";
|
|
2255
|
+
};
|
|
2256
|
+
const newPage = () => {
|
|
2257
|
+
flushHtml();
|
|
2258
|
+
currentCard = createPageCard();
|
|
2259
|
+
pages.push({ card: currentCard, html: "" });
|
|
2260
|
+
};
|
|
2112
2261
|
const body = doc.getElementsByTagNameNS("*", "body")[0] || doc.documentElement;
|
|
2113
|
-
let html = "";
|
|
2114
2262
|
for (const child of Array.from(body.children)) {
|
|
2115
2263
|
const tag = child.localName || child.nodeName.split(":").pop();
|
|
2116
2264
|
if (tag === "p") {
|
|
2117
2265
|
const pStyle = child.getElementsByTagNameNS("*", "pStyle")[0];
|
|
2118
2266
|
const styleVal = pStyle?.getAttribute("w:val") || pStyle?.getAttribute("val") || "";
|
|
2119
2267
|
const numPr = child.getElementsByTagNameNS("*", "numPr")[0];
|
|
2120
|
-
const
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2268
|
+
const chunks = this.extractParagraphChunks(child, imageMap);
|
|
2269
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
2270
|
+
if (i > 0) {
|
|
2271
|
+
newPage();
|
|
2272
|
+
}
|
|
2273
|
+
const textContent = chunks[i];
|
|
2274
|
+
if (!textContent.trim() && !textContent.includes("<img")) {
|
|
2275
|
+
currentHtml += '<div style="height: 10px;"></div>';
|
|
2276
|
+
continue;
|
|
2277
|
+
}
|
|
2278
|
+
const lowerStyle = styleVal.toLowerCase();
|
|
2279
|
+
if (lowerStyle.includes("title")) {
|
|
2280
|
+
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>`;
|
|
2281
|
+
} else if (lowerStyle.includes("heading1") || styleVal === "1") {
|
|
2282
|
+
currentHtml += `<h2 style="font-size: 22px; font-weight: 700; color: #1e40af; margin: 20px 0 10px;">${textContent}</h2>`;
|
|
2283
|
+
} else if (lowerStyle.includes("heading2") || styleVal === "2") {
|
|
2284
|
+
currentHtml += `<h3 style="font-size: 18px; font-weight: 600; color: #2563eb; margin: 16px 0 8px;">${textContent}</h3>`;
|
|
2285
|
+
} else if (lowerStyle.includes("heading3") || styleVal === "3") {
|
|
2286
|
+
currentHtml += `<h4 style="font-size: 15px; font-weight: 600; color: #334155; margin: 12px 0 6px;">${textContent}</h4>`;
|
|
2287
|
+
} else if (numPr) {
|
|
2288
|
+
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>`;
|
|
2289
|
+
} else {
|
|
2290
|
+
currentHtml += `<p style="margin: 8px 0; font-size: 14px;">${textContent}</p>`;
|
|
2291
|
+
}
|
|
2138
2292
|
}
|
|
2139
2293
|
} else if (tag === "tbl") {
|
|
2140
|
-
|
|
2294
|
+
currentHtml += '<table style="width: 100%; border-collapse: collapse; margin: 20px 0; border: 1px solid #cbd5e1;">';
|
|
2141
2295
|
const rows = Array.from(child.getElementsByTagNameNS("*", "tr"));
|
|
2142
2296
|
rows.forEach((tr, rIdx) => {
|
|
2143
|
-
|
|
2297
|
+
currentHtml += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
|
|
2144
2298
|
const cells = Array.from(tr.getElementsByTagNameNS("*", "tc"));
|
|
2145
2299
|
cells.forEach((tc) => {
|
|
2146
2300
|
const cellText = this.extractParagraphHtml(tc, imageMap);
|
|
2147
|
-
|
|
2301
|
+
currentHtml += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || " "}</td>`;
|
|
2148
2302
|
});
|
|
2149
|
-
|
|
2303
|
+
currentHtml += "</tr>";
|
|
2150
2304
|
});
|
|
2151
|
-
|
|
2305
|
+
currentHtml += "</table>";
|
|
2152
2306
|
}
|
|
2153
2307
|
}
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2308
|
+
flushHtml();
|
|
2309
|
+
for (const page of pages) {
|
|
2310
|
+
page.card.innerHTML = DOMPurify6.sanitize(page.html, {
|
|
2311
|
+
ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "s", "strike", "img", "div", "br"],
|
|
2312
|
+
ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
|
|
2313
|
+
});
|
|
2314
|
+
wrapper.appendChild(page.card);
|
|
2315
|
+
}
|
|
2159
2316
|
}
|
|
2160
2317
|
extractParagraphHtml(pElement, imageMap = {}) {
|
|
2161
|
-
|
|
2318
|
+
return this.extractParagraphChunks(pElement, imageMap).join("<br/>");
|
|
2319
|
+
}
|
|
2320
|
+
extractParagraphChunks(pElement, imageMap = {}) {
|
|
2321
|
+
const chunks = [""];
|
|
2322
|
+
let currentChunkIndex = 0;
|
|
2162
2323
|
const drawings = Array.from(pElement.getElementsByTagNameNS("*", "drawing"));
|
|
2163
2324
|
for (const drawing of drawings) {
|
|
2164
2325
|
const blip = drawing.getElementsByTagNameNS("*", "blip")[0];
|
|
2165
2326
|
const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
|
|
2166
2327
|
if (rId && imageMap[rId]) {
|
|
2167
|
-
|
|
2328
|
+
chunks[currentChunkIndex] += `<div style="text-align:center; margin: 12px 0;"><img src="${imageMap[rId]}" style="max-width: 100%; height: auto; border-radius: 4px;" /></div>`;
|
|
2168
2329
|
}
|
|
2169
2330
|
}
|
|
2170
2331
|
const runs = Array.from(pElement.getElementsByTagNameNS("*", "r"));
|
|
2171
|
-
if (runs.length === 0 && !
|
|
2172
|
-
|
|
2332
|
+
if (runs.length === 0 && !chunks[currentChunkIndex]) {
|
|
2333
|
+
chunks[currentChunkIndex] = DOMPurify6.sanitize(pElement.textContent || "");
|
|
2334
|
+
return chunks;
|
|
2173
2335
|
}
|
|
2174
2336
|
for (const r of runs) {
|
|
2175
2337
|
const blip = r.getElementsByTagNameNS("*", "blip")[0] || r.getElementsByTagNameNS("*", "imagedata")[0];
|
|
2176
2338
|
const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
|
|
2177
2339
|
if (rId && imageMap[rId]) {
|
|
2178
|
-
|
|
2340
|
+
chunks[currentChunkIndex] += `<img src="${imageMap[rId]}" style="max-width: 100%; height: auto; display: inline-block; margin: 4px;" />`;
|
|
2179
2341
|
}
|
|
2180
|
-
const brs = r.getElementsByTagNameNS("*", "br");
|
|
2181
|
-
for (
|
|
2182
|
-
|
|
2342
|
+
const brs = Array.from(r.getElementsByTagNameNS("*", "br"));
|
|
2343
|
+
for (const br of brs) {
|
|
2344
|
+
const type = br.getAttribute("w:type") || br.getAttribute("type");
|
|
2345
|
+
if (type === "page") {
|
|
2346
|
+
chunks.push("");
|
|
2347
|
+
currentChunkIndex++;
|
|
2348
|
+
} else {
|
|
2349
|
+
chunks[currentChunkIndex] += "<br/>";
|
|
2350
|
+
}
|
|
2183
2351
|
}
|
|
2184
2352
|
const tabs = r.getElementsByTagNameNS("*", "tab");
|
|
2185
2353
|
if (tabs.length > 0) {
|
|
2186
|
-
|
|
2354
|
+
chunks[currentChunkIndex] += " ";
|
|
2187
2355
|
}
|
|
2188
2356
|
const rPr = r.getElementsByTagNameNS("*", "rPr")[0];
|
|
2189
2357
|
const isBold = !!rPr?.getElementsByTagNameNS("*", "b")[0];
|
|
@@ -2197,7 +2365,7 @@ var DocxPlugin = class {
|
|
|
2197
2365
|
const texts = Array.from(r.getElementsByTagNameNS("*", "t"));
|
|
2198
2366
|
let text = texts.map((t) => t.textContent || "").join("");
|
|
2199
2367
|
if (!text) continue;
|
|
2200
|
-
text =
|
|
2368
|
+
text = DOMPurify6.sanitize(text);
|
|
2201
2369
|
let styles = "";
|
|
2202
2370
|
if (isBold) styles += "font-weight: bold; ";
|
|
2203
2371
|
if (isItalic) styles += "font-style: italic; ";
|
|
@@ -2209,12 +2377,12 @@ var DocxPlugin = class {
|
|
|
2209
2377
|
if (!isNaN(pt) && pt > 0) styles += `font-size: ${pt}pt; `;
|
|
2210
2378
|
}
|
|
2211
2379
|
if (styles) {
|
|
2212
|
-
|
|
2380
|
+
chunks[currentChunkIndex] += `<span style="${styles}">${text}</span>`;
|
|
2213
2381
|
} else {
|
|
2214
|
-
|
|
2382
|
+
chunks[currentChunkIndex] += text;
|
|
2215
2383
|
}
|
|
2216
2384
|
}
|
|
2217
|
-
return
|
|
2385
|
+
return chunks;
|
|
2218
2386
|
}
|
|
2219
2387
|
renderBinaryDocFallback(ctx, wrapper) {
|
|
2220
2388
|
const card = document.createElement("div");
|
|
@@ -2231,14 +2399,14 @@ var DocxPlugin = class {
|
|
|
2231
2399
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
2232
2400
|
if (wordDocStream && wordDocStream.length >= 512) {
|
|
2233
2401
|
const text2 = this.extractReadableStrings(wordDocStream);
|
|
2234
|
-
card.innerHTML = `<div style="white-space: pre-wrap;">${
|
|
2402
|
+
card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6.sanitize(text2)}</div>`;
|
|
2235
2403
|
wrapper.appendChild(card);
|
|
2236
2404
|
return;
|
|
2237
2405
|
}
|
|
2238
2406
|
} catch {
|
|
2239
2407
|
}
|
|
2240
2408
|
const text = this.extractReadableStrings(new Uint8Array(ctx.buffer));
|
|
2241
|
-
card.innerHTML = `<div style="white-space: pre-wrap;">${
|
|
2409
|
+
card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6.sanitize(text)}</div>`;
|
|
2242
2410
|
wrapper.appendChild(card);
|
|
2243
2411
|
}
|
|
2244
2412
|
extractReadableStrings(bytes) {
|
|
@@ -2334,6 +2502,26 @@ var ExcelPlugin = class {
|
|
|
2334
2502
|
instance.zoomIn?.();
|
|
2335
2503
|
}
|
|
2336
2504
|
},
|
|
2505
|
+
{
|
|
2506
|
+
id: "fit-page",
|
|
2507
|
+
icon: "fit-page",
|
|
2508
|
+
label: "Fit to View",
|
|
2509
|
+
type: "button",
|
|
2510
|
+
group: "zoom",
|
|
2511
|
+
execute: () => {
|
|
2512
|
+
instance.fitToPage?.();
|
|
2513
|
+
}
|
|
2514
|
+
},
|
|
2515
|
+
{
|
|
2516
|
+
id: "rotate-cw",
|
|
2517
|
+
icon: "rotate-cw",
|
|
2518
|
+
label: "Rotate",
|
|
2519
|
+
type: "button",
|
|
2520
|
+
group: "view",
|
|
2521
|
+
execute: () => {
|
|
2522
|
+
instance.rotateCW?.();
|
|
2523
|
+
}
|
|
2524
|
+
},
|
|
2337
2525
|
{
|
|
2338
2526
|
id: "download",
|
|
2339
2527
|
icon: "download",
|
|
@@ -2384,9 +2572,23 @@ var ExcelPlugin = class {
|
|
|
2384
2572
|
container.appendChild(tabsArea);
|
|
2385
2573
|
ctx.container.appendChild(container);
|
|
2386
2574
|
let scale = 1;
|
|
2575
|
+
let rotation = 0;
|
|
2387
2576
|
let currentSheetIndex = 1;
|
|
2388
2577
|
let sheetNames = [];
|
|
2389
2578
|
let wb = null;
|
|
2579
|
+
const applyTransform = () => {
|
|
2580
|
+
contentArea.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2581
|
+
contentArea.style.transformOrigin = "top left";
|
|
2582
|
+
};
|
|
2583
|
+
const calculateFitScale = () => {
|
|
2584
|
+
const table = contentArea.querySelector("table");
|
|
2585
|
+
if (!table) return 1;
|
|
2586
|
+
const availW = Math.max(200, container.clientWidth - 48);
|
|
2587
|
+
const availH = Math.max(200, container.clientHeight - 80);
|
|
2588
|
+
const tW = table.offsetWidth || 800;
|
|
2589
|
+
const tH = table.offsetHeight || 600;
|
|
2590
|
+
return Math.min(1, Math.min(availW / tW, availH / tH));
|
|
2591
|
+
};
|
|
2390
2592
|
try {
|
|
2391
2593
|
wb = XLSX.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
|
|
2392
2594
|
sheetNames = wb.SheetNames || [];
|
|
@@ -2474,17 +2676,30 @@ var ExcelPlugin = class {
|
|
|
2474
2676
|
return {
|
|
2475
2677
|
destroy: cleanup,
|
|
2476
2678
|
zoomIn: () => {
|
|
2477
|
-
scale += 0.
|
|
2478
|
-
|
|
2679
|
+
scale += 0.15;
|
|
2680
|
+
applyTransform();
|
|
2479
2681
|
},
|
|
2480
2682
|
zoomOut: () => {
|
|
2481
|
-
scale = Math.max(0.2, scale - 0.
|
|
2482
|
-
|
|
2683
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
2684
|
+
applyTransform();
|
|
2483
2685
|
},
|
|
2484
2686
|
getZoom: () => scale,
|
|
2485
2687
|
setZoom: (level) => {
|
|
2486
2688
|
scale = level;
|
|
2487
|
-
|
|
2689
|
+
applyTransform();
|
|
2690
|
+
},
|
|
2691
|
+
fitToPage: () => {
|
|
2692
|
+
scale = calculateFitScale();
|
|
2693
|
+
rotation = 0;
|
|
2694
|
+
applyTransform();
|
|
2695
|
+
},
|
|
2696
|
+
rotateCW: () => {
|
|
2697
|
+
rotation = (rotation + 90) % 360;
|
|
2698
|
+
applyTransform();
|
|
2699
|
+
},
|
|
2700
|
+
rotateCCW: () => {
|
|
2701
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
2702
|
+
applyTransform();
|
|
2488
2703
|
},
|
|
2489
2704
|
goToPage: (page) => {
|
|
2490
2705
|
if (page > 0 && page <= sheetNames.length) {
|
|
@@ -2734,6 +2949,26 @@ var CodePlugin = class {
|
|
|
2734
2949
|
instance.zoomIn?.();
|
|
2735
2950
|
}
|
|
2736
2951
|
},
|
|
2952
|
+
{
|
|
2953
|
+
id: "fit-page",
|
|
2954
|
+
icon: "fit-page",
|
|
2955
|
+
label: "Fit to View",
|
|
2956
|
+
type: "button",
|
|
2957
|
+
group: "zoom",
|
|
2958
|
+
execute: () => {
|
|
2959
|
+
instance.fitToPage?.();
|
|
2960
|
+
}
|
|
2961
|
+
},
|
|
2962
|
+
{
|
|
2963
|
+
id: "rotate-cw",
|
|
2964
|
+
icon: "rotate-cw",
|
|
2965
|
+
label: "Rotate",
|
|
2966
|
+
type: "button",
|
|
2967
|
+
group: "view",
|
|
2968
|
+
execute: () => {
|
|
2969
|
+
instance.rotateCW?.();
|
|
2970
|
+
}
|
|
2971
|
+
},
|
|
2737
2972
|
{
|
|
2738
2973
|
id: "copy",
|
|
2739
2974
|
icon: "copy",
|
|
@@ -2770,40 +3005,94 @@ var CodePlugin = class {
|
|
|
2770
3005
|
async render(ctx) {
|
|
2771
3006
|
const decoder = new TextDecoder("utf-8");
|
|
2772
3007
|
const fullText = decoder.decode(ctx.buffer);
|
|
2773
|
-
const
|
|
2774
|
-
const
|
|
3008
|
+
const extRaw = ctx.metadata.extension?.toLowerCase();
|
|
3009
|
+
const mimeRaw = ctx.metadata.mimeType?.toLowerCase();
|
|
3010
|
+
const isTxt = extRaw === ".txt" || mimeRaw === "text/plain" && (!extRaw || !this.extensions.filter((e) => e !== ".txt").includes(extRaw));
|
|
3011
|
+
let rawPages = [];
|
|
3012
|
+
if (isTxt) {
|
|
3013
|
+
const explicitPages = fullText.split(/(?:\f|\x0C)/);
|
|
3014
|
+
for (const ep of explicitPages) {
|
|
3015
|
+
const lines = ep.split(/\r?\n/);
|
|
3016
|
+
let currentChunk = [];
|
|
3017
|
+
for (let i = 0; i < lines.length; i++) {
|
|
3018
|
+
currentChunk.push(lines[i]);
|
|
3019
|
+
if (currentChunk.length >= 46) {
|
|
3020
|
+
rawPages.push(currentChunk.join("\n"));
|
|
3021
|
+
currentChunk = [];
|
|
3022
|
+
}
|
|
3023
|
+
}
|
|
3024
|
+
if (currentChunk.length > 0 || lines.length === 0) {
|
|
3025
|
+
rawPages.push(currentChunk.join("\n"));
|
|
3026
|
+
}
|
|
3027
|
+
}
|
|
3028
|
+
if (rawPages.length === 0) rawPages = [""];
|
|
3029
|
+
} else {
|
|
3030
|
+
const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
|
|
3031
|
+
rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
3032
|
+
}
|
|
2775
3033
|
const totalPages = Math.max(1, rawPages.length);
|
|
2776
3034
|
let currentPage = 1;
|
|
2777
3035
|
const container = document.createElement("div");
|
|
2778
3036
|
container.style.width = "100%";
|
|
2779
3037
|
container.style.height = "100%";
|
|
2780
3038
|
container.style.overflow = "auto";
|
|
2781
|
-
container.style.backgroundColor = "#1e1e1e";
|
|
2782
|
-
container.style.color = "#d4d4d4";
|
|
2783
|
-
container.style.padding = "16px";
|
|
2784
|
-
container.style.boxSizing = "border-box";
|
|
2785
3039
|
let fontSize = 13;
|
|
3040
|
+
let rotation = 0;
|
|
3041
|
+
let zoomLevel = 1;
|
|
2786
3042
|
const pre = document.createElement("pre");
|
|
2787
|
-
pre.style.margin = "0";
|
|
2788
|
-
pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
|
|
2789
|
-
pre.style.fontSize = `${fontSize}px`;
|
|
2790
|
-
pre.style.lineHeight = "1.5";
|
|
2791
|
-
pre.style.whiteSpace = "pre-wrap";
|
|
2792
|
-
pre.style.wordBreak = "break-all";
|
|
2793
3043
|
const code = document.createElement("code");
|
|
3044
|
+
if (isTxt) {
|
|
3045
|
+
container.style.backgroundColor = "#f1f5f9";
|
|
3046
|
+
container.style.padding = "32px";
|
|
3047
|
+
container.style.boxSizing = "border-box";
|
|
3048
|
+
container.style.display = "flex";
|
|
3049
|
+
container.style.flexDirection = "column";
|
|
3050
|
+
container.style.alignItems = "center";
|
|
3051
|
+
pre.style.margin = "0";
|
|
3052
|
+
pre.style.fontFamily = "Consolas, 'Courier New', monospace";
|
|
3053
|
+
pre.style.fontSize = "13px";
|
|
3054
|
+
pre.style.color = "#1e293b";
|
|
3055
|
+
pre.style.lineHeight = "1.5";
|
|
3056
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3057
|
+
pre.style.wordBreak = "break-word";
|
|
3058
|
+
pre.style.backgroundColor = "#ffffff";
|
|
3059
|
+
pre.style.width = "816px";
|
|
3060
|
+
pre.style.minHeight = "1056px";
|
|
3061
|
+
pre.style.padding = "72px 56px";
|
|
3062
|
+
pre.style.boxSizing = "border-box";
|
|
3063
|
+
pre.style.boxShadow = "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)";
|
|
3064
|
+
pre.style.borderRadius = "4px";
|
|
3065
|
+
pre.style.transformOrigin = "top center";
|
|
3066
|
+
} else {
|
|
3067
|
+
container.style.backgroundColor = "#1e1e1e";
|
|
3068
|
+
container.style.color = "#d4d4d4";
|
|
3069
|
+
container.style.padding = "16px";
|
|
3070
|
+
container.style.boxSizing = "border-box";
|
|
3071
|
+
pre.style.margin = "0";
|
|
3072
|
+
pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
|
|
3073
|
+
pre.style.fontSize = `${fontSize}px`;
|
|
3074
|
+
pre.style.lineHeight = "1.5";
|
|
3075
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3076
|
+
pre.style.wordBreak = "break-all";
|
|
3077
|
+
pre.style.transformOrigin = "top left";
|
|
3078
|
+
}
|
|
2794
3079
|
const ext = (ctx.metadata.extension || "").replace(".", "");
|
|
2795
3080
|
const renderCodePage = (text) => {
|
|
2796
|
-
|
|
2797
|
-
if (ext && hljs.getLanguage(ext)) {
|
|
2798
|
-
code.innerHTML = hljs.highlight(text, { language: ext }).value;
|
|
2799
|
-
} else {
|
|
2800
|
-
code.innerHTML = hljs.highlightAuto(text).value;
|
|
2801
|
-
}
|
|
2802
|
-
} catch {
|
|
3081
|
+
if (isTxt) {
|
|
2803
3082
|
code.textContent = text;
|
|
3083
|
+
} else {
|
|
3084
|
+
try {
|
|
3085
|
+
if (ext && hljs.getLanguage(ext)) {
|
|
3086
|
+
code.innerHTML = hljs.highlight(text, { language: ext }).value;
|
|
3087
|
+
} else {
|
|
3088
|
+
code.innerHTML = hljs.highlightAuto(text).value;
|
|
3089
|
+
}
|
|
3090
|
+
} catch {
|
|
3091
|
+
code.textContent = text;
|
|
3092
|
+
}
|
|
2804
3093
|
}
|
|
2805
3094
|
};
|
|
2806
|
-
renderCodePage(rawPages[0] || fullText);
|
|
3095
|
+
renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
|
|
2807
3096
|
pre.appendChild(code);
|
|
2808
3097
|
container.appendChild(pre);
|
|
2809
3098
|
let indicator = null;
|
|
@@ -2812,15 +3101,22 @@ var CodePlugin = class {
|
|
|
2812
3101
|
indicator.className = "fp-code-page-indicator";
|
|
2813
3102
|
indicator.style.position = "sticky";
|
|
2814
3103
|
indicator.style.bottom = "16px";
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
3104
|
+
if (isTxt) {
|
|
3105
|
+
indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
|
|
3106
|
+
indicator.style.color = "#334155";
|
|
3107
|
+
indicator.style.border = "1px solid #e2e8f0";
|
|
3108
|
+
indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
|
|
3109
|
+
} else {
|
|
3110
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3111
|
+
indicator.style.color = "#f8fafc";
|
|
3112
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3113
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3114
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
3115
|
+
}
|
|
2818
3116
|
indicator.style.fontSize = "12px";
|
|
2819
3117
|
indicator.style.fontWeight = "600";
|
|
2820
3118
|
indicator.style.padding = "5px 14px";
|
|
2821
3119
|
indicator.style.borderRadius = "20px";
|
|
2822
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2823
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2824
3120
|
indicator.style.zIndex = "10";
|
|
2825
3121
|
indicator.style.userSelect = "none";
|
|
2826
3122
|
indicator.style.pointerEvents = "none";
|
|
@@ -2831,7 +3127,7 @@ var CodePlugin = class {
|
|
|
2831
3127
|
}
|
|
2832
3128
|
const showPage = (pageNum) => {
|
|
2833
3129
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2834
|
-
renderCodePage(rawPages[currentPage - 1] || fullText);
|
|
3130
|
+
renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
|
|
2835
3131
|
if (indicator) {
|
|
2836
3132
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2837
3133
|
}
|
|
@@ -2847,23 +3143,57 @@ var CodePlugin = class {
|
|
|
2847
3143
|
ctx.container.innerHTML = "";
|
|
2848
3144
|
};
|
|
2849
3145
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3146
|
+
const updateTransform = () => {
|
|
3147
|
+
if (isTxt) {
|
|
3148
|
+
pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
|
|
3149
|
+
} else {
|
|
3150
|
+
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3151
|
+
pre.style.fontSize = `${fontSize}px`;
|
|
3152
|
+
}
|
|
3153
|
+
};
|
|
2850
3154
|
return {
|
|
2851
3155
|
destroy: cleanup,
|
|
2852
3156
|
getPageCount: () => totalPages,
|
|
2853
3157
|
getCurrentPage: () => currentPage,
|
|
2854
3158
|
goToPage: (page) => showPage(page),
|
|
2855
3159
|
zoomIn: () => {
|
|
2856
|
-
|
|
2857
|
-
|
|
3160
|
+
if (isTxt) {
|
|
3161
|
+
zoomLevel = Math.min(3, zoomLevel + 0.1);
|
|
3162
|
+
} else {
|
|
3163
|
+
fontSize = Math.min(32, fontSize + 2);
|
|
3164
|
+
}
|
|
3165
|
+
updateTransform();
|
|
2858
3166
|
},
|
|
2859
3167
|
zoomOut: () => {
|
|
2860
|
-
|
|
2861
|
-
|
|
3168
|
+
if (isTxt) {
|
|
3169
|
+
zoomLevel = Math.max(0.1, zoomLevel - 0.1);
|
|
3170
|
+
} else {
|
|
3171
|
+
fontSize = Math.max(8, fontSize - 2);
|
|
3172
|
+
}
|
|
3173
|
+
updateTransform();
|
|
2862
3174
|
},
|
|
2863
|
-
getZoom: () => fontSize / 13,
|
|
3175
|
+
getZoom: () => isTxt ? zoomLevel : fontSize / 13,
|
|
2864
3176
|
setZoom: (level) => {
|
|
2865
|
-
|
|
2866
|
-
|
|
3177
|
+
if (isTxt) {
|
|
3178
|
+
zoomLevel = level;
|
|
3179
|
+
} else {
|
|
3180
|
+
fontSize = Math.round(13 * level);
|
|
3181
|
+
}
|
|
3182
|
+
updateTransform();
|
|
3183
|
+
},
|
|
3184
|
+
fitToPage: () => {
|
|
3185
|
+
fontSize = 13;
|
|
3186
|
+
rotation = 0;
|
|
3187
|
+
zoomLevel = 1;
|
|
3188
|
+
updateTransform();
|
|
3189
|
+
},
|
|
3190
|
+
rotateCW: () => {
|
|
3191
|
+
rotation = (rotation + 90) % 360;
|
|
3192
|
+
updateTransform();
|
|
3193
|
+
},
|
|
3194
|
+
rotateCCW: () => {
|
|
3195
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
3196
|
+
updateTransform();
|
|
2867
3197
|
},
|
|
2868
3198
|
download: () => {
|
|
2869
3199
|
const mimeType = ctx.metadata.mimeType || "text/plain";
|
|
@@ -3162,7 +3492,7 @@ var MarkdownPlugin = class {
|
|
|
3162
3492
|
gfm: true,
|
|
3163
3493
|
breaks: true
|
|
3164
3494
|
});
|
|
3165
|
-
const cleanHtml =
|
|
3495
|
+
const cleanHtml = DOMPurify6.sanitize(rawHtml, {
|
|
3166
3496
|
USE_PROFILES: { html: true }
|
|
3167
3497
|
});
|
|
3168
3498
|
const wrapper = document.createElement("div");
|
|
@@ -3376,6 +3706,14 @@ var PptxPlugin = class {
|
|
|
3376
3706
|
group: "zoom",
|
|
3377
3707
|
execute: () => instance.fitToPage?.()
|
|
3378
3708
|
},
|
|
3709
|
+
{
|
|
3710
|
+
id: "rotate-cw",
|
|
3711
|
+
icon: "rotate-cw",
|
|
3712
|
+
label: "Rotate",
|
|
3713
|
+
type: "button",
|
|
3714
|
+
group: "view",
|
|
3715
|
+
execute: () => instance.rotateCW?.()
|
|
3716
|
+
},
|
|
3379
3717
|
{
|
|
3380
3718
|
id: "download",
|
|
3381
3719
|
icon: "download",
|
|
@@ -3400,6 +3738,7 @@ var PptxPlugin = class {
|
|
|
3400
3738
|
const slideCount = renderer.slidePaths?.length || 1;
|
|
3401
3739
|
let currentSlide = 1;
|
|
3402
3740
|
let scale = 1;
|
|
3741
|
+
let rotation = 0;
|
|
3403
3742
|
const wrapper = document.createElement("div");
|
|
3404
3743
|
wrapper.className = "fp-pptx-wrapper";
|
|
3405
3744
|
wrapper.style.cssText = `
|
|
@@ -3422,6 +3761,8 @@ var PptxPlugin = class {
|
|
|
3422
3761
|
background: #ffffff;
|
|
3423
3762
|
transform-origin: top center;
|
|
3424
3763
|
transition: transform 0.2s ease;
|
|
3764
|
+
max-width: calc(100% - 32px);
|
|
3765
|
+
max-height: calc(100% - 48px);
|
|
3425
3766
|
`;
|
|
3426
3767
|
const canvas = document.createElement("canvas");
|
|
3427
3768
|
slideContainer.appendChild(canvas);
|
|
@@ -3429,10 +3770,22 @@ var PptxPlugin = class {
|
|
|
3429
3770
|
ctx.container.innerHTML = "";
|
|
3430
3771
|
ctx.container.style.overflow = "auto";
|
|
3431
3772
|
ctx.container.appendChild(wrapper);
|
|
3773
|
+
const calculateFitScale = () => {
|
|
3774
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
3775
|
+
const availH = Math.max(200, ctx.container.clientHeight - 72);
|
|
3776
|
+
const cW = canvas.offsetWidth || 1280;
|
|
3777
|
+
const cH = canvas.offsetHeight || 720;
|
|
3778
|
+
return Math.min(1, Math.min(availW / cW, availH / cH));
|
|
3779
|
+
};
|
|
3780
|
+
const applyTransform = () => {
|
|
3781
|
+
slideContainer.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
3782
|
+
};
|
|
3432
3783
|
const renderCurrentSlide = async () => {
|
|
3433
3784
|
try {
|
|
3434
3785
|
await renderer.renderSlide(currentSlide - 1, canvas, 1280);
|
|
3435
3786
|
ctx.emit("page-change", { page: currentSlide, totalPages: slideCount });
|
|
3787
|
+
scale = calculateFitScale();
|
|
3788
|
+
applyTransform();
|
|
3436
3789
|
} catch (err) {
|
|
3437
3790
|
console.error("[PptxPlugin] Failed to render slide:", err);
|
|
3438
3791
|
}
|
|
@@ -3455,21 +3808,30 @@ var PptxPlugin = class {
|
|
|
3455
3808
|
getPageCount: () => slideCount,
|
|
3456
3809
|
getCurrentPage: () => currentSlide,
|
|
3457
3810
|
zoomIn: () => {
|
|
3458
|
-
scale += 0.
|
|
3459
|
-
|
|
3811
|
+
scale += 0.15;
|
|
3812
|
+
applyTransform();
|
|
3460
3813
|
},
|
|
3461
3814
|
zoomOut: () => {
|
|
3462
|
-
scale = Math.max(0.2, scale - 0.
|
|
3463
|
-
|
|
3815
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
3816
|
+
applyTransform();
|
|
3464
3817
|
},
|
|
3465
3818
|
getZoom: () => scale,
|
|
3466
3819
|
setZoom: (level) => {
|
|
3467
3820
|
scale = level;
|
|
3468
|
-
|
|
3821
|
+
applyTransform();
|
|
3469
3822
|
},
|
|
3470
3823
|
fitToPage: () => {
|
|
3471
|
-
scale =
|
|
3472
|
-
|
|
3824
|
+
scale = calculateFitScale();
|
|
3825
|
+
rotation = 0;
|
|
3826
|
+
applyTransform();
|
|
3827
|
+
},
|
|
3828
|
+
rotateCW: () => {
|
|
3829
|
+
rotation = (rotation + 90) % 360;
|
|
3830
|
+
applyTransform();
|
|
3831
|
+
},
|
|
3832
|
+
rotateCCW: () => {
|
|
3833
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
3834
|
+
applyTransform();
|
|
3473
3835
|
},
|
|
3474
3836
|
getThumbnails: () => {
|
|
3475
3837
|
const list = [];
|
|
@@ -3750,6 +4112,14 @@ var RtfPlugin = class {
|
|
|
3750
4112
|
group: "zoom",
|
|
3751
4113
|
execute: () => instance.fitToPage?.()
|
|
3752
4114
|
},
|
|
4115
|
+
{
|
|
4116
|
+
id: "rotate-cw",
|
|
4117
|
+
icon: "rotate-cw",
|
|
4118
|
+
label: "Rotate",
|
|
4119
|
+
type: "button",
|
|
4120
|
+
group: "view",
|
|
4121
|
+
execute: () => instance.rotateCW?.()
|
|
4122
|
+
},
|
|
3753
4123
|
{
|
|
3754
4124
|
id: "download",
|
|
3755
4125
|
icon: "download",
|
|
@@ -3758,6 +4128,14 @@ var RtfPlugin = class {
|
|
|
3758
4128
|
group: "actions",
|
|
3759
4129
|
execute: () => instance.download?.()
|
|
3760
4130
|
},
|
|
4131
|
+
{
|
|
4132
|
+
id: "copy",
|
|
4133
|
+
icon: "copy",
|
|
4134
|
+
label: "Copy Text",
|
|
4135
|
+
type: "button",
|
|
4136
|
+
group: "actions",
|
|
4137
|
+
execute: () => instance.copy?.()
|
|
4138
|
+
},
|
|
3761
4139
|
{
|
|
3762
4140
|
id: "print",
|
|
3763
4141
|
icon: "print",
|
|
@@ -3786,7 +4164,24 @@ var RtfPlugin = class {
|
|
|
3786
4164
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
3787
4165
|
ctx.container.appendChild(wrapper);
|
|
3788
4166
|
let scale = 1;
|
|
4167
|
+
let rotation = 0;
|
|
3789
4168
|
let pageElements = [];
|
|
4169
|
+
const calculateFitScale = () => {
|
|
4170
|
+
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4171
|
+
const elW = activeEl.offsetWidth || 850;
|
|
4172
|
+
const elH = activeEl.offsetHeight || 1e3;
|
|
4173
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
4174
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
4175
|
+
return Math.min(1.1, Math.min(availW / elW, availH / elH));
|
|
4176
|
+
};
|
|
4177
|
+
const applyTransform = () => {
|
|
4178
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4179
|
+
wrapper.style.transformOrigin = "top center";
|
|
4180
|
+
};
|
|
4181
|
+
setTimeout(() => {
|
|
4182
|
+
scale = calculateFitScale();
|
|
4183
|
+
applyTransform();
|
|
4184
|
+
}, 60);
|
|
3790
4185
|
try {
|
|
3791
4186
|
if (typeof RTFJS.loggingEnabled === "function") {
|
|
3792
4187
|
RTFJS.loggingEnabled(false);
|
|
@@ -3802,14 +4197,31 @@ var RtfPlugin = class {
|
|
|
3802
4197
|
} catch (err) {
|
|
3803
4198
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
3804
4199
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
3805
|
-
const
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
4200
|
+
const rawPages = text.split(/\\page\b/).map((segment) => {
|
|
4201
|
+
return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
|
|
4202
|
+
}).filter((p) => p.length > 0);
|
|
4203
|
+
const pages = rawPages.length > 0 ? rawPages : [text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim()];
|
|
4204
|
+
for (let i = 0; i < pages.length; i++) {
|
|
4205
|
+
const pageCard = document.createElement("div");
|
|
4206
|
+
pageCard.className = "fp-rtf-page-card";
|
|
4207
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
4208
|
+
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4209
|
+
pageCard.style.borderRadius = "4px";
|
|
4210
|
+
pageCard.style.padding = "72px 56px";
|
|
4211
|
+
pageCard.style.width = "816px";
|
|
4212
|
+
pageCard.style.minHeight = "1056px";
|
|
4213
|
+
pageCard.style.maxWidth = "100%";
|
|
4214
|
+
pageCard.style.boxSizing = "border-box";
|
|
4215
|
+
pageCard.style.fontFamily = "serif";
|
|
4216
|
+
pageCard.style.fontSize = "12pt";
|
|
4217
|
+
pageCard.style.lineHeight = "1.6";
|
|
4218
|
+
pageCard.style.color = "#1e293b";
|
|
4219
|
+
pageCard.style.whiteSpace = "pre-wrap";
|
|
4220
|
+
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4221
|
+
pageCard.textContent = pages[i];
|
|
4222
|
+
wrapper.appendChild(pageCard);
|
|
4223
|
+
pageElements.push(pageCard);
|
|
4224
|
+
}
|
|
3813
4225
|
}
|
|
3814
4226
|
const totalPages = Math.max(1, pageElements.length);
|
|
3815
4227
|
let currentPage = 1;
|
|
@@ -3863,21 +4275,30 @@ var RtfPlugin = class {
|
|
|
3863
4275
|
getCurrentPage: () => currentPage,
|
|
3864
4276
|
goToPage: (page) => showPage(page),
|
|
3865
4277
|
zoomIn: () => {
|
|
3866
|
-
scale += 0.
|
|
3867
|
-
|
|
4278
|
+
scale += 0.15;
|
|
4279
|
+
applyTransform();
|
|
3868
4280
|
},
|
|
3869
4281
|
zoomOut: () => {
|
|
3870
|
-
scale = Math.max(0.2, scale - 0.
|
|
3871
|
-
|
|
4282
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
4283
|
+
applyTransform();
|
|
3872
4284
|
},
|
|
3873
4285
|
getZoom: () => scale,
|
|
3874
4286
|
setZoom: (level) => {
|
|
3875
4287
|
scale = level;
|
|
3876
|
-
|
|
4288
|
+
applyTransform();
|
|
3877
4289
|
},
|
|
3878
4290
|
fitToPage: () => {
|
|
3879
|
-
scale =
|
|
3880
|
-
|
|
4291
|
+
scale = calculateFitScale();
|
|
4292
|
+
rotation = 0;
|
|
4293
|
+
applyTransform();
|
|
4294
|
+
},
|
|
4295
|
+
rotateCW: () => {
|
|
4296
|
+
rotation = (rotation + 90) % 360;
|
|
4297
|
+
applyTransform();
|
|
4298
|
+
},
|
|
4299
|
+
rotateCCW: () => {
|
|
4300
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
4301
|
+
applyTransform();
|
|
3881
4302
|
},
|
|
3882
4303
|
download: () => {
|
|
3883
4304
|
const blob = new Blob([ctx.buffer], { type: "application/rtf" });
|
|
@@ -3888,6 +4309,10 @@ var RtfPlugin = class {
|
|
|
3888
4309
|
a.click();
|
|
3889
4310
|
URL.revokeObjectURL(url);
|
|
3890
4311
|
},
|
|
4312
|
+
copy: () => {
|
|
4313
|
+
const text = wrapper.textContent || "";
|
|
4314
|
+
navigator.clipboard?.writeText(text);
|
|
4315
|
+
},
|
|
3891
4316
|
print: () => {
|
|
3892
4317
|
window.print();
|
|
3893
4318
|
}
|
|
@@ -3962,7 +4387,7 @@ var HtmlPreviewPlugin = class {
|
|
|
3962
4387
|
}
|
|
3963
4388
|
async render(ctx) {
|
|
3964
4389
|
const rawHtml = new TextDecoder("utf-8").decode(ctx.buffer);
|
|
3965
|
-
const sanitized =
|
|
4390
|
+
const sanitized = DOMPurify6.sanitize(rawHtml, {
|
|
3966
4391
|
WHOLE_DOCUMENT: true,
|
|
3967
4392
|
ADD_TAGS: ["style", "link"],
|
|
3968
4393
|
ADD_ATTR: ["target", "rel"]
|
|
@@ -4105,11 +4530,19 @@ var OpenDocumentPlugin = class {
|
|
|
4105
4530
|
{
|
|
4106
4531
|
id: "fit-page",
|
|
4107
4532
|
icon: "fit-page",
|
|
4108
|
-
label: "Fit to Page",
|
|
4533
|
+
label: isPresentation ? "Fit to Slide" : "Fit to Page",
|
|
4109
4534
|
type: "button",
|
|
4110
4535
|
group: "zoom",
|
|
4111
4536
|
execute: () => instance.fitToPage?.()
|
|
4112
4537
|
},
|
|
4538
|
+
{
|
|
4539
|
+
id: "rotate-cw",
|
|
4540
|
+
icon: "rotate-cw",
|
|
4541
|
+
label: "Rotate",
|
|
4542
|
+
type: "button",
|
|
4543
|
+
group: "view",
|
|
4544
|
+
execute: () => instance.rotateCW?.()
|
|
4545
|
+
},
|
|
4113
4546
|
{
|
|
4114
4547
|
id: "download",
|
|
4115
4548
|
icon: "download",
|
|
@@ -4173,6 +4606,22 @@ var OpenDocumentPlugin = class {
|
|
|
4173
4606
|
container.appendChild(wrapper);
|
|
4174
4607
|
ctx.container.appendChild(container);
|
|
4175
4608
|
let scale = 1;
|
|
4609
|
+
let rotation = 0;
|
|
4610
|
+
const calculateFitScale = () => {
|
|
4611
|
+
const elW = wrapper.offsetWidth || 850;
|
|
4612
|
+
const elH = wrapper.offsetHeight || (isPresentation ? 540 : 1e3);
|
|
4613
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
4614
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
4615
|
+
return Math.min(1, Math.min(availW / elW, availH / elH));
|
|
4616
|
+
};
|
|
4617
|
+
const applyTransform = () => {
|
|
4618
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4619
|
+
wrapper.style.transformOrigin = "top center";
|
|
4620
|
+
};
|
|
4621
|
+
setTimeout(() => {
|
|
4622
|
+
scale = calculateFitScale();
|
|
4623
|
+
applyTransform();
|
|
4624
|
+
}, 60);
|
|
4176
4625
|
let currentPage = 1;
|
|
4177
4626
|
let totalPages = 1;
|
|
4178
4627
|
let slides = [];
|
|
@@ -4204,14 +4653,97 @@ var OpenDocumentPlugin = class {
|
|
|
4204
4653
|
wrapper.textContent = contentDoc.documentElement.textContent || "Formula content";
|
|
4205
4654
|
}
|
|
4206
4655
|
} else {
|
|
4207
|
-
wrapper.style.maxWidth = "
|
|
4208
|
-
wrapper.style.padding = "
|
|
4656
|
+
wrapper.style.maxWidth = "none";
|
|
4657
|
+
wrapper.style.padding = "0";
|
|
4209
4658
|
wrapper.style.minHeight = "100%";
|
|
4659
|
+
wrapper.style.backgroundColor = "transparent";
|
|
4660
|
+
wrapper.style.boxShadow = "none";
|
|
4661
|
+
wrapper.style.position = "relative";
|
|
4662
|
+
const dims = this.getPageDimensions(stylesDoc, contentDoc);
|
|
4210
4663
|
const bodyHtml = this.renderOdfBody(contentDoc, styleMap, imageUrls);
|
|
4211
|
-
|
|
4212
|
-
|
|
4664
|
+
const tempDiv = document.createElement("div");
|
|
4665
|
+
tempDiv.style.width = `${dims.width - dims.marginLeft - dims.marginRight}px`;
|
|
4666
|
+
tempDiv.style.position = "absolute";
|
|
4667
|
+
tempDiv.style.visibility = "hidden";
|
|
4668
|
+
tempDiv.innerHTML = DOMPurify6.sanitize(bodyHtml, {
|
|
4669
|
+
ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub", "hr"],
|
|
4213
4670
|
ADD_ATTR: ["style", "colspan", "rowspan"]
|
|
4214
4671
|
});
|
|
4672
|
+
document.body.appendChild(tempDiv);
|
|
4673
|
+
const contentHeight = dims.height - dims.marginTop - dims.marginBottom;
|
|
4674
|
+
const pageElements = [[]];
|
|
4675
|
+
let currentHeight = 0;
|
|
4676
|
+
let currentPageIdx = 0;
|
|
4677
|
+
Array.from(tempDiv.children).forEach((child) => {
|
|
4678
|
+
const el = child;
|
|
4679
|
+
const style = el.getAttribute("style") || "";
|
|
4680
|
+
const isBreakBefore = style.includes("page-break-before: always");
|
|
4681
|
+
const isBreakAfter = style.includes("page-break-after: always");
|
|
4682
|
+
const isSoftBreak = el.classList.contains("odf-page-break");
|
|
4683
|
+
if (isBreakBefore) {
|
|
4684
|
+
if (pageElements[currentPageIdx].length > 0) {
|
|
4685
|
+
currentPageIdx++;
|
|
4686
|
+
pageElements.push([]);
|
|
4687
|
+
currentHeight = 0;
|
|
4688
|
+
}
|
|
4689
|
+
}
|
|
4690
|
+
const h = el.offsetHeight || 0;
|
|
4691
|
+
if (currentHeight + h > contentHeight && pageElements[currentPageIdx].length > 0 && !isSoftBreak) {
|
|
4692
|
+
currentPageIdx++;
|
|
4693
|
+
pageElements.push([]);
|
|
4694
|
+
currentHeight = 0;
|
|
4695
|
+
}
|
|
4696
|
+
if (!isSoftBreak) {
|
|
4697
|
+
pageElements[currentPageIdx].push(el.cloneNode(true));
|
|
4698
|
+
currentHeight += h;
|
|
4699
|
+
}
|
|
4700
|
+
if (isBreakAfter || isSoftBreak) {
|
|
4701
|
+
currentPageIdx++;
|
|
4702
|
+
pageElements.push([]);
|
|
4703
|
+
currentHeight = 0;
|
|
4704
|
+
}
|
|
4705
|
+
});
|
|
4706
|
+
document.body.removeChild(tempDiv);
|
|
4707
|
+
if (pageElements.length > 1 && pageElements[pageElements.length - 1].length === 0) {
|
|
4708
|
+
pageElements.pop();
|
|
4709
|
+
}
|
|
4710
|
+
totalPages = Math.max(1, pageElements.length);
|
|
4711
|
+
pageElements.forEach((elements, idx) => {
|
|
4712
|
+
const page = document.createElement("div");
|
|
4713
|
+
page.className = `fp-odt-page fp-odt-page-${idx + 1}`;
|
|
4714
|
+
page.style.width = `${dims.width}px`;
|
|
4715
|
+
page.style.minHeight = `${dims.height}px`;
|
|
4716
|
+
page.style.padding = `${dims.marginTop}px ${dims.marginRight}px ${dims.marginBottom}px ${dims.marginLeft}px`;
|
|
4717
|
+
page.style.margin = "0 auto";
|
|
4718
|
+
page.style.backgroundColor = "#ffffff";
|
|
4719
|
+
page.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
|
|
4720
|
+
page.style.borderRadius = "4px";
|
|
4721
|
+
page.style.boxSizing = "border-box";
|
|
4722
|
+
page.style.display = idx === 0 ? "block" : "none";
|
|
4723
|
+
page.style.position = "absolute";
|
|
4724
|
+
page.style.top = "0";
|
|
4725
|
+
page.style.left = "50%";
|
|
4726
|
+
page.style.transform = "translateX(-50%)";
|
|
4727
|
+
elements.forEach((el) => page.appendChild(el));
|
|
4728
|
+
wrapper.appendChild(page);
|
|
4729
|
+
slides.push(page);
|
|
4730
|
+
});
|
|
4731
|
+
const pageIndicator = document.createElement("div");
|
|
4732
|
+
pageIndicator.className = "fp-odt-page-indicator";
|
|
4733
|
+
pageIndicator.style.position = "sticky";
|
|
4734
|
+
pageIndicator.style.bottom = "16px";
|
|
4735
|
+
pageIndicator.style.left = "50%";
|
|
4736
|
+
pageIndicator.style.transform = "translateX(-50%)";
|
|
4737
|
+
pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
|
4738
|
+
pageIndicator.style.color = "#fff";
|
|
4739
|
+
pageIndicator.style.padding = "6px 12px";
|
|
4740
|
+
pageIndicator.style.borderRadius = "16px";
|
|
4741
|
+
pageIndicator.style.fontSize = "12px";
|
|
4742
|
+
pageIndicator.style.zIndex = "100";
|
|
4743
|
+
pageIndicator.style.display = "inline-block";
|
|
4744
|
+
pageIndicator.style.width = "fit-content";
|
|
4745
|
+
pageIndicator.textContent = `Page 1 of ${totalPages}`;
|
|
4746
|
+
container.appendChild(pageIndicator);
|
|
4215
4747
|
}
|
|
4216
4748
|
const cleanup = () => {
|
|
4217
4749
|
imageUrls.forEach((url) => URL.revokeObjectURL(url));
|
|
@@ -4220,32 +4752,45 @@ var OpenDocumentPlugin = class {
|
|
|
4220
4752
|
};
|
|
4221
4753
|
ctx.signal.addEventListener("abort", cleanup);
|
|
4222
4754
|
const goToPage = (page) => {
|
|
4223
|
-
if (
|
|
4755
|
+
if (page < 1 || page > totalPages) return;
|
|
4224
4756
|
currentPage = page;
|
|
4225
4757
|
slides.forEach((s, idx) => {
|
|
4226
4758
|
s.style.display = idx === page - 1 ? "block" : "none";
|
|
4227
4759
|
});
|
|
4760
|
+
const indicator = container.querySelector(".fp-odt-page-indicator");
|
|
4761
|
+
if (indicator) {
|
|
4762
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4763
|
+
}
|
|
4228
4764
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4229
4765
|
};
|
|
4230
4766
|
return {
|
|
4231
4767
|
destroy: cleanup,
|
|
4232
4768
|
isPresentation,
|
|
4233
4769
|
zoomIn: () => {
|
|
4234
|
-
scale += 0.
|
|
4235
|
-
|
|
4770
|
+
scale += 0.15;
|
|
4771
|
+
applyTransform();
|
|
4236
4772
|
},
|
|
4237
4773
|
zoomOut: () => {
|
|
4238
|
-
scale = Math.max(0.2, scale - 0.
|
|
4239
|
-
|
|
4774
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
4775
|
+
applyTransform();
|
|
4240
4776
|
},
|
|
4241
4777
|
getZoom: () => scale,
|
|
4242
4778
|
setZoom: (level) => {
|
|
4243
4779
|
scale = level;
|
|
4244
|
-
|
|
4780
|
+
applyTransform();
|
|
4245
4781
|
},
|
|
4246
4782
|
fitToPage: () => {
|
|
4247
|
-
scale =
|
|
4248
|
-
|
|
4783
|
+
scale = calculateFitScale();
|
|
4784
|
+
rotation = 0;
|
|
4785
|
+
applyTransform();
|
|
4786
|
+
},
|
|
4787
|
+
rotateCW: () => {
|
|
4788
|
+
rotation = (rotation + 90) % 360;
|
|
4789
|
+
applyTransform();
|
|
4790
|
+
},
|
|
4791
|
+
rotateCCW: () => {
|
|
4792
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
4793
|
+
applyTransform();
|
|
4249
4794
|
},
|
|
4250
4795
|
goToPage,
|
|
4251
4796
|
getPageCount: () => totalPages,
|
|
@@ -4284,6 +4829,43 @@ var OpenDocumentPlugin = class {
|
|
|
4284
4829
|
}
|
|
4285
4830
|
};
|
|
4286
4831
|
}
|
|
4832
|
+
getPageDimensions(stylesDoc, contentDoc) {
|
|
4833
|
+
let width = 850;
|
|
4834
|
+
let height = 1123;
|
|
4835
|
+
let marginTop = 48;
|
|
4836
|
+
let marginBottom = 48;
|
|
4837
|
+
let marginLeft = 48;
|
|
4838
|
+
let marginRight = 48;
|
|
4839
|
+
const parseUnit = (val) => {
|
|
4840
|
+
if (!val) return null;
|
|
4841
|
+
if (val.endsWith("cm")) return parseFloat(val) * 37.8;
|
|
4842
|
+
if (val.endsWith("mm")) return parseFloat(val) * 3.78;
|
|
4843
|
+
if (val.endsWith("in")) return parseFloat(val) * 96;
|
|
4844
|
+
if (val.endsWith("pt")) return parseFloat(val) * 1.33;
|
|
4845
|
+
if (val.endsWith("px")) return parseFloat(val);
|
|
4846
|
+
return parseFloat(val);
|
|
4847
|
+
};
|
|
4848
|
+
const docs = [stylesDoc, contentDoc].filter(Boolean);
|
|
4849
|
+
for (const doc of docs) {
|
|
4850
|
+
const pageLayout = doc.querySelector("page-layout-properties, [page-width]");
|
|
4851
|
+
if (pageLayout) {
|
|
4852
|
+
const w = parseUnit(pageLayout.getAttribute("fo:page-width") || pageLayout.getAttribute("page-width"));
|
|
4853
|
+
const h = parseUnit(pageLayout.getAttribute("fo:page-height") || pageLayout.getAttribute("page-height"));
|
|
4854
|
+
const mt = parseUnit(pageLayout.getAttribute("fo:margin-top") || pageLayout.getAttribute("margin-top"));
|
|
4855
|
+
const mb = parseUnit(pageLayout.getAttribute("fo:margin-bottom") || pageLayout.getAttribute("margin-bottom"));
|
|
4856
|
+
const ml = parseUnit(pageLayout.getAttribute("fo:margin-left") || pageLayout.getAttribute("margin-left"));
|
|
4857
|
+
const mr = parseUnit(pageLayout.getAttribute("fo:margin-right") || pageLayout.getAttribute("margin-right"));
|
|
4858
|
+
if (w !== null) width = w;
|
|
4859
|
+
if (h !== null) height = h;
|
|
4860
|
+
if (mt !== null) marginTop = mt;
|
|
4861
|
+
if (mb !== null) marginBottom = mb;
|
|
4862
|
+
if (ml !== null) marginLeft = ml;
|
|
4863
|
+
if (mr !== null) marginRight = mr;
|
|
4864
|
+
break;
|
|
4865
|
+
}
|
|
4866
|
+
}
|
|
4867
|
+
return { width, height, marginTop, marginBottom, marginLeft, marginRight };
|
|
4868
|
+
}
|
|
4287
4869
|
extractStyles(stylesDoc, contentDoc) {
|
|
4288
4870
|
const map = /* @__PURE__ */ new Map();
|
|
4289
4871
|
const styleNodes = [];
|
|
@@ -4306,14 +4888,21 @@ var OpenDocumentPlugin = class {
|
|
|
4306
4888
|
if (color) css += `color: ${color}; `;
|
|
4307
4889
|
if (size) css += `font-size: ${size}; `;
|
|
4308
4890
|
}
|
|
4309
|
-
|
|
4891
|
+
let paraProp = node.querySelector("paragraph-properties, [text-align]");
|
|
4892
|
+
if (!paraProp) {
|
|
4893
|
+
paraProp = Array.from(node.children).find((c) => c.tagName.includes("paragraph-properties")) || null;
|
|
4894
|
+
}
|
|
4310
4895
|
if (paraProp) {
|
|
4311
4896
|
const align = paraProp.getAttribute("fo:text-align") || paraProp.getAttribute("text-align");
|
|
4312
4897
|
const mt = paraProp.getAttribute("fo:margin-top") || paraProp.getAttribute("margin-top");
|
|
4313
4898
|
const mb = paraProp.getAttribute("fo:margin-bottom") || paraProp.getAttribute("margin-bottom");
|
|
4899
|
+
const breakBefore = paraProp.getAttribute("fo:break-before") || paraProp.getAttribute("break-before");
|
|
4900
|
+
const breakAfter = paraProp.getAttribute("fo:break-after") || paraProp.getAttribute("break-after");
|
|
4314
4901
|
if (align) css += `text-align: ${align}; `;
|
|
4315
4902
|
if (mt) css += `margin-top: ${mt}; `;
|
|
4316
4903
|
if (mb) css += `margin-bottom: ${mb}; `;
|
|
4904
|
+
if (breakBefore === "page") css += "page-break-before: always; ";
|
|
4905
|
+
if (breakAfter === "page") css += "page-break-after: always; ";
|
|
4317
4906
|
}
|
|
4318
4907
|
if (css) map.set(name, css);
|
|
4319
4908
|
}
|
|
@@ -4398,6 +4987,8 @@ var OpenDocumentPlugin = class {
|
|
|
4398
4987
|
result += " ";
|
|
4399
4988
|
} else if (tag === "line-break") {
|
|
4400
4989
|
result += "<br/>";
|
|
4990
|
+
} else if (tag === "soft-page-break") {
|
|
4991
|
+
result += '<hr class="odf-page-break" style="page-break-after: always; border: none; margin: 0; padding: 0; height: 0;" />';
|
|
4401
4992
|
} else {
|
|
4402
4993
|
result += el.textContent || "";
|
|
4403
4994
|
}
|
|
@@ -4515,6 +5106,14 @@ var DocPlugin = class {
|
|
|
4515
5106
|
group: "zoom",
|
|
4516
5107
|
execute: () => instance.fitToPage?.()
|
|
4517
5108
|
},
|
|
5109
|
+
{
|
|
5110
|
+
id: "rotate-cw",
|
|
5111
|
+
icon: "rotate-cw",
|
|
5112
|
+
label: "Rotate",
|
|
5113
|
+
type: "button",
|
|
5114
|
+
group: "view",
|
|
5115
|
+
execute: () => instance.rotateCW?.()
|
|
5116
|
+
},
|
|
4518
5117
|
{
|
|
4519
5118
|
id: "copy",
|
|
4520
5119
|
icon: "copy",
|
|
@@ -4550,20 +5149,9 @@ var DocPlugin = class {
|
|
|
4550
5149
|
container.style.overflow = "auto";
|
|
4551
5150
|
container.style.padding = "32px 16px";
|
|
4552
5151
|
container.style.backgroundColor = "#f1f5f9";
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
wrapper.style.margin = "0 auto";
|
|
4557
|
-
wrapper.style.backgroundColor = "#ffffff";
|
|
4558
|
-
wrapper.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4559
|
-
wrapper.style.borderRadius = "4px";
|
|
4560
|
-
wrapper.style.padding = "56px 48px";
|
|
4561
|
-
wrapper.style.minHeight = "100%";
|
|
4562
|
-
wrapper.style.transformOrigin = "top center";
|
|
4563
|
-
wrapper.style.transition = "transform 0.2s ease";
|
|
4564
|
-
wrapper.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4565
|
-
wrapper.style.color = "#1e293b";
|
|
4566
|
-
container.appendChild(wrapper);
|
|
5152
|
+
container.style.display = "flex";
|
|
5153
|
+
container.style.justifyContent = "center";
|
|
5154
|
+
container.style.alignItems = "flex-start";
|
|
4567
5155
|
ctx.container.appendChild(container);
|
|
4568
5156
|
let scale = 1;
|
|
4569
5157
|
let extractedRawText = "";
|
|
@@ -4590,21 +5178,27 @@ var DocPlugin = class {
|
|
|
4590
5178
|
const rawPages = this.splitIntoPages(extractedRawText);
|
|
4591
5179
|
const totalPages = Math.max(1, rawPages.length);
|
|
4592
5180
|
let currentPage = 1;
|
|
4593
|
-
wrapper.innerHTML = "";
|
|
4594
5181
|
const pageCards = [];
|
|
4595
5182
|
for (let i = 0; i < totalPages; i++) {
|
|
4596
5183
|
const pageCard = document.createElement("div");
|
|
4597
5184
|
pageCard.className = "fp-doc-page-card";
|
|
5185
|
+
pageCard.style.width = "816px";
|
|
5186
|
+
pageCard.style.height = "1056px";
|
|
4598
5187
|
pageCard.style.backgroundColor = "#ffffff";
|
|
4599
5188
|
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4600
5189
|
pageCard.style.borderRadius = "4px";
|
|
4601
|
-
pageCard.style.padding = "
|
|
4602
|
-
pageCard.style.
|
|
5190
|
+
pageCard.style.padding = "96px 72px";
|
|
5191
|
+
pageCard.style.boxSizing = "border-box";
|
|
5192
|
+
pageCard.style.overflow = "hidden";
|
|
4603
5193
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
5194
|
+
pageCard.style.transformOrigin = "top center";
|
|
5195
|
+
pageCard.style.transition = "transform 0.2s ease";
|
|
5196
|
+
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
5197
|
+
pageCard.style.color = "#1e293b";
|
|
4604
5198
|
if (isFallback && i === 0) {
|
|
4605
5199
|
pageCard.innerHTML = `
|
|
4606
5200
|
<div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
|
|
4607
|
-
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${
|
|
5201
|
+
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify6.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
|
|
4608
5202
|
<span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
|
|
4609
5203
|
</div>
|
|
4610
5204
|
${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
|
|
@@ -4612,15 +5206,17 @@ var DocPlugin = class {
|
|
|
4612
5206
|
} else {
|
|
4613
5207
|
pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
|
|
4614
5208
|
}
|
|
4615
|
-
|
|
5209
|
+
container.appendChild(pageCard);
|
|
4616
5210
|
pageCards.push(pageCard);
|
|
4617
5211
|
}
|
|
4618
5212
|
let indicator = null;
|
|
4619
5213
|
if (totalPages > 1) {
|
|
4620
5214
|
indicator = document.createElement("div");
|
|
4621
5215
|
indicator.className = "fp-doc-page-indicator";
|
|
4622
|
-
indicator.style.position = "
|
|
5216
|
+
indicator.style.position = "fixed";
|
|
4623
5217
|
indicator.style.bottom = "16px";
|
|
5218
|
+
indicator.style.left = "50%";
|
|
5219
|
+
indicator.style.transform = "translateX(-50%)";
|
|
4624
5220
|
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4625
5221
|
indicator.style.backdropFilter = "blur(8px)";
|
|
4626
5222
|
indicator.style.color = "#f8fafc";
|
|
@@ -4634,17 +5230,25 @@ var DocPlugin = class {
|
|
|
4634
5230
|
indicator.style.userSelect = "none";
|
|
4635
5231
|
indicator.style.pointerEvents = "none";
|
|
4636
5232
|
indicator.style.textAlign = "center";
|
|
4637
|
-
indicator.style.width = "fit-content";
|
|
4638
|
-
indicator.style.margin = "16px auto 0";
|
|
4639
5233
|
container.appendChild(indicator);
|
|
4640
5234
|
}
|
|
5235
|
+
let rotation = 0;
|
|
5236
|
+
const applyTransform = () => {
|
|
5237
|
+
const activeCard = pageCards[currentPage - 1];
|
|
5238
|
+
if (activeCard) {
|
|
5239
|
+
activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5240
|
+
}
|
|
5241
|
+
};
|
|
4641
5242
|
const showPage = (pageNum) => {
|
|
4642
5243
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
card.style.display =
|
|
4646
|
-
|
|
4647
|
-
|
|
5244
|
+
pageCards.forEach((card, idx) => {
|
|
5245
|
+
if (idx + 1 === currentPage) {
|
|
5246
|
+
card.style.display = "block";
|
|
5247
|
+
card.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5248
|
+
} else {
|
|
5249
|
+
card.style.display = "none";
|
|
5250
|
+
}
|
|
5251
|
+
});
|
|
4648
5252
|
if (indicator) {
|
|
4649
5253
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4650
5254
|
}
|
|
@@ -4653,6 +5257,17 @@ var DocPlugin = class {
|
|
|
4653
5257
|
if (totalPages > 1) {
|
|
4654
5258
|
showPage(1);
|
|
4655
5259
|
}
|
|
5260
|
+
const calculateFitScale = () => {
|
|
5261
|
+
const elW = 816;
|
|
5262
|
+
const elH = 1056;
|
|
5263
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
5264
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
5265
|
+
return Math.min(1.1, Math.min(availW / elW, availH / elH));
|
|
5266
|
+
};
|
|
5267
|
+
setTimeout(() => {
|
|
5268
|
+
scale = calculateFitScale();
|
|
5269
|
+
applyTransform();
|
|
5270
|
+
}, 60);
|
|
4656
5271
|
const cleanup = () => {
|
|
4657
5272
|
indicator?.remove();
|
|
4658
5273
|
container.remove();
|
|
@@ -4665,21 +5280,30 @@ var DocPlugin = class {
|
|
|
4665
5280
|
getCurrentPage: () => currentPage,
|
|
4666
5281
|
goToPage: (page) => showPage(page),
|
|
4667
5282
|
zoomIn: () => {
|
|
4668
|
-
scale += 0.
|
|
4669
|
-
|
|
5283
|
+
scale += 0.15;
|
|
5284
|
+
applyTransform();
|
|
4670
5285
|
},
|
|
4671
5286
|
zoomOut: () => {
|
|
4672
|
-
scale = Math.max(0.2, scale - 0.
|
|
4673
|
-
|
|
5287
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
5288
|
+
applyTransform();
|
|
4674
5289
|
},
|
|
4675
5290
|
getZoom: () => scale,
|
|
4676
5291
|
setZoom: (level) => {
|
|
4677
5292
|
scale = level;
|
|
4678
|
-
|
|
5293
|
+
applyTransform();
|
|
4679
5294
|
},
|
|
4680
5295
|
fitToPage: () => {
|
|
4681
|
-
scale =
|
|
4682
|
-
|
|
5296
|
+
scale = calculateFitScale();
|
|
5297
|
+
rotation = 0;
|
|
5298
|
+
applyTransform();
|
|
5299
|
+
},
|
|
5300
|
+
rotateCW: () => {
|
|
5301
|
+
rotation = (rotation + 90) % 360;
|
|
5302
|
+
applyTransform();
|
|
5303
|
+
},
|
|
5304
|
+
rotateCCW: () => {
|
|
5305
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
5306
|
+
applyTransform();
|
|
4683
5307
|
},
|
|
4684
5308
|
copy: () => {
|
|
4685
5309
|
navigator.clipboard.writeText(extractedRawText);
|
|
@@ -4797,8 +5421,28 @@ var DocPlugin = class {
|
|
|
4797
5421
|
}
|
|
4798
5422
|
splitIntoPages(text) {
|
|
4799
5423
|
if (!text) return [""];
|
|
4800
|
-
const
|
|
4801
|
-
|
|
5424
|
+
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);
|
|
5425
|
+
if (explicitParts.length === 0) explicitParts.push(text);
|
|
5426
|
+
const maxLinesPerPage = 48;
|
|
5427
|
+
const finalPages = [];
|
|
5428
|
+
for (const part of explicitParts) {
|
|
5429
|
+
const lines = part.split(/\r?\n/);
|
|
5430
|
+
let currentLines = [];
|
|
5431
|
+
let count = 0;
|
|
5432
|
+
for (const line of lines) {
|
|
5433
|
+
currentLines.push(line);
|
|
5434
|
+
count++;
|
|
5435
|
+
if (count >= maxLinesPerPage) {
|
|
5436
|
+
finalPages.push(currentLines.join("\n"));
|
|
5437
|
+
currentLines = [];
|
|
5438
|
+
count = 0;
|
|
5439
|
+
}
|
|
5440
|
+
}
|
|
5441
|
+
if (currentLines.length > 0) {
|
|
5442
|
+
finalPages.push(currentLines.join("\n"));
|
|
5443
|
+
}
|
|
5444
|
+
}
|
|
5445
|
+
return finalPages.length > 0 ? finalPages : [text];
|
|
4802
5446
|
}
|
|
4803
5447
|
/**
|
|
4804
5448
|
* Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
|
|
@@ -4807,17 +5451,65 @@ var DocPlugin = class {
|
|
|
4807
5451
|
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
|
|
4808
5452
|
let html = "";
|
|
4809
5453
|
let inList = false;
|
|
4810
|
-
|
|
4811
|
-
|
|
5454
|
+
let tableLines = [];
|
|
5455
|
+
const flushTable = () => {
|
|
5456
|
+
if (tableLines.length > 0) {
|
|
5457
|
+
html += '<table style="width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 12px;">';
|
|
5458
|
+
for (const tLine of tableLines) {
|
|
5459
|
+
html += "<tr>";
|
|
5460
|
+
const cols = tLine.split(" ");
|
|
5461
|
+
for (const col of cols) {
|
|
5462
|
+
html += `<td style="border: 1px solid #cbd5e1; padding: 6px 8px;">${DOMPurify6.sanitize(col.trim())}</td>`;
|
|
5463
|
+
}
|
|
5464
|
+
html += "</tr>";
|
|
5465
|
+
}
|
|
5466
|
+
html += "</table>";
|
|
5467
|
+
tableLines = [];
|
|
5468
|
+
}
|
|
5469
|
+
};
|
|
5470
|
+
let i = 0;
|
|
5471
|
+
while (i < lines.length) {
|
|
5472
|
+
let line = lines[i];
|
|
5473
|
+
let tabCount = (line.match(/\t/g) || []).length;
|
|
5474
|
+
if (tabCount > 0) {
|
|
5475
|
+
let consecutiveTableLines = 1;
|
|
5476
|
+
let j = i + 1;
|
|
5477
|
+
while (j < lines.length) {
|
|
5478
|
+
const nextTabCount = (lines[j].match(/\t/g) || []).length;
|
|
5479
|
+
if (nextTabCount === tabCount) {
|
|
5480
|
+
consecutiveTableLines++;
|
|
5481
|
+
j++;
|
|
5482
|
+
} else {
|
|
5483
|
+
break;
|
|
5484
|
+
}
|
|
5485
|
+
}
|
|
5486
|
+
if (consecutiveTableLines >= 3) {
|
|
5487
|
+
if (inList) {
|
|
5488
|
+
html += "</ul>";
|
|
5489
|
+
inList = false;
|
|
5490
|
+
}
|
|
5491
|
+
tableLines = lines.slice(i, j);
|
|
5492
|
+
flushTable();
|
|
5493
|
+
i = j;
|
|
5494
|
+
continue;
|
|
5495
|
+
}
|
|
5496
|
+
}
|
|
5497
|
+
line = line.trim();
|
|
4812
5498
|
if (!line) {
|
|
4813
5499
|
if (inList) {
|
|
4814
5500
|
html += "</ul>";
|
|
4815
5501
|
inList = false;
|
|
4816
5502
|
}
|
|
5503
|
+
html += '<div style="height: 1.15em;"></div>';
|
|
5504
|
+
i++;
|
|
4817
5505
|
continue;
|
|
4818
5506
|
}
|
|
4819
|
-
if (/^[\x00-\x1F\x7F-\x9F]+$/.test(line))
|
|
4820
|
-
|
|
5507
|
+
if (/^[\x00-\x1F\x7F-\x9F]+$/.test(line)) {
|
|
5508
|
+
i++;
|
|
5509
|
+
continue;
|
|
5510
|
+
}
|
|
5511
|
+
if ((line.includes("Normal.dot") || line.includes("Microsoft Word") || line.includes("Times New Roman")) && line.length < 30) {
|
|
5512
|
+
i++;
|
|
4821
5513
|
continue;
|
|
4822
5514
|
}
|
|
4823
5515
|
if (line.length < 60 && !line.endsWith(".") && (/^[A-Z0-9\s:_-]+$/.test(line) || line.startsWith("#"))) {
|
|
@@ -4825,24 +5517,26 @@ var DocPlugin = class {
|
|
|
4825
5517
|
html += "</ul>";
|
|
4826
5518
|
inList = false;
|
|
4827
5519
|
}
|
|
4828
|
-
html += `<h2 style="font-size:
|
|
5520
|
+
html += `<h2 style="font-size: 16px; font-weight: 700; color: #1e3a8a; margin: 16px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify6.sanitize(line)}</h2>`;
|
|
4829
5521
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
4830
5522
|
if (!inList) {
|
|
4831
5523
|
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
4832
5524
|
inList = true;
|
|
4833
5525
|
}
|
|
4834
5526
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
4835
|
-
html += `<li style="margin: 4px 0; line-height: 1.
|
|
5527
|
+
html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6.sanitize(bulletText)}</li>`;
|
|
4836
5528
|
} else {
|
|
4837
5529
|
if (inList) {
|
|
4838
5530
|
html += "</ul>";
|
|
4839
5531
|
inList = false;
|
|
4840
5532
|
}
|
|
4841
|
-
html += `<p style="line-height: 1.
|
|
5533
|
+
html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6.sanitize(line)}</p>`;
|
|
4842
5534
|
}
|
|
5535
|
+
i++;
|
|
4843
5536
|
}
|
|
4844
5537
|
if (inList) html += "</ul>";
|
|
4845
|
-
|
|
5538
|
+
flushTable();
|
|
5539
|
+
return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify6.sanitize(filename)})</p>`;
|
|
4846
5540
|
}
|
|
4847
5541
|
};
|
|
4848
5542
|
function docPlugin() {
|
|
@@ -4919,6 +5613,14 @@ var PptPlugin = class {
|
|
|
4919
5613
|
group: "zoom",
|
|
4920
5614
|
execute: () => instance.fitToPage?.()
|
|
4921
5615
|
},
|
|
5616
|
+
{
|
|
5617
|
+
id: "rotate-cw",
|
|
5618
|
+
icon: "rotate-cw",
|
|
5619
|
+
label: "Rotate",
|
|
5620
|
+
type: "button",
|
|
5621
|
+
group: "view",
|
|
5622
|
+
execute: () => instance.rotateCW?.()
|
|
5623
|
+
},
|
|
4922
5624
|
{
|
|
4923
5625
|
id: "download",
|
|
4924
5626
|
icon: "download",
|
|
@@ -4952,22 +5654,36 @@ var PptPlugin = class {
|
|
|
4952
5654
|
const slideCard = document.createElement("div");
|
|
4953
5655
|
slideCard.className = "fp-ppt-slide-card";
|
|
4954
5656
|
slideCard.style.width = "960px";
|
|
4955
|
-
slideCard.style.maxWidth = "
|
|
5657
|
+
slideCard.style.maxWidth = "calc(100% - 32px)";
|
|
5658
|
+
slideCard.style.maxHeight = "calc(100% - 48px)";
|
|
4956
5659
|
slideCard.style.aspectRatio = "16 / 9";
|
|
4957
5660
|
slideCard.style.backgroundColor = "#ffffff";
|
|
4958
5661
|
slideCard.style.boxShadow = "0 12px 40px rgba(0,0,0,0.35)";
|
|
4959
5662
|
slideCard.style.borderRadius = "8px";
|
|
4960
5663
|
slideCard.style.boxSizing = "border-box";
|
|
4961
5664
|
slideCard.style.position = "relative";
|
|
4962
|
-
slideCard.style.overflow = "hidden";
|
|
4963
|
-
slideCard.style.transformOrigin = "center center";
|
|
4964
5665
|
slideCard.style.transition = "transform 0.2s ease";
|
|
5666
|
+
slideCard.style.transformOrigin = "center center";
|
|
5667
|
+
slideCard.style.flexShrink = "0";
|
|
4965
5668
|
container.appendChild(slideCard);
|
|
4966
5669
|
ctx.container.appendChild(container);
|
|
4967
5670
|
let scale = 1;
|
|
5671
|
+
let rotation = 0;
|
|
4968
5672
|
let currentSlide = 1;
|
|
4969
5673
|
let slides = [];
|
|
4970
5674
|
const createdBlobUrls = [];
|
|
5675
|
+
const calculateFitScale = () => {
|
|
5676
|
+
const availW = Math.max(200, container.clientWidth - 48);
|
|
5677
|
+
const availH = Math.max(200, container.clientHeight - 72);
|
|
5678
|
+
return Math.min(1, Math.min(availW / 960, availH / 540));
|
|
5679
|
+
};
|
|
5680
|
+
const applyTransform = () => {
|
|
5681
|
+
slideCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5682
|
+
};
|
|
5683
|
+
setTimeout(() => {
|
|
5684
|
+
scale = calculateFitScale();
|
|
5685
|
+
applyTransform();
|
|
5686
|
+
}, 60);
|
|
4971
5687
|
try {
|
|
4972
5688
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4973
5689
|
const pptStream = cfbf.readStream("PowerPoint Document");
|
|
@@ -4998,7 +5714,7 @@ var PptPlugin = class {
|
|
|
4998
5714
|
if (s.pictureUrl) {
|
|
4999
5715
|
contentHtml = `
|
|
5000
5716
|
<div style="flex: 1; display: flex; justify-content: center; align-items: center; padding: 12px; overflow: hidden;">
|
|
5001
|
-
<img src="${s.pictureUrl}" alt="${
|
|
5717
|
+
<img src="${s.pictureUrl}" alt="${DOMPurify6.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;" />
|
|
5002
5718
|
</div>
|
|
5003
5719
|
`;
|
|
5004
5720
|
} else if (s.tableColumns.length > 0) {
|
|
@@ -5008,7 +5724,7 @@ var PptPlugin = class {
|
|
|
5008
5724
|
<table style="width: 100%; border-collapse: collapse; border: 1px solid #cbd5e1; border-radius: 6px; overflow: hidden; background: #ffffff;">
|
|
5009
5725
|
<thead>
|
|
5010
5726
|
<tr style="background: #e2e8f0; color: #1e293b; font-weight: 600; font-size: 14px;">
|
|
5011
|
-
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${
|
|
5727
|
+
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify6.sanitize(c)}</th>`).join("")}
|
|
5012
5728
|
</tr>
|
|
5013
5729
|
</thead>
|
|
5014
5730
|
<tbody>
|
|
@@ -5024,7 +5740,7 @@ var PptPlugin = class {
|
|
|
5024
5740
|
} else {
|
|
5025
5741
|
const pTags = s.paragraphs.map((p) => {
|
|
5026
5742
|
const lines = p.split(/[\r\n]+/).map((l) => l.trim()).filter(Boolean);
|
|
5027
|
-
return lines.map((l) => `<p style="margin: 0 0 14px; font-size: 14px; line-height: 1.65; color: #334155; text-align: justify;">${
|
|
5743
|
+
return lines.map((l) => `<p style="margin: 0 0 14px; font-size: 14px; line-height: 1.65; color: #334155; text-align: justify;">${DOMPurify6.sanitize(l)}</p>`).join("");
|
|
5028
5744
|
}).join("");
|
|
5029
5745
|
contentHtml = `
|
|
5030
5746
|
<div style="flex: 1; overflow: auto; padding: 4px 8px; display: flex; flex-direction: column; justify-content: flex-start;">
|
|
@@ -5037,11 +5753,11 @@ var PptPlugin = class {
|
|
|
5037
5753
|
<!-- Header Banner matching PowerPoint design -->
|
|
5038
5754
|
<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;">
|
|
5039
5755
|
<h1 style="margin: 0; font-size: 26px; font-weight: 700; color: #1e293b; letter-spacing: -0.3px;">
|
|
5040
|
-
${
|
|
5756
|
+
${DOMPurify6.sanitize(s.title)}
|
|
5041
5757
|
</h1>
|
|
5042
5758
|
${s.subtitle ? `
|
|
5043
5759
|
<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);">
|
|
5044
|
-
${
|
|
5760
|
+
${DOMPurify6.sanitize(s.subtitle)}
|
|
5045
5761
|
</span>
|
|
5046
5762
|
` : `
|
|
5047
5763
|
<span style="font-size: 12px; color: #365314; font-weight: 600;">
|
|
@@ -5068,21 +5784,30 @@ var PptPlugin = class {
|
|
|
5068
5784
|
return {
|
|
5069
5785
|
destroy: cleanup,
|
|
5070
5786
|
zoomIn: () => {
|
|
5071
|
-
scale += 0.
|
|
5072
|
-
|
|
5787
|
+
scale += 0.15;
|
|
5788
|
+
applyTransform();
|
|
5073
5789
|
},
|
|
5074
5790
|
zoomOut: () => {
|
|
5075
|
-
scale = Math.max(0.
|
|
5076
|
-
|
|
5791
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
5792
|
+
applyTransform();
|
|
5077
5793
|
},
|
|
5078
5794
|
getZoom: () => scale,
|
|
5079
5795
|
setZoom: (level) => {
|
|
5080
5796
|
scale = level;
|
|
5081
|
-
|
|
5797
|
+
applyTransform();
|
|
5082
5798
|
},
|
|
5083
5799
|
fitToPage: () => {
|
|
5084
|
-
scale =
|
|
5085
|
-
|
|
5800
|
+
scale = calculateFitScale();
|
|
5801
|
+
rotation = 0;
|
|
5802
|
+
applyTransform();
|
|
5803
|
+
},
|
|
5804
|
+
rotateCW: () => {
|
|
5805
|
+
rotation = (rotation + 90) % 360;
|
|
5806
|
+
applyTransform();
|
|
5807
|
+
},
|
|
5808
|
+
rotateCCW: () => {
|
|
5809
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
5810
|
+
applyTransform();
|
|
5086
5811
|
},
|
|
5087
5812
|
goToPage: (page) => {
|
|
5088
5813
|
if (page >= 1 && page <= totalSlides) {
|