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