@files-preview-app/preview-file 1.2.5 → 1.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular.cjs +933 -208
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.js +932 -207
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +934 -209
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +933 -208
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +933 -208
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +932 -207
- package/dist/react.js.map +1 -1
- package/dist/styles.css +28 -1
- package/dist/vue.cjs +933 -208
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +932 -207
- package/dist/vue.js.map +1 -1
- package/package.json +179 -169
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import DOMPurify6 from 'dompurify';
|
|
2
2
|
import * as pdfjsLib from 'pdfjs-dist';
|
|
3
3
|
import * as docx from 'docx-preview';
|
|
4
4
|
import { unzipSync, strFromU8, unzip } from 'fflate';
|
|
@@ -356,7 +356,7 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
356
356
|
if (magicMime === "application/zip") {
|
|
357
357
|
const ooxmlMime = detectOoxmlType(buffer);
|
|
358
358
|
if (ooxmlMime && ooxmlMime !== "application/zip") {
|
|
359
|
-
metadata.mimeType = ooxmlMime;
|
|
359
|
+
metadata.mimeType = metadata.mimeType ?? ooxmlMime;
|
|
360
360
|
if (ooxmlMime.includes("wordprocessing")) metadata.extension = metadata.extension ?? ".docx";
|
|
361
361
|
else if (ooxmlMime.includes("spreadsheet")) metadata.extension = metadata.extension ?? ".xlsx";
|
|
362
362
|
else if (ooxmlMime.includes("presentation")) metadata.extension = metadata.extension ?? ".pptx";
|
|
@@ -385,12 +385,12 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
385
385
|
return { buffer, metadata };
|
|
386
386
|
}
|
|
387
387
|
function sanitizeHTML(html) {
|
|
388
|
-
return
|
|
388
|
+
return DOMPurify6.sanitize(html, {
|
|
389
389
|
USE_PROFILES: { html: true }
|
|
390
390
|
});
|
|
391
391
|
}
|
|
392
392
|
function sanitizeSVG(svg) {
|
|
393
|
-
return
|
|
393
|
+
return DOMPurify6.sanitize(svg, {
|
|
394
394
|
USE_PROFILES: { svg: true, svgFilters: true }
|
|
395
395
|
});
|
|
396
396
|
}
|
|
@@ -748,6 +748,8 @@ var FilePreviewViewer = class {
|
|
|
748
748
|
keyHandler = null;
|
|
749
749
|
currentContainer = null;
|
|
750
750
|
currentOptions = {};
|
|
751
|
+
resizeObserver = null;
|
|
752
|
+
fullscreenHandler = null;
|
|
751
753
|
/**
|
|
752
754
|
* Register a preview plugin.
|
|
753
755
|
*/
|
|
@@ -820,12 +822,31 @@ var FilePreviewViewer = class {
|
|
|
820
822
|
label: "Toggle Fullscreen",
|
|
821
823
|
type: "button",
|
|
822
824
|
group: "view",
|
|
823
|
-
execute: () => {
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
825
|
+
execute: async () => {
|
|
826
|
+
try {
|
|
827
|
+
const isNativeFs = !!document.fullscreenElement;
|
|
828
|
+
const isCssFs = this.wrapperEl?.classList.contains("fp-fullscreen-active");
|
|
829
|
+
if (!isNativeFs && !isCssFs) {
|
|
830
|
+
if (this.wrapperEl?.requestFullscreen) {
|
|
831
|
+
await this.wrapperEl.requestFullscreen().catch(() => {
|
|
832
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
833
|
+
});
|
|
834
|
+
} else {
|
|
835
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
836
|
+
}
|
|
837
|
+
} else {
|
|
838
|
+
if (document.fullscreenElement) {
|
|
839
|
+
await document.exitFullscreen().catch(() => {
|
|
840
|
+
});
|
|
841
|
+
}
|
|
842
|
+
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
843
|
+
}
|
|
844
|
+
} catch {
|
|
845
|
+
this.wrapperEl?.classList.toggle("fp-fullscreen-active");
|
|
828
846
|
}
|
|
847
|
+
setTimeout(() => {
|
|
848
|
+
this.activeInstance?.fitToPage?.();
|
|
849
|
+
}, 120);
|
|
829
850
|
}
|
|
830
851
|
});
|
|
831
852
|
}
|
|
@@ -875,6 +896,15 @@ var FilePreviewViewer = class {
|
|
|
875
896
|
window.removeEventListener("keydown", this.keyHandler);
|
|
876
897
|
this.keyHandler = null;
|
|
877
898
|
}
|
|
899
|
+
if (this.resizeObserver) {
|
|
900
|
+
this.resizeObserver.disconnect();
|
|
901
|
+
this.resizeObserver = null;
|
|
902
|
+
}
|
|
903
|
+
if (this.fullscreenHandler) {
|
|
904
|
+
document.removeEventListener("fullscreenchange", this.fullscreenHandler);
|
|
905
|
+
document.removeEventListener("webkitfullscreenchange", this.fullscreenHandler);
|
|
906
|
+
this.fullscreenHandler = null;
|
|
907
|
+
}
|
|
878
908
|
this.abort();
|
|
879
909
|
this.destroyInstance();
|
|
880
910
|
this.toolbar?.destroy();
|
|
@@ -954,6 +984,25 @@ var FilePreviewViewer = class {
|
|
|
954
984
|
this.thumbnailPanel = new ThumbnailPanel(thumbnailEl);
|
|
955
985
|
this.setupKeyboardShortcuts();
|
|
956
986
|
this.setupDragAndDrop(container, options);
|
|
987
|
+
this.setupResizeAndFullscreenListeners();
|
|
988
|
+
}
|
|
989
|
+
setupResizeAndFullscreenListeners() {
|
|
990
|
+
if (this.fullscreenHandler) return;
|
|
991
|
+
this.fullscreenHandler = () => {
|
|
992
|
+
setTimeout(() => {
|
|
993
|
+
this.activeInstance?.fitToPage?.();
|
|
994
|
+
}, 100);
|
|
995
|
+
};
|
|
996
|
+
document.addEventListener("fullscreenchange", this.fullscreenHandler);
|
|
997
|
+
document.addEventListener("webkitfullscreenchange", this.fullscreenHandler);
|
|
998
|
+
if (typeof ResizeObserver !== "undefined" && this.contentEl) {
|
|
999
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
1000
|
+
if (this.activeInstance && (!this.activeInstance.getZoom || Math.abs((this.activeInstance.getZoom?.() ?? 1) - 1) < 0.05)) {
|
|
1001
|
+
this.activeInstance.fitToPage?.();
|
|
1002
|
+
}
|
|
1003
|
+
});
|
|
1004
|
+
this.resizeObserver.observe(this.contentEl);
|
|
1005
|
+
}
|
|
957
1006
|
}
|
|
958
1007
|
setupKeyboardShortcuts() {
|
|
959
1008
|
if (this.keyHandler) return;
|
|
@@ -1345,7 +1394,8 @@ var PdfPlugin = class {
|
|
|
1345
1394
|
container.style.display = "flex";
|
|
1346
1395
|
container.style.flexDirection = "column";
|
|
1347
1396
|
container.style.alignItems = "center";
|
|
1348
|
-
container.style.
|
|
1397
|
+
container.style.justifyContent = "flex-start";
|
|
1398
|
+
container.style.padding = "20px 16px";
|
|
1349
1399
|
container.style.backgroundColor = "#0f172a";
|
|
1350
1400
|
container.style.boxSizing = "border-box";
|
|
1351
1401
|
container.style.position = "relative";
|
|
@@ -1358,7 +1408,8 @@ var PdfPlugin = class {
|
|
|
1358
1408
|
pageCard.style.lineHeight = "0";
|
|
1359
1409
|
pageCard.style.transition = "transform 0.15s ease";
|
|
1360
1410
|
pageCard.style.position = "relative";
|
|
1361
|
-
|
|
1411
|
+
pageCard.style.flexShrink = "0";
|
|
1412
|
+
let canvas = document.createElement("canvas");
|
|
1362
1413
|
pageCard.appendChild(canvas);
|
|
1363
1414
|
container.appendChild(pageCard);
|
|
1364
1415
|
const indicator = document.createElement("div");
|
|
@@ -1400,14 +1451,22 @@ var PdfPlugin = class {
|
|
|
1400
1451
|
}
|
|
1401
1452
|
currentRenderTask = null;
|
|
1402
1453
|
}
|
|
1454
|
+
const newCanvas = document.createElement("canvas");
|
|
1455
|
+
pageCard.replaceChild(newCanvas, canvas);
|
|
1456
|
+
canvas = newCanvas;
|
|
1403
1457
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1404
1458
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1405
1459
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1406
1460
|
const page = await pdfDoc.getPage(currentPage);
|
|
1407
1461
|
const containerWidth = container.clientWidth || 900;
|
|
1462
|
+
const containerHeight = container.clientHeight || 700;
|
|
1408
1463
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1409
|
-
const
|
|
1410
|
-
const
|
|
1464
|
+
const availWidth = Math.max(100, containerWidth - 48);
|
|
1465
|
+
const availHeight = Math.max(100, containerHeight - 88);
|
|
1466
|
+
const scaleW = availWidth / unscaledVp.width;
|
|
1467
|
+
const scaleH = availHeight / unscaledVp.height;
|
|
1468
|
+
const fitScale = Math.min(scaleW, scaleH);
|
|
1469
|
+
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1411
1470
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
1412
1471
|
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
1413
1472
|
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
@@ -1432,7 +1491,19 @@ var PdfPlugin = class {
|
|
|
1432
1491
|
}
|
|
1433
1492
|
};
|
|
1434
1493
|
await renderPage(1);
|
|
1494
|
+
let resizeTimer = null;
|
|
1495
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
1496
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1497
|
+
resizeTimer = setTimeout(() => {
|
|
1498
|
+
if (Math.abs(zoomScale - 1) < 0.05) {
|
|
1499
|
+
renderPage(currentPage);
|
|
1500
|
+
}
|
|
1501
|
+
}, 150);
|
|
1502
|
+
});
|
|
1503
|
+
resizeObserver.observe(container);
|
|
1435
1504
|
const cleanup = () => {
|
|
1505
|
+
resizeObserver.disconnect();
|
|
1506
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1436
1507
|
if (currentRenderTask) {
|
|
1437
1508
|
try {
|
|
1438
1509
|
currentRenderTask.cancel();
|
|
@@ -1464,6 +1535,7 @@ var PdfPlugin = class {
|
|
|
1464
1535
|
},
|
|
1465
1536
|
fitToPage: () => {
|
|
1466
1537
|
zoomScale = 1;
|
|
1538
|
+
rotation = 0;
|
|
1467
1539
|
renderPage(currentPage);
|
|
1468
1540
|
},
|
|
1469
1541
|
rotateCW: () => {
|
|
@@ -1914,6 +1986,14 @@ var DocxPlugin = class {
|
|
|
1914
1986
|
group: "zoom",
|
|
1915
1987
|
execute: () => instance.fitToPage?.()
|
|
1916
1988
|
},
|
|
1989
|
+
{
|
|
1990
|
+
id: "rotate-cw",
|
|
1991
|
+
icon: "rotate-cw",
|
|
1992
|
+
label: "Rotate",
|
|
1993
|
+
type: "button",
|
|
1994
|
+
group: "view",
|
|
1995
|
+
execute: () => instance.rotateCW?.()
|
|
1996
|
+
},
|
|
1917
1997
|
{
|
|
1918
1998
|
id: "download",
|
|
1919
1999
|
icon: "download",
|
|
@@ -2050,6 +2130,26 @@ var DocxPlugin = class {
|
|
|
2050
2130
|
if (totalPages > 1) {
|
|
2051
2131
|
showPage(1);
|
|
2052
2132
|
}
|
|
2133
|
+
scale = 1;
|
|
2134
|
+
let rotation = 0;
|
|
2135
|
+
const calculateFitScale = () => {
|
|
2136
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.firstElementChild || wrapper;
|
|
2137
|
+
const elW = activeEl.offsetWidth || 816;
|
|
2138
|
+
const elH = activeEl.offsetHeight || 1056;
|
|
2139
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
2140
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
2141
|
+
const sW = availW / elW;
|
|
2142
|
+
const sH = availH / elH;
|
|
2143
|
+
return Math.min(1.1, Math.min(sW, sH));
|
|
2144
|
+
};
|
|
2145
|
+
const applyTransform = () => {
|
|
2146
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2147
|
+
wrapper.style.transformOrigin = "top center";
|
|
2148
|
+
};
|
|
2149
|
+
setTimeout(() => {
|
|
2150
|
+
scale = calculateFitScale();
|
|
2151
|
+
applyTransform();
|
|
2152
|
+
}, 60);
|
|
2053
2153
|
const cleanup = () => {
|
|
2054
2154
|
indicator?.remove();
|
|
2055
2155
|
for (const url of createdBlobUrls) {
|
|
@@ -2068,21 +2168,30 @@ var DocxPlugin = class {
|
|
|
2068
2168
|
showPage(page);
|
|
2069
2169
|
},
|
|
2070
2170
|
zoomIn: () => {
|
|
2071
|
-
scale += 0.
|
|
2072
|
-
|
|
2171
|
+
scale += 0.15;
|
|
2172
|
+
applyTransform();
|
|
2073
2173
|
},
|
|
2074
2174
|
zoomOut: () => {
|
|
2075
|
-
scale = Math.max(0.2, scale - 0.
|
|
2076
|
-
|
|
2175
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
2176
|
+
applyTransform();
|
|
2077
2177
|
},
|
|
2078
2178
|
getZoom: () => scale,
|
|
2079
2179
|
setZoom: (level) => {
|
|
2080
2180
|
scale = level;
|
|
2081
|
-
|
|
2181
|
+
applyTransform();
|
|
2082
2182
|
},
|
|
2083
2183
|
fitToPage: () => {
|
|
2084
|
-
scale =
|
|
2085
|
-
|
|
2184
|
+
scale = calculateFitScale();
|
|
2185
|
+
rotation = 0;
|
|
2186
|
+
applyTransform();
|
|
2187
|
+
},
|
|
2188
|
+
rotateCW: () => {
|
|
2189
|
+
rotation = (rotation + 90) % 360;
|
|
2190
|
+
applyTransform();
|
|
2191
|
+
},
|
|
2192
|
+
rotateCCW: () => {
|
|
2193
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
2194
|
+
applyTransform();
|
|
2086
2195
|
},
|
|
2087
2196
|
download: () => {
|
|
2088
2197
|
const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
|
|
@@ -2142,90 +2251,149 @@ var DocxPlugin = class {
|
|
|
2142
2251
|
console.warn("[DocxPlugin] Error parsing relationships:", relsErr);
|
|
2143
2252
|
}
|
|
2144
2253
|
}
|
|
2145
|
-
const
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2254
|
+
const sectPrs = Array.from(doc.getElementsByTagNameNS("*", "sectPr"));
|
|
2255
|
+
const lastSectPr = sectPrs[sectPrs.length - 1];
|
|
2256
|
+
let defaultW = 12240;
|
|
2257
|
+
let defaultH = 15840;
|
|
2258
|
+
let margins = { top: 1440, right: 1440, bottom: 1440, left: 1440 };
|
|
2259
|
+
if (lastSectPr) {
|
|
2260
|
+
const pgSz = lastSectPr.getElementsByTagNameNS("*", "pgSz")[0];
|
|
2261
|
+
if (pgSz) {
|
|
2262
|
+
defaultW = parseInt(pgSz.getAttribute("w:w") || pgSz.getAttribute("w") || "12240", 10);
|
|
2263
|
+
defaultH = parseInt(pgSz.getAttribute("w:h") || pgSz.getAttribute("h") || "15840", 10);
|
|
2264
|
+
}
|
|
2265
|
+
const pgMar = lastSectPr.getElementsByTagNameNS("*", "pgMar")[0];
|
|
2266
|
+
if (pgMar) {
|
|
2267
|
+
margins.top = parseInt(pgMar.getAttribute("w:top") || pgMar.getAttribute("top") || "1440", 10);
|
|
2268
|
+
margins.bottom = parseInt(pgMar.getAttribute("w:bottom") || pgMar.getAttribute("bottom") || "1440", 10);
|
|
2269
|
+
margins.left = parseInt(pgMar.getAttribute("w:left") || pgMar.getAttribute("left") || "1440", 10);
|
|
2270
|
+
margins.right = parseInt(pgMar.getAttribute("w:right") || pgMar.getAttribute("right") || "1440", 10);
|
|
2271
|
+
}
|
|
2272
|
+
}
|
|
2273
|
+
const createPageCard = () => {
|
|
2274
|
+
const card = document.createElement("div");
|
|
2275
|
+
card.className = "fp-docx-page-card";
|
|
2276
|
+
card.style.backgroundColor = "#ffffff";
|
|
2277
|
+
card.style.borderRadius = "4px";
|
|
2278
|
+
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
2279
|
+
card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
2280
|
+
card.style.color = "#1e293b";
|
|
2281
|
+
card.style.lineHeight = "1.6";
|
|
2282
|
+
card.style.boxSizing = "border-box";
|
|
2283
|
+
card.style.overflow = "hidden";
|
|
2284
|
+
card.style.position = "relative";
|
|
2285
|
+
card.style.marginBottom = "24px";
|
|
2286
|
+
card.style.width = `${defaultW / 15}px`;
|
|
2287
|
+
card.style.height = `${defaultH / 15}px`;
|
|
2288
|
+
card.style.padding = `${margins.top / 15}px ${margins.right / 15}px ${margins.bottom / 15}px ${margins.left / 15}px`;
|
|
2289
|
+
return card;
|
|
2290
|
+
};
|
|
2291
|
+
let currentCard = createPageCard();
|
|
2292
|
+
let currentHtml = "";
|
|
2293
|
+
const pages = [{ card: currentCard, html: "" }];
|
|
2294
|
+
const flushHtml = () => {
|
|
2295
|
+
pages[pages.length - 1].html += currentHtml;
|
|
2296
|
+
currentHtml = "";
|
|
2297
|
+
};
|
|
2298
|
+
const newPage = () => {
|
|
2299
|
+
flushHtml();
|
|
2300
|
+
currentCard = createPageCard();
|
|
2301
|
+
pages.push({ card: currentCard, html: "" });
|
|
2302
|
+
};
|
|
2154
2303
|
const body = doc.getElementsByTagNameNS("*", "body")[0] || doc.documentElement;
|
|
2155
|
-
let html = "";
|
|
2156
2304
|
for (const child of Array.from(body.children)) {
|
|
2157
2305
|
const tag = child.localName || child.nodeName.split(":").pop();
|
|
2158
2306
|
if (tag === "p") {
|
|
2159
2307
|
const pStyle = child.getElementsByTagNameNS("*", "pStyle")[0];
|
|
2160
2308
|
const styleVal = pStyle?.getAttribute("w:val") || pStyle?.getAttribute("val") || "";
|
|
2161
2309
|
const numPr = child.getElementsByTagNameNS("*", "numPr")[0];
|
|
2162
|
-
const
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2310
|
+
const chunks = this.extractParagraphChunks(child, imageMap);
|
|
2311
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
2312
|
+
if (i > 0) {
|
|
2313
|
+
newPage();
|
|
2314
|
+
}
|
|
2315
|
+
const textContent = chunks[i];
|
|
2316
|
+
if (!textContent.trim() && !textContent.includes("<img")) {
|
|
2317
|
+
currentHtml += '<div style="height: 10px;"></div>';
|
|
2318
|
+
continue;
|
|
2319
|
+
}
|
|
2320
|
+
const lowerStyle = styleVal.toLowerCase();
|
|
2321
|
+
if (lowerStyle.includes("title")) {
|
|
2322
|
+
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>`;
|
|
2323
|
+
} else if (lowerStyle.includes("heading1") || styleVal === "1") {
|
|
2324
|
+
currentHtml += `<h2 style="font-size: 22px; font-weight: 700; color: #1e40af; margin: 20px 0 10px;">${textContent}</h2>`;
|
|
2325
|
+
} else if (lowerStyle.includes("heading2") || styleVal === "2") {
|
|
2326
|
+
currentHtml += `<h3 style="font-size: 18px; font-weight: 600; color: #2563eb; margin: 16px 0 8px;">${textContent}</h3>`;
|
|
2327
|
+
} else if (lowerStyle.includes("heading3") || styleVal === "3") {
|
|
2328
|
+
currentHtml += `<h4 style="font-size: 15px; font-weight: 600; color: #334155; margin: 12px 0 6px;">${textContent}</h4>`;
|
|
2329
|
+
} else if (numPr) {
|
|
2330
|
+
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>`;
|
|
2331
|
+
} else {
|
|
2332
|
+
currentHtml += `<p style="margin: 8px 0; font-size: 14px;">${textContent}</p>`;
|
|
2333
|
+
}
|
|
2180
2334
|
}
|
|
2181
2335
|
} else if (tag === "tbl") {
|
|
2182
|
-
|
|
2336
|
+
currentHtml += '<table style="width: 100%; border-collapse: collapse; margin: 20px 0; border: 1px solid #cbd5e1;">';
|
|
2183
2337
|
const rows = Array.from(child.getElementsByTagNameNS("*", "tr"));
|
|
2184
2338
|
rows.forEach((tr, rIdx) => {
|
|
2185
|
-
|
|
2339
|
+
currentHtml += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
|
|
2186
2340
|
const cells = Array.from(tr.getElementsByTagNameNS("*", "tc"));
|
|
2187
2341
|
cells.forEach((tc) => {
|
|
2188
2342
|
const cellText = this.extractParagraphHtml(tc, imageMap);
|
|
2189
|
-
|
|
2343
|
+
currentHtml += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || " "}</td>`;
|
|
2190
2344
|
});
|
|
2191
|
-
|
|
2345
|
+
currentHtml += "</tr>";
|
|
2192
2346
|
});
|
|
2193
|
-
|
|
2347
|
+
currentHtml += "</table>";
|
|
2194
2348
|
}
|
|
2195
2349
|
}
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2350
|
+
flushHtml();
|
|
2351
|
+
for (const page of pages) {
|
|
2352
|
+
page.card.innerHTML = DOMPurify6.sanitize(page.html, {
|
|
2353
|
+
ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "s", "strike", "img", "div", "br"],
|
|
2354
|
+
ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
|
|
2355
|
+
});
|
|
2356
|
+
wrapper.appendChild(page.card);
|
|
2357
|
+
}
|
|
2201
2358
|
}
|
|
2202
2359
|
extractParagraphHtml(pElement, imageMap = {}) {
|
|
2203
|
-
|
|
2360
|
+
return this.extractParagraphChunks(pElement, imageMap).join("<br/>");
|
|
2361
|
+
}
|
|
2362
|
+
extractParagraphChunks(pElement, imageMap = {}) {
|
|
2363
|
+
const chunks = [""];
|
|
2364
|
+
let currentChunkIndex = 0;
|
|
2204
2365
|
const drawings = Array.from(pElement.getElementsByTagNameNS("*", "drawing"));
|
|
2205
2366
|
for (const drawing of drawings) {
|
|
2206
2367
|
const blip = drawing.getElementsByTagNameNS("*", "blip")[0];
|
|
2207
2368
|
const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
|
|
2208
2369
|
if (rId && imageMap[rId]) {
|
|
2209
|
-
|
|
2370
|
+
chunks[currentChunkIndex] += `<div style="text-align:center; margin: 12px 0;"><img src="${imageMap[rId]}" style="max-width: 100%; height: auto; border-radius: 4px;" /></div>`;
|
|
2210
2371
|
}
|
|
2211
2372
|
}
|
|
2212
2373
|
const runs = Array.from(pElement.getElementsByTagNameNS("*", "r"));
|
|
2213
|
-
if (runs.length === 0 && !
|
|
2214
|
-
|
|
2374
|
+
if (runs.length === 0 && !chunks[currentChunkIndex]) {
|
|
2375
|
+
chunks[currentChunkIndex] = DOMPurify6.sanitize(pElement.textContent || "");
|
|
2376
|
+
return chunks;
|
|
2215
2377
|
}
|
|
2216
2378
|
for (const r of runs) {
|
|
2217
2379
|
const blip = r.getElementsByTagNameNS("*", "blip")[0] || r.getElementsByTagNameNS("*", "imagedata")[0];
|
|
2218
2380
|
const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
|
|
2219
2381
|
if (rId && imageMap[rId]) {
|
|
2220
|
-
|
|
2382
|
+
chunks[currentChunkIndex] += `<img src="${imageMap[rId]}" style="max-width: 100%; height: auto; display: inline-block; margin: 4px;" />`;
|
|
2221
2383
|
}
|
|
2222
|
-
const brs = r.getElementsByTagNameNS("*", "br");
|
|
2223
|
-
for (
|
|
2224
|
-
|
|
2384
|
+
const brs = Array.from(r.getElementsByTagNameNS("*", "br"));
|
|
2385
|
+
for (const br of brs) {
|
|
2386
|
+
const type = br.getAttribute("w:type") || br.getAttribute("type");
|
|
2387
|
+
if (type === "page") {
|
|
2388
|
+
chunks.push("");
|
|
2389
|
+
currentChunkIndex++;
|
|
2390
|
+
} else {
|
|
2391
|
+
chunks[currentChunkIndex] += "<br/>";
|
|
2392
|
+
}
|
|
2225
2393
|
}
|
|
2226
2394
|
const tabs = r.getElementsByTagNameNS("*", "tab");
|
|
2227
2395
|
if (tabs.length > 0) {
|
|
2228
|
-
|
|
2396
|
+
chunks[currentChunkIndex] += " ";
|
|
2229
2397
|
}
|
|
2230
2398
|
const rPr = r.getElementsByTagNameNS("*", "rPr")[0];
|
|
2231
2399
|
const isBold = !!rPr?.getElementsByTagNameNS("*", "b")[0];
|
|
@@ -2239,7 +2407,7 @@ var DocxPlugin = class {
|
|
|
2239
2407
|
const texts = Array.from(r.getElementsByTagNameNS("*", "t"));
|
|
2240
2408
|
let text = texts.map((t) => t.textContent || "").join("");
|
|
2241
2409
|
if (!text) continue;
|
|
2242
|
-
text =
|
|
2410
|
+
text = DOMPurify6.sanitize(text);
|
|
2243
2411
|
let styles = "";
|
|
2244
2412
|
if (isBold) styles += "font-weight: bold; ";
|
|
2245
2413
|
if (isItalic) styles += "font-style: italic; ";
|
|
@@ -2251,12 +2419,12 @@ var DocxPlugin = class {
|
|
|
2251
2419
|
if (!isNaN(pt) && pt > 0) styles += `font-size: ${pt}pt; `;
|
|
2252
2420
|
}
|
|
2253
2421
|
if (styles) {
|
|
2254
|
-
|
|
2422
|
+
chunks[currentChunkIndex] += `<span style="${styles}">${text}</span>`;
|
|
2255
2423
|
} else {
|
|
2256
|
-
|
|
2424
|
+
chunks[currentChunkIndex] += text;
|
|
2257
2425
|
}
|
|
2258
2426
|
}
|
|
2259
|
-
return
|
|
2427
|
+
return chunks;
|
|
2260
2428
|
}
|
|
2261
2429
|
renderBinaryDocFallback(ctx, wrapper) {
|
|
2262
2430
|
const card = document.createElement("div");
|
|
@@ -2273,14 +2441,14 @@ var DocxPlugin = class {
|
|
|
2273
2441
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
2274
2442
|
if (wordDocStream && wordDocStream.length >= 512) {
|
|
2275
2443
|
const text2 = this.extractReadableStrings(wordDocStream);
|
|
2276
|
-
card.innerHTML = `<div style="white-space: pre-wrap;">${
|
|
2444
|
+
card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6.sanitize(text2)}</div>`;
|
|
2277
2445
|
wrapper.appendChild(card);
|
|
2278
2446
|
return;
|
|
2279
2447
|
}
|
|
2280
2448
|
} catch {
|
|
2281
2449
|
}
|
|
2282
2450
|
const text = this.extractReadableStrings(new Uint8Array(ctx.buffer));
|
|
2283
|
-
card.innerHTML = `<div style="white-space: pre-wrap;">${
|
|
2451
|
+
card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6.sanitize(text)}</div>`;
|
|
2284
2452
|
wrapper.appendChild(card);
|
|
2285
2453
|
}
|
|
2286
2454
|
extractReadableStrings(bytes) {
|
|
@@ -2376,6 +2544,26 @@ var ExcelPlugin = class {
|
|
|
2376
2544
|
instance.zoomIn?.();
|
|
2377
2545
|
}
|
|
2378
2546
|
},
|
|
2547
|
+
{
|
|
2548
|
+
id: "fit-page",
|
|
2549
|
+
icon: "fit-page",
|
|
2550
|
+
label: "Fit to View",
|
|
2551
|
+
type: "button",
|
|
2552
|
+
group: "zoom",
|
|
2553
|
+
execute: () => {
|
|
2554
|
+
instance.fitToPage?.();
|
|
2555
|
+
}
|
|
2556
|
+
},
|
|
2557
|
+
{
|
|
2558
|
+
id: "rotate-cw",
|
|
2559
|
+
icon: "rotate-cw",
|
|
2560
|
+
label: "Rotate",
|
|
2561
|
+
type: "button",
|
|
2562
|
+
group: "view",
|
|
2563
|
+
execute: () => {
|
|
2564
|
+
instance.rotateCW?.();
|
|
2565
|
+
}
|
|
2566
|
+
},
|
|
2379
2567
|
{
|
|
2380
2568
|
id: "download",
|
|
2381
2569
|
icon: "download",
|
|
@@ -2426,9 +2614,23 @@ var ExcelPlugin = class {
|
|
|
2426
2614
|
container.appendChild(tabsArea);
|
|
2427
2615
|
ctx.container.appendChild(container);
|
|
2428
2616
|
let scale = 1;
|
|
2617
|
+
let rotation = 0;
|
|
2429
2618
|
let currentSheetIndex = 1;
|
|
2430
2619
|
let sheetNames = [];
|
|
2431
2620
|
let wb = null;
|
|
2621
|
+
const applyTransform = () => {
|
|
2622
|
+
contentArea.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2623
|
+
contentArea.style.transformOrigin = "top left";
|
|
2624
|
+
};
|
|
2625
|
+
const calculateFitScale = () => {
|
|
2626
|
+
const table = contentArea.querySelector("table");
|
|
2627
|
+
if (!table) return 1;
|
|
2628
|
+
const availW = Math.max(200, container.clientWidth - 48);
|
|
2629
|
+
const availH = Math.max(200, container.clientHeight - 80);
|
|
2630
|
+
const tW = table.offsetWidth || 800;
|
|
2631
|
+
const tH = table.offsetHeight || 600;
|
|
2632
|
+
return Math.min(1, Math.min(availW / tW, availH / tH));
|
|
2633
|
+
};
|
|
2432
2634
|
try {
|
|
2433
2635
|
wb = XLSX.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
|
|
2434
2636
|
sheetNames = wb.SheetNames || [];
|
|
@@ -2516,17 +2718,30 @@ var ExcelPlugin = class {
|
|
|
2516
2718
|
return {
|
|
2517
2719
|
destroy: cleanup,
|
|
2518
2720
|
zoomIn: () => {
|
|
2519
|
-
scale += 0.
|
|
2520
|
-
|
|
2721
|
+
scale += 0.15;
|
|
2722
|
+
applyTransform();
|
|
2521
2723
|
},
|
|
2522
2724
|
zoomOut: () => {
|
|
2523
|
-
scale = Math.max(0.2, scale - 0.
|
|
2524
|
-
|
|
2725
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
2726
|
+
applyTransform();
|
|
2525
2727
|
},
|
|
2526
2728
|
getZoom: () => scale,
|
|
2527
2729
|
setZoom: (level) => {
|
|
2528
2730
|
scale = level;
|
|
2529
|
-
|
|
2731
|
+
applyTransform();
|
|
2732
|
+
},
|
|
2733
|
+
fitToPage: () => {
|
|
2734
|
+
scale = calculateFitScale();
|
|
2735
|
+
rotation = 0;
|
|
2736
|
+
applyTransform();
|
|
2737
|
+
},
|
|
2738
|
+
rotateCW: () => {
|
|
2739
|
+
rotation = (rotation + 90) % 360;
|
|
2740
|
+
applyTransform();
|
|
2741
|
+
},
|
|
2742
|
+
rotateCCW: () => {
|
|
2743
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
2744
|
+
applyTransform();
|
|
2530
2745
|
},
|
|
2531
2746
|
goToPage: (page) => {
|
|
2532
2747
|
if (page > 0 && page <= sheetNames.length) {
|
|
@@ -2776,6 +2991,26 @@ var CodePlugin = class {
|
|
|
2776
2991
|
instance.zoomIn?.();
|
|
2777
2992
|
}
|
|
2778
2993
|
},
|
|
2994
|
+
{
|
|
2995
|
+
id: "fit-page",
|
|
2996
|
+
icon: "fit-page",
|
|
2997
|
+
label: "Fit to View",
|
|
2998
|
+
type: "button",
|
|
2999
|
+
group: "zoom",
|
|
3000
|
+
execute: () => {
|
|
3001
|
+
instance.fitToPage?.();
|
|
3002
|
+
}
|
|
3003
|
+
},
|
|
3004
|
+
{
|
|
3005
|
+
id: "rotate-cw",
|
|
3006
|
+
icon: "rotate-cw",
|
|
3007
|
+
label: "Rotate",
|
|
3008
|
+
type: "button",
|
|
3009
|
+
group: "view",
|
|
3010
|
+
execute: () => {
|
|
3011
|
+
instance.rotateCW?.();
|
|
3012
|
+
}
|
|
3013
|
+
},
|
|
2779
3014
|
{
|
|
2780
3015
|
id: "copy",
|
|
2781
3016
|
icon: "copy",
|
|
@@ -2812,40 +3047,94 @@ var CodePlugin = class {
|
|
|
2812
3047
|
async render(ctx) {
|
|
2813
3048
|
const decoder = new TextDecoder("utf-8");
|
|
2814
3049
|
const fullText = decoder.decode(ctx.buffer);
|
|
2815
|
-
const
|
|
2816
|
-
const
|
|
3050
|
+
const extRaw = ctx.metadata.extension?.toLowerCase();
|
|
3051
|
+
const mimeRaw = ctx.metadata.mimeType?.toLowerCase();
|
|
3052
|
+
const isTxt = extRaw === ".txt" || mimeRaw === "text/plain" && (!extRaw || !this.extensions.filter((e) => e !== ".txt").includes(extRaw));
|
|
3053
|
+
let rawPages = [];
|
|
3054
|
+
if (isTxt) {
|
|
3055
|
+
const explicitPages = fullText.split(/(?:\f|\x0C)/);
|
|
3056
|
+
for (const ep of explicitPages) {
|
|
3057
|
+
const lines = ep.split(/\r?\n/);
|
|
3058
|
+
let currentChunk = [];
|
|
3059
|
+
for (let i = 0; i < lines.length; i++) {
|
|
3060
|
+
currentChunk.push(lines[i]);
|
|
3061
|
+
if (currentChunk.length >= 46) {
|
|
3062
|
+
rawPages.push(currentChunk.join("\n"));
|
|
3063
|
+
currentChunk = [];
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
if (currentChunk.length > 0 || lines.length === 0) {
|
|
3067
|
+
rawPages.push(currentChunk.join("\n"));
|
|
3068
|
+
}
|
|
3069
|
+
}
|
|
3070
|
+
if (rawPages.length === 0) rawPages = [""];
|
|
3071
|
+
} else {
|
|
3072
|
+
const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
|
|
3073
|
+
rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
3074
|
+
}
|
|
2817
3075
|
const totalPages = Math.max(1, rawPages.length);
|
|
2818
3076
|
let currentPage = 1;
|
|
2819
3077
|
const container = document.createElement("div");
|
|
2820
3078
|
container.style.width = "100%";
|
|
2821
3079
|
container.style.height = "100%";
|
|
2822
3080
|
container.style.overflow = "auto";
|
|
2823
|
-
container.style.backgroundColor = "#1e1e1e";
|
|
2824
|
-
container.style.color = "#d4d4d4";
|
|
2825
|
-
container.style.padding = "16px";
|
|
2826
|
-
container.style.boxSizing = "border-box";
|
|
2827
3081
|
let fontSize = 13;
|
|
3082
|
+
let rotation = 0;
|
|
3083
|
+
let zoomLevel = 1;
|
|
2828
3084
|
const pre = document.createElement("pre");
|
|
2829
|
-
pre.style.margin = "0";
|
|
2830
|
-
pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
|
|
2831
|
-
pre.style.fontSize = `${fontSize}px`;
|
|
2832
|
-
pre.style.lineHeight = "1.5";
|
|
2833
|
-
pre.style.whiteSpace = "pre-wrap";
|
|
2834
|
-
pre.style.wordBreak = "break-all";
|
|
2835
3085
|
const code = document.createElement("code");
|
|
3086
|
+
if (isTxt) {
|
|
3087
|
+
container.style.backgroundColor = "#f1f5f9";
|
|
3088
|
+
container.style.padding = "32px";
|
|
3089
|
+
container.style.boxSizing = "border-box";
|
|
3090
|
+
container.style.display = "flex";
|
|
3091
|
+
container.style.flexDirection = "column";
|
|
3092
|
+
container.style.alignItems = "center";
|
|
3093
|
+
pre.style.margin = "0";
|
|
3094
|
+
pre.style.fontFamily = "Consolas, 'Courier New', monospace";
|
|
3095
|
+
pre.style.fontSize = "13px";
|
|
3096
|
+
pre.style.color = "#1e293b";
|
|
3097
|
+
pre.style.lineHeight = "1.5";
|
|
3098
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3099
|
+
pre.style.wordBreak = "break-word";
|
|
3100
|
+
pre.style.backgroundColor = "#ffffff";
|
|
3101
|
+
pre.style.width = "816px";
|
|
3102
|
+
pre.style.minHeight = "1056px";
|
|
3103
|
+
pre.style.padding = "72px 56px";
|
|
3104
|
+
pre.style.boxSizing = "border-box";
|
|
3105
|
+
pre.style.boxShadow = "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)";
|
|
3106
|
+
pre.style.borderRadius = "4px";
|
|
3107
|
+
pre.style.transformOrigin = "top center";
|
|
3108
|
+
} else {
|
|
3109
|
+
container.style.backgroundColor = "#1e1e1e";
|
|
3110
|
+
container.style.color = "#d4d4d4";
|
|
3111
|
+
container.style.padding = "16px";
|
|
3112
|
+
container.style.boxSizing = "border-box";
|
|
3113
|
+
pre.style.margin = "0";
|
|
3114
|
+
pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
|
|
3115
|
+
pre.style.fontSize = `${fontSize}px`;
|
|
3116
|
+
pre.style.lineHeight = "1.5";
|
|
3117
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3118
|
+
pre.style.wordBreak = "break-all";
|
|
3119
|
+
pre.style.transformOrigin = "top left";
|
|
3120
|
+
}
|
|
2836
3121
|
const ext = (ctx.metadata.extension || "").replace(".", "");
|
|
2837
3122
|
const renderCodePage = (text) => {
|
|
2838
|
-
|
|
2839
|
-
if (ext && hljs.getLanguage(ext)) {
|
|
2840
|
-
code.innerHTML = hljs.highlight(text, { language: ext }).value;
|
|
2841
|
-
} else {
|
|
2842
|
-
code.innerHTML = hljs.highlightAuto(text).value;
|
|
2843
|
-
}
|
|
2844
|
-
} catch {
|
|
3123
|
+
if (isTxt) {
|
|
2845
3124
|
code.textContent = text;
|
|
3125
|
+
} else {
|
|
3126
|
+
try {
|
|
3127
|
+
if (ext && hljs.getLanguage(ext)) {
|
|
3128
|
+
code.innerHTML = hljs.highlight(text, { language: ext }).value;
|
|
3129
|
+
} else {
|
|
3130
|
+
code.innerHTML = hljs.highlightAuto(text).value;
|
|
3131
|
+
}
|
|
3132
|
+
} catch {
|
|
3133
|
+
code.textContent = text;
|
|
3134
|
+
}
|
|
2846
3135
|
}
|
|
2847
3136
|
};
|
|
2848
|
-
renderCodePage(rawPages[0] || fullText);
|
|
3137
|
+
renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
|
|
2849
3138
|
pre.appendChild(code);
|
|
2850
3139
|
container.appendChild(pre);
|
|
2851
3140
|
let indicator = null;
|
|
@@ -2854,15 +3143,22 @@ var CodePlugin = class {
|
|
|
2854
3143
|
indicator.className = "fp-code-page-indicator";
|
|
2855
3144
|
indicator.style.position = "sticky";
|
|
2856
3145
|
indicator.style.bottom = "16px";
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
3146
|
+
if (isTxt) {
|
|
3147
|
+
indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
|
|
3148
|
+
indicator.style.color = "#334155";
|
|
3149
|
+
indicator.style.border = "1px solid #e2e8f0";
|
|
3150
|
+
indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
|
|
3151
|
+
} else {
|
|
3152
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3153
|
+
indicator.style.color = "#f8fafc";
|
|
3154
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3155
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3156
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
3157
|
+
}
|
|
2860
3158
|
indicator.style.fontSize = "12px";
|
|
2861
3159
|
indicator.style.fontWeight = "600";
|
|
2862
3160
|
indicator.style.padding = "5px 14px";
|
|
2863
3161
|
indicator.style.borderRadius = "20px";
|
|
2864
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2865
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2866
3162
|
indicator.style.zIndex = "10";
|
|
2867
3163
|
indicator.style.userSelect = "none";
|
|
2868
3164
|
indicator.style.pointerEvents = "none";
|
|
@@ -2873,7 +3169,7 @@ var CodePlugin = class {
|
|
|
2873
3169
|
}
|
|
2874
3170
|
const showPage = (pageNum) => {
|
|
2875
3171
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2876
|
-
renderCodePage(rawPages[currentPage - 1] || fullText);
|
|
3172
|
+
renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
|
|
2877
3173
|
if (indicator) {
|
|
2878
3174
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2879
3175
|
}
|
|
@@ -2889,23 +3185,57 @@ var CodePlugin = class {
|
|
|
2889
3185
|
ctx.container.innerHTML = "";
|
|
2890
3186
|
};
|
|
2891
3187
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3188
|
+
const updateTransform = () => {
|
|
3189
|
+
if (isTxt) {
|
|
3190
|
+
pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
|
|
3191
|
+
} else {
|
|
3192
|
+
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3193
|
+
pre.style.fontSize = `${fontSize}px`;
|
|
3194
|
+
}
|
|
3195
|
+
};
|
|
2892
3196
|
return {
|
|
2893
3197
|
destroy: cleanup,
|
|
2894
3198
|
getPageCount: () => totalPages,
|
|
2895
3199
|
getCurrentPage: () => currentPage,
|
|
2896
3200
|
goToPage: (page) => showPage(page),
|
|
2897
3201
|
zoomIn: () => {
|
|
2898
|
-
|
|
2899
|
-
|
|
3202
|
+
if (isTxt) {
|
|
3203
|
+
zoomLevel = Math.min(3, zoomLevel + 0.1);
|
|
3204
|
+
} else {
|
|
3205
|
+
fontSize = Math.min(32, fontSize + 2);
|
|
3206
|
+
}
|
|
3207
|
+
updateTransform();
|
|
2900
3208
|
},
|
|
2901
3209
|
zoomOut: () => {
|
|
2902
|
-
|
|
2903
|
-
|
|
3210
|
+
if (isTxt) {
|
|
3211
|
+
zoomLevel = Math.max(0.1, zoomLevel - 0.1);
|
|
3212
|
+
} else {
|
|
3213
|
+
fontSize = Math.max(8, fontSize - 2);
|
|
3214
|
+
}
|
|
3215
|
+
updateTransform();
|
|
2904
3216
|
},
|
|
2905
|
-
getZoom: () => fontSize / 13,
|
|
3217
|
+
getZoom: () => isTxt ? zoomLevel : fontSize / 13,
|
|
2906
3218
|
setZoom: (level) => {
|
|
2907
|
-
|
|
2908
|
-
|
|
3219
|
+
if (isTxt) {
|
|
3220
|
+
zoomLevel = level;
|
|
3221
|
+
} else {
|
|
3222
|
+
fontSize = Math.round(13 * level);
|
|
3223
|
+
}
|
|
3224
|
+
updateTransform();
|
|
3225
|
+
},
|
|
3226
|
+
fitToPage: () => {
|
|
3227
|
+
fontSize = 13;
|
|
3228
|
+
rotation = 0;
|
|
3229
|
+
zoomLevel = 1;
|
|
3230
|
+
updateTransform();
|
|
3231
|
+
},
|
|
3232
|
+
rotateCW: () => {
|
|
3233
|
+
rotation = (rotation + 90) % 360;
|
|
3234
|
+
updateTransform();
|
|
3235
|
+
},
|
|
3236
|
+
rotateCCW: () => {
|
|
3237
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
3238
|
+
updateTransform();
|
|
2909
3239
|
},
|
|
2910
3240
|
download: () => {
|
|
2911
3241
|
const mimeType = ctx.metadata.mimeType || "text/plain";
|
|
@@ -3204,7 +3534,7 @@ var MarkdownPlugin = class {
|
|
|
3204
3534
|
gfm: true,
|
|
3205
3535
|
breaks: true
|
|
3206
3536
|
});
|
|
3207
|
-
const cleanHtml =
|
|
3537
|
+
const cleanHtml = DOMPurify6.sanitize(rawHtml, {
|
|
3208
3538
|
USE_PROFILES: { html: true }
|
|
3209
3539
|
});
|
|
3210
3540
|
const wrapper = document.createElement("div");
|
|
@@ -3418,6 +3748,14 @@ var PptxPlugin = class {
|
|
|
3418
3748
|
group: "zoom",
|
|
3419
3749
|
execute: () => instance.fitToPage?.()
|
|
3420
3750
|
},
|
|
3751
|
+
{
|
|
3752
|
+
id: "rotate-cw",
|
|
3753
|
+
icon: "rotate-cw",
|
|
3754
|
+
label: "Rotate",
|
|
3755
|
+
type: "button",
|
|
3756
|
+
group: "view",
|
|
3757
|
+
execute: () => instance.rotateCW?.()
|
|
3758
|
+
},
|
|
3421
3759
|
{
|
|
3422
3760
|
id: "download",
|
|
3423
3761
|
icon: "download",
|
|
@@ -3442,6 +3780,7 @@ var PptxPlugin = class {
|
|
|
3442
3780
|
const slideCount = renderer.slidePaths?.length || 1;
|
|
3443
3781
|
let currentSlide = 1;
|
|
3444
3782
|
let scale = 1;
|
|
3783
|
+
let rotation = 0;
|
|
3445
3784
|
const wrapper = document.createElement("div");
|
|
3446
3785
|
wrapper.className = "fp-pptx-wrapper";
|
|
3447
3786
|
wrapper.style.cssText = `
|
|
@@ -3464,6 +3803,8 @@ var PptxPlugin = class {
|
|
|
3464
3803
|
background: #ffffff;
|
|
3465
3804
|
transform-origin: top center;
|
|
3466
3805
|
transition: transform 0.2s ease;
|
|
3806
|
+
max-width: calc(100% - 32px);
|
|
3807
|
+
max-height: calc(100% - 48px);
|
|
3467
3808
|
`;
|
|
3468
3809
|
const canvas = document.createElement("canvas");
|
|
3469
3810
|
slideContainer.appendChild(canvas);
|
|
@@ -3471,10 +3812,22 @@ var PptxPlugin = class {
|
|
|
3471
3812
|
ctx.container.innerHTML = "";
|
|
3472
3813
|
ctx.container.style.overflow = "auto";
|
|
3473
3814
|
ctx.container.appendChild(wrapper);
|
|
3815
|
+
const calculateFitScale = () => {
|
|
3816
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
3817
|
+
const availH = Math.max(200, ctx.container.clientHeight - 72);
|
|
3818
|
+
const cW = canvas.offsetWidth || 1280;
|
|
3819
|
+
const cH = canvas.offsetHeight || 720;
|
|
3820
|
+
return Math.min(1, Math.min(availW / cW, availH / cH));
|
|
3821
|
+
};
|
|
3822
|
+
const applyTransform = () => {
|
|
3823
|
+
slideContainer.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
3824
|
+
};
|
|
3474
3825
|
const renderCurrentSlide = async () => {
|
|
3475
3826
|
try {
|
|
3476
3827
|
await renderer.renderSlide(currentSlide - 1, canvas, 1280);
|
|
3477
3828
|
ctx.emit("page-change", { page: currentSlide, totalPages: slideCount });
|
|
3829
|
+
scale = calculateFitScale();
|
|
3830
|
+
applyTransform();
|
|
3478
3831
|
} catch (err) {
|
|
3479
3832
|
console.error("[PptxPlugin] Failed to render slide:", err);
|
|
3480
3833
|
}
|
|
@@ -3497,21 +3850,30 @@ var PptxPlugin = class {
|
|
|
3497
3850
|
getPageCount: () => slideCount,
|
|
3498
3851
|
getCurrentPage: () => currentSlide,
|
|
3499
3852
|
zoomIn: () => {
|
|
3500
|
-
scale += 0.
|
|
3501
|
-
|
|
3853
|
+
scale += 0.15;
|
|
3854
|
+
applyTransform();
|
|
3502
3855
|
},
|
|
3503
3856
|
zoomOut: () => {
|
|
3504
|
-
scale = Math.max(0.2, scale - 0.
|
|
3505
|
-
|
|
3857
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
3858
|
+
applyTransform();
|
|
3506
3859
|
},
|
|
3507
3860
|
getZoom: () => scale,
|
|
3508
3861
|
setZoom: (level) => {
|
|
3509
3862
|
scale = level;
|
|
3510
|
-
|
|
3863
|
+
applyTransform();
|
|
3511
3864
|
},
|
|
3512
3865
|
fitToPage: () => {
|
|
3513
|
-
scale =
|
|
3514
|
-
|
|
3866
|
+
scale = calculateFitScale();
|
|
3867
|
+
rotation = 0;
|
|
3868
|
+
applyTransform();
|
|
3869
|
+
},
|
|
3870
|
+
rotateCW: () => {
|
|
3871
|
+
rotation = (rotation + 90) % 360;
|
|
3872
|
+
applyTransform();
|
|
3873
|
+
},
|
|
3874
|
+
rotateCCW: () => {
|
|
3875
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
3876
|
+
applyTransform();
|
|
3515
3877
|
},
|
|
3516
3878
|
getThumbnails: () => {
|
|
3517
3879
|
const list = [];
|
|
@@ -3792,6 +4154,14 @@ var RtfPlugin = class {
|
|
|
3792
4154
|
group: "zoom",
|
|
3793
4155
|
execute: () => instance.fitToPage?.()
|
|
3794
4156
|
},
|
|
4157
|
+
{
|
|
4158
|
+
id: "rotate-cw",
|
|
4159
|
+
icon: "rotate-cw",
|
|
4160
|
+
label: "Rotate",
|
|
4161
|
+
type: "button",
|
|
4162
|
+
group: "view",
|
|
4163
|
+
execute: () => instance.rotateCW?.()
|
|
4164
|
+
},
|
|
3795
4165
|
{
|
|
3796
4166
|
id: "download",
|
|
3797
4167
|
icon: "download",
|
|
@@ -3800,6 +4170,14 @@ var RtfPlugin = class {
|
|
|
3800
4170
|
group: "actions",
|
|
3801
4171
|
execute: () => instance.download?.()
|
|
3802
4172
|
},
|
|
4173
|
+
{
|
|
4174
|
+
id: "copy",
|
|
4175
|
+
icon: "copy",
|
|
4176
|
+
label: "Copy Text",
|
|
4177
|
+
type: "button",
|
|
4178
|
+
group: "actions",
|
|
4179
|
+
execute: () => instance.copy?.()
|
|
4180
|
+
},
|
|
3803
4181
|
{
|
|
3804
4182
|
id: "print",
|
|
3805
4183
|
icon: "print",
|
|
@@ -3828,7 +4206,24 @@ var RtfPlugin = class {
|
|
|
3828
4206
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
3829
4207
|
ctx.container.appendChild(wrapper);
|
|
3830
4208
|
let scale = 1;
|
|
4209
|
+
let rotation = 0;
|
|
3831
4210
|
let pageElements = [];
|
|
4211
|
+
const calculateFitScale = () => {
|
|
4212
|
+
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4213
|
+
const elW = activeEl.offsetWidth || 850;
|
|
4214
|
+
const elH = activeEl.offsetHeight || 1e3;
|
|
4215
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
4216
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
4217
|
+
return Math.min(1.1, Math.min(availW / elW, availH / elH));
|
|
4218
|
+
};
|
|
4219
|
+
const applyTransform = () => {
|
|
4220
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4221
|
+
wrapper.style.transformOrigin = "top center";
|
|
4222
|
+
};
|
|
4223
|
+
setTimeout(() => {
|
|
4224
|
+
scale = calculateFitScale();
|
|
4225
|
+
applyTransform();
|
|
4226
|
+
}, 60);
|
|
3832
4227
|
try {
|
|
3833
4228
|
if (typeof RTFJS.loggingEnabled === "function") {
|
|
3834
4229
|
RTFJS.loggingEnabled(false);
|
|
@@ -3844,14 +4239,31 @@ var RtfPlugin = class {
|
|
|
3844
4239
|
} catch (err) {
|
|
3845
4240
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
3846
4241
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
3847
|
-
const
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
4242
|
+
const rawPages = text.split(/\\page\b/).map((segment) => {
|
|
4243
|
+
return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
|
|
4244
|
+
}).filter((p) => p.length > 0);
|
|
4245
|
+
const pages = rawPages.length > 0 ? rawPages : [text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim()];
|
|
4246
|
+
for (let i = 0; i < pages.length; i++) {
|
|
4247
|
+
const pageCard = document.createElement("div");
|
|
4248
|
+
pageCard.className = "fp-rtf-page-card";
|
|
4249
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
4250
|
+
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4251
|
+
pageCard.style.borderRadius = "4px";
|
|
4252
|
+
pageCard.style.padding = "72px 56px";
|
|
4253
|
+
pageCard.style.width = "816px";
|
|
4254
|
+
pageCard.style.minHeight = "1056px";
|
|
4255
|
+
pageCard.style.maxWidth = "100%";
|
|
4256
|
+
pageCard.style.boxSizing = "border-box";
|
|
4257
|
+
pageCard.style.fontFamily = "serif";
|
|
4258
|
+
pageCard.style.fontSize = "12pt";
|
|
4259
|
+
pageCard.style.lineHeight = "1.6";
|
|
4260
|
+
pageCard.style.color = "#1e293b";
|
|
4261
|
+
pageCard.style.whiteSpace = "pre-wrap";
|
|
4262
|
+
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4263
|
+
pageCard.textContent = pages[i];
|
|
4264
|
+
wrapper.appendChild(pageCard);
|
|
4265
|
+
pageElements.push(pageCard);
|
|
4266
|
+
}
|
|
3855
4267
|
}
|
|
3856
4268
|
const totalPages = Math.max(1, pageElements.length);
|
|
3857
4269
|
let currentPage = 1;
|
|
@@ -3905,21 +4317,30 @@ var RtfPlugin = class {
|
|
|
3905
4317
|
getCurrentPage: () => currentPage,
|
|
3906
4318
|
goToPage: (page) => showPage(page),
|
|
3907
4319
|
zoomIn: () => {
|
|
3908
|
-
scale += 0.
|
|
3909
|
-
|
|
4320
|
+
scale += 0.15;
|
|
4321
|
+
applyTransform();
|
|
3910
4322
|
},
|
|
3911
4323
|
zoomOut: () => {
|
|
3912
|
-
scale = Math.max(0.2, scale - 0.
|
|
3913
|
-
|
|
4324
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
4325
|
+
applyTransform();
|
|
3914
4326
|
},
|
|
3915
4327
|
getZoom: () => scale,
|
|
3916
4328
|
setZoom: (level) => {
|
|
3917
4329
|
scale = level;
|
|
3918
|
-
|
|
4330
|
+
applyTransform();
|
|
3919
4331
|
},
|
|
3920
4332
|
fitToPage: () => {
|
|
3921
|
-
scale =
|
|
3922
|
-
|
|
4333
|
+
scale = calculateFitScale();
|
|
4334
|
+
rotation = 0;
|
|
4335
|
+
applyTransform();
|
|
4336
|
+
},
|
|
4337
|
+
rotateCW: () => {
|
|
4338
|
+
rotation = (rotation + 90) % 360;
|
|
4339
|
+
applyTransform();
|
|
4340
|
+
},
|
|
4341
|
+
rotateCCW: () => {
|
|
4342
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
4343
|
+
applyTransform();
|
|
3923
4344
|
},
|
|
3924
4345
|
download: () => {
|
|
3925
4346
|
const blob = new Blob([ctx.buffer], { type: "application/rtf" });
|
|
@@ -3930,6 +4351,10 @@ var RtfPlugin = class {
|
|
|
3930
4351
|
a.click();
|
|
3931
4352
|
URL.revokeObjectURL(url);
|
|
3932
4353
|
},
|
|
4354
|
+
copy: () => {
|
|
4355
|
+
const text = wrapper.textContent || "";
|
|
4356
|
+
navigator.clipboard?.writeText(text);
|
|
4357
|
+
},
|
|
3933
4358
|
print: () => {
|
|
3934
4359
|
window.print();
|
|
3935
4360
|
}
|
|
@@ -4004,7 +4429,7 @@ var HtmlPreviewPlugin = class {
|
|
|
4004
4429
|
}
|
|
4005
4430
|
async render(ctx) {
|
|
4006
4431
|
const rawHtml = new TextDecoder("utf-8").decode(ctx.buffer);
|
|
4007
|
-
const sanitized =
|
|
4432
|
+
const sanitized = DOMPurify6.sanitize(rawHtml, {
|
|
4008
4433
|
WHOLE_DOCUMENT: true,
|
|
4009
4434
|
ADD_TAGS: ["style", "link"],
|
|
4010
4435
|
ADD_ATTR: ["target", "rel"]
|
|
@@ -4147,11 +4572,19 @@ var OpenDocumentPlugin = class {
|
|
|
4147
4572
|
{
|
|
4148
4573
|
id: "fit-page",
|
|
4149
4574
|
icon: "fit-page",
|
|
4150
|
-
label: "Fit to Page",
|
|
4575
|
+
label: isPresentation ? "Fit to Slide" : "Fit to Page",
|
|
4151
4576
|
type: "button",
|
|
4152
4577
|
group: "zoom",
|
|
4153
4578
|
execute: () => instance.fitToPage?.()
|
|
4154
4579
|
},
|
|
4580
|
+
{
|
|
4581
|
+
id: "rotate-cw",
|
|
4582
|
+
icon: "rotate-cw",
|
|
4583
|
+
label: "Rotate",
|
|
4584
|
+
type: "button",
|
|
4585
|
+
group: "view",
|
|
4586
|
+
execute: () => instance.rotateCW?.()
|
|
4587
|
+
},
|
|
4155
4588
|
{
|
|
4156
4589
|
id: "download",
|
|
4157
4590
|
icon: "download",
|
|
@@ -4215,6 +4648,22 @@ var OpenDocumentPlugin = class {
|
|
|
4215
4648
|
container.appendChild(wrapper);
|
|
4216
4649
|
ctx.container.appendChild(container);
|
|
4217
4650
|
let scale = 1;
|
|
4651
|
+
let rotation = 0;
|
|
4652
|
+
const calculateFitScale = () => {
|
|
4653
|
+
const elW = wrapper.offsetWidth || 850;
|
|
4654
|
+
const elH = wrapper.offsetHeight || (isPresentation ? 540 : 1e3);
|
|
4655
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
4656
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
4657
|
+
return Math.min(1, Math.min(availW / elW, availH / elH));
|
|
4658
|
+
};
|
|
4659
|
+
const applyTransform = () => {
|
|
4660
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4661
|
+
wrapper.style.transformOrigin = "top center";
|
|
4662
|
+
};
|
|
4663
|
+
setTimeout(() => {
|
|
4664
|
+
scale = calculateFitScale();
|
|
4665
|
+
applyTransform();
|
|
4666
|
+
}, 60);
|
|
4218
4667
|
let currentPage = 1;
|
|
4219
4668
|
let totalPages = 1;
|
|
4220
4669
|
let slides = [];
|
|
@@ -4246,14 +4695,97 @@ var OpenDocumentPlugin = class {
|
|
|
4246
4695
|
wrapper.textContent = contentDoc.documentElement.textContent || "Formula content";
|
|
4247
4696
|
}
|
|
4248
4697
|
} else {
|
|
4249
|
-
wrapper.style.maxWidth = "
|
|
4250
|
-
wrapper.style.padding = "
|
|
4698
|
+
wrapper.style.maxWidth = "none";
|
|
4699
|
+
wrapper.style.padding = "0";
|
|
4251
4700
|
wrapper.style.minHeight = "100%";
|
|
4701
|
+
wrapper.style.backgroundColor = "transparent";
|
|
4702
|
+
wrapper.style.boxShadow = "none";
|
|
4703
|
+
wrapper.style.position = "relative";
|
|
4704
|
+
const dims = this.getPageDimensions(stylesDoc, contentDoc);
|
|
4252
4705
|
const bodyHtml = this.renderOdfBody(contentDoc, styleMap, imageUrls);
|
|
4253
|
-
|
|
4254
|
-
|
|
4706
|
+
const tempDiv = document.createElement("div");
|
|
4707
|
+
tempDiv.style.width = `${dims.width - dims.marginLeft - dims.marginRight}px`;
|
|
4708
|
+
tempDiv.style.position = "absolute";
|
|
4709
|
+
tempDiv.style.visibility = "hidden";
|
|
4710
|
+
tempDiv.innerHTML = DOMPurify6.sanitize(bodyHtml, {
|
|
4711
|
+
ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub", "hr"],
|
|
4255
4712
|
ADD_ATTR: ["style", "colspan", "rowspan"]
|
|
4256
4713
|
});
|
|
4714
|
+
document.body.appendChild(tempDiv);
|
|
4715
|
+
const contentHeight = dims.height - dims.marginTop - dims.marginBottom;
|
|
4716
|
+
const pageElements = [[]];
|
|
4717
|
+
let currentHeight = 0;
|
|
4718
|
+
let currentPageIdx = 0;
|
|
4719
|
+
Array.from(tempDiv.children).forEach((child) => {
|
|
4720
|
+
const el = child;
|
|
4721
|
+
const style = el.getAttribute("style") || "";
|
|
4722
|
+
const isBreakBefore = style.includes("page-break-before: always");
|
|
4723
|
+
const isBreakAfter = style.includes("page-break-after: always");
|
|
4724
|
+
const isSoftBreak = el.classList.contains("odf-page-break");
|
|
4725
|
+
if (isBreakBefore) {
|
|
4726
|
+
if (pageElements[currentPageIdx].length > 0) {
|
|
4727
|
+
currentPageIdx++;
|
|
4728
|
+
pageElements.push([]);
|
|
4729
|
+
currentHeight = 0;
|
|
4730
|
+
}
|
|
4731
|
+
}
|
|
4732
|
+
const h = el.offsetHeight || 0;
|
|
4733
|
+
if (currentHeight + h > contentHeight && pageElements[currentPageIdx].length > 0 && !isSoftBreak) {
|
|
4734
|
+
currentPageIdx++;
|
|
4735
|
+
pageElements.push([]);
|
|
4736
|
+
currentHeight = 0;
|
|
4737
|
+
}
|
|
4738
|
+
if (!isSoftBreak) {
|
|
4739
|
+
pageElements[currentPageIdx].push(el.cloneNode(true));
|
|
4740
|
+
currentHeight += h;
|
|
4741
|
+
}
|
|
4742
|
+
if (isBreakAfter || isSoftBreak) {
|
|
4743
|
+
currentPageIdx++;
|
|
4744
|
+
pageElements.push([]);
|
|
4745
|
+
currentHeight = 0;
|
|
4746
|
+
}
|
|
4747
|
+
});
|
|
4748
|
+
document.body.removeChild(tempDiv);
|
|
4749
|
+
if (pageElements.length > 1 && pageElements[pageElements.length - 1].length === 0) {
|
|
4750
|
+
pageElements.pop();
|
|
4751
|
+
}
|
|
4752
|
+
totalPages = Math.max(1, pageElements.length);
|
|
4753
|
+
pageElements.forEach((elements, idx) => {
|
|
4754
|
+
const page = document.createElement("div");
|
|
4755
|
+
page.className = `fp-odt-page fp-odt-page-${idx + 1}`;
|
|
4756
|
+
page.style.width = `${dims.width}px`;
|
|
4757
|
+
page.style.minHeight = `${dims.height}px`;
|
|
4758
|
+
page.style.padding = `${dims.marginTop}px ${dims.marginRight}px ${dims.marginBottom}px ${dims.marginLeft}px`;
|
|
4759
|
+
page.style.margin = "0 auto";
|
|
4760
|
+
page.style.backgroundColor = "#ffffff";
|
|
4761
|
+
page.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
|
|
4762
|
+
page.style.borderRadius = "4px";
|
|
4763
|
+
page.style.boxSizing = "border-box";
|
|
4764
|
+
page.style.display = idx === 0 ? "block" : "none";
|
|
4765
|
+
page.style.position = "absolute";
|
|
4766
|
+
page.style.top = "0";
|
|
4767
|
+
page.style.left = "50%";
|
|
4768
|
+
page.style.transform = "translateX(-50%)";
|
|
4769
|
+
elements.forEach((el) => page.appendChild(el));
|
|
4770
|
+
wrapper.appendChild(page);
|
|
4771
|
+
slides.push(page);
|
|
4772
|
+
});
|
|
4773
|
+
const pageIndicator = document.createElement("div");
|
|
4774
|
+
pageIndicator.className = "fp-odt-page-indicator";
|
|
4775
|
+
pageIndicator.style.position = "sticky";
|
|
4776
|
+
pageIndicator.style.bottom = "16px";
|
|
4777
|
+
pageIndicator.style.left = "50%";
|
|
4778
|
+
pageIndicator.style.transform = "translateX(-50%)";
|
|
4779
|
+
pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
|
4780
|
+
pageIndicator.style.color = "#fff";
|
|
4781
|
+
pageIndicator.style.padding = "6px 12px";
|
|
4782
|
+
pageIndicator.style.borderRadius = "16px";
|
|
4783
|
+
pageIndicator.style.fontSize = "12px";
|
|
4784
|
+
pageIndicator.style.zIndex = "100";
|
|
4785
|
+
pageIndicator.style.display = "inline-block";
|
|
4786
|
+
pageIndicator.style.width = "fit-content";
|
|
4787
|
+
pageIndicator.textContent = `Page 1 of ${totalPages}`;
|
|
4788
|
+
container.appendChild(pageIndicator);
|
|
4257
4789
|
}
|
|
4258
4790
|
const cleanup = () => {
|
|
4259
4791
|
imageUrls.forEach((url) => URL.revokeObjectURL(url));
|
|
@@ -4262,32 +4794,45 @@ var OpenDocumentPlugin = class {
|
|
|
4262
4794
|
};
|
|
4263
4795
|
ctx.signal.addEventListener("abort", cleanup);
|
|
4264
4796
|
const goToPage = (page) => {
|
|
4265
|
-
if (
|
|
4797
|
+
if (page < 1 || page > totalPages) return;
|
|
4266
4798
|
currentPage = page;
|
|
4267
4799
|
slides.forEach((s, idx) => {
|
|
4268
4800
|
s.style.display = idx === page - 1 ? "block" : "none";
|
|
4269
4801
|
});
|
|
4802
|
+
const indicator = container.querySelector(".fp-odt-page-indicator");
|
|
4803
|
+
if (indicator) {
|
|
4804
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4805
|
+
}
|
|
4270
4806
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4271
4807
|
};
|
|
4272
4808
|
return {
|
|
4273
4809
|
destroy: cleanup,
|
|
4274
4810
|
isPresentation,
|
|
4275
4811
|
zoomIn: () => {
|
|
4276
|
-
scale += 0.
|
|
4277
|
-
|
|
4812
|
+
scale += 0.15;
|
|
4813
|
+
applyTransform();
|
|
4278
4814
|
},
|
|
4279
4815
|
zoomOut: () => {
|
|
4280
|
-
scale = Math.max(0.2, scale - 0.
|
|
4281
|
-
|
|
4816
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
4817
|
+
applyTransform();
|
|
4282
4818
|
},
|
|
4283
4819
|
getZoom: () => scale,
|
|
4284
4820
|
setZoom: (level) => {
|
|
4285
4821
|
scale = level;
|
|
4286
|
-
|
|
4822
|
+
applyTransform();
|
|
4287
4823
|
},
|
|
4288
4824
|
fitToPage: () => {
|
|
4289
|
-
scale =
|
|
4290
|
-
|
|
4825
|
+
scale = calculateFitScale();
|
|
4826
|
+
rotation = 0;
|
|
4827
|
+
applyTransform();
|
|
4828
|
+
},
|
|
4829
|
+
rotateCW: () => {
|
|
4830
|
+
rotation = (rotation + 90) % 360;
|
|
4831
|
+
applyTransform();
|
|
4832
|
+
},
|
|
4833
|
+
rotateCCW: () => {
|
|
4834
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
4835
|
+
applyTransform();
|
|
4291
4836
|
},
|
|
4292
4837
|
goToPage,
|
|
4293
4838
|
getPageCount: () => totalPages,
|
|
@@ -4326,6 +4871,43 @@ var OpenDocumentPlugin = class {
|
|
|
4326
4871
|
}
|
|
4327
4872
|
};
|
|
4328
4873
|
}
|
|
4874
|
+
getPageDimensions(stylesDoc, contentDoc) {
|
|
4875
|
+
let width = 850;
|
|
4876
|
+
let height = 1123;
|
|
4877
|
+
let marginTop = 48;
|
|
4878
|
+
let marginBottom = 48;
|
|
4879
|
+
let marginLeft = 48;
|
|
4880
|
+
let marginRight = 48;
|
|
4881
|
+
const parseUnit = (val) => {
|
|
4882
|
+
if (!val) return null;
|
|
4883
|
+
if (val.endsWith("cm")) return parseFloat(val) * 37.8;
|
|
4884
|
+
if (val.endsWith("mm")) return parseFloat(val) * 3.78;
|
|
4885
|
+
if (val.endsWith("in")) return parseFloat(val) * 96;
|
|
4886
|
+
if (val.endsWith("pt")) return parseFloat(val) * 1.33;
|
|
4887
|
+
if (val.endsWith("px")) return parseFloat(val);
|
|
4888
|
+
return parseFloat(val);
|
|
4889
|
+
};
|
|
4890
|
+
const docs = [stylesDoc, contentDoc].filter(Boolean);
|
|
4891
|
+
for (const doc of docs) {
|
|
4892
|
+
const pageLayout = doc.querySelector("page-layout-properties, [page-width]");
|
|
4893
|
+
if (pageLayout) {
|
|
4894
|
+
const w = parseUnit(pageLayout.getAttribute("fo:page-width") || pageLayout.getAttribute("page-width"));
|
|
4895
|
+
const h = parseUnit(pageLayout.getAttribute("fo:page-height") || pageLayout.getAttribute("page-height"));
|
|
4896
|
+
const mt = parseUnit(pageLayout.getAttribute("fo:margin-top") || pageLayout.getAttribute("margin-top"));
|
|
4897
|
+
const mb = parseUnit(pageLayout.getAttribute("fo:margin-bottom") || pageLayout.getAttribute("margin-bottom"));
|
|
4898
|
+
const ml = parseUnit(pageLayout.getAttribute("fo:margin-left") || pageLayout.getAttribute("margin-left"));
|
|
4899
|
+
const mr = parseUnit(pageLayout.getAttribute("fo:margin-right") || pageLayout.getAttribute("margin-right"));
|
|
4900
|
+
if (w !== null) width = w;
|
|
4901
|
+
if (h !== null) height = h;
|
|
4902
|
+
if (mt !== null) marginTop = mt;
|
|
4903
|
+
if (mb !== null) marginBottom = mb;
|
|
4904
|
+
if (ml !== null) marginLeft = ml;
|
|
4905
|
+
if (mr !== null) marginRight = mr;
|
|
4906
|
+
break;
|
|
4907
|
+
}
|
|
4908
|
+
}
|
|
4909
|
+
return { width, height, marginTop, marginBottom, marginLeft, marginRight };
|
|
4910
|
+
}
|
|
4329
4911
|
extractStyles(stylesDoc, contentDoc) {
|
|
4330
4912
|
const map = /* @__PURE__ */ new Map();
|
|
4331
4913
|
const styleNodes = [];
|
|
@@ -4348,14 +4930,21 @@ var OpenDocumentPlugin = class {
|
|
|
4348
4930
|
if (color) css += `color: ${color}; `;
|
|
4349
4931
|
if (size) css += `font-size: ${size}; `;
|
|
4350
4932
|
}
|
|
4351
|
-
|
|
4933
|
+
let paraProp = node.querySelector("paragraph-properties, [text-align]");
|
|
4934
|
+
if (!paraProp) {
|
|
4935
|
+
paraProp = Array.from(node.children).find((c) => c.tagName.includes("paragraph-properties")) || null;
|
|
4936
|
+
}
|
|
4352
4937
|
if (paraProp) {
|
|
4353
4938
|
const align = paraProp.getAttribute("fo:text-align") || paraProp.getAttribute("text-align");
|
|
4354
4939
|
const mt = paraProp.getAttribute("fo:margin-top") || paraProp.getAttribute("margin-top");
|
|
4355
4940
|
const mb = paraProp.getAttribute("fo:margin-bottom") || paraProp.getAttribute("margin-bottom");
|
|
4941
|
+
const breakBefore = paraProp.getAttribute("fo:break-before") || paraProp.getAttribute("break-before");
|
|
4942
|
+
const breakAfter = paraProp.getAttribute("fo:break-after") || paraProp.getAttribute("break-after");
|
|
4356
4943
|
if (align) css += `text-align: ${align}; `;
|
|
4357
4944
|
if (mt) css += `margin-top: ${mt}; `;
|
|
4358
4945
|
if (mb) css += `margin-bottom: ${mb}; `;
|
|
4946
|
+
if (breakBefore === "page") css += "page-break-before: always; ";
|
|
4947
|
+
if (breakAfter === "page") css += "page-break-after: always; ";
|
|
4359
4948
|
}
|
|
4360
4949
|
if (css) map.set(name, css);
|
|
4361
4950
|
}
|
|
@@ -4440,6 +5029,8 @@ var OpenDocumentPlugin = class {
|
|
|
4440
5029
|
result += " ";
|
|
4441
5030
|
} else if (tag === "line-break") {
|
|
4442
5031
|
result += "<br/>";
|
|
5032
|
+
} else if (tag === "soft-page-break") {
|
|
5033
|
+
result += '<hr class="odf-page-break" style="page-break-after: always; border: none; margin: 0; padding: 0; height: 0;" />';
|
|
4443
5034
|
} else {
|
|
4444
5035
|
result += el.textContent || "";
|
|
4445
5036
|
}
|
|
@@ -4557,6 +5148,14 @@ var DocPlugin = class {
|
|
|
4557
5148
|
group: "zoom",
|
|
4558
5149
|
execute: () => instance.fitToPage?.()
|
|
4559
5150
|
},
|
|
5151
|
+
{
|
|
5152
|
+
id: "rotate-cw",
|
|
5153
|
+
icon: "rotate-cw",
|
|
5154
|
+
label: "Rotate",
|
|
5155
|
+
type: "button",
|
|
5156
|
+
group: "view",
|
|
5157
|
+
execute: () => instance.rotateCW?.()
|
|
5158
|
+
},
|
|
4560
5159
|
{
|
|
4561
5160
|
id: "copy",
|
|
4562
5161
|
icon: "copy",
|
|
@@ -4592,20 +5191,9 @@ var DocPlugin = class {
|
|
|
4592
5191
|
container.style.overflow = "auto";
|
|
4593
5192
|
container.style.padding = "32px 16px";
|
|
4594
5193
|
container.style.backgroundColor = "#f1f5f9";
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
wrapper.style.margin = "0 auto";
|
|
4599
|
-
wrapper.style.backgroundColor = "#ffffff";
|
|
4600
|
-
wrapper.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4601
|
-
wrapper.style.borderRadius = "4px";
|
|
4602
|
-
wrapper.style.padding = "56px 48px";
|
|
4603
|
-
wrapper.style.minHeight = "100%";
|
|
4604
|
-
wrapper.style.transformOrigin = "top center";
|
|
4605
|
-
wrapper.style.transition = "transform 0.2s ease";
|
|
4606
|
-
wrapper.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4607
|
-
wrapper.style.color = "#1e293b";
|
|
4608
|
-
container.appendChild(wrapper);
|
|
5194
|
+
container.style.display = "flex";
|
|
5195
|
+
container.style.justifyContent = "center";
|
|
5196
|
+
container.style.alignItems = "flex-start";
|
|
4609
5197
|
ctx.container.appendChild(container);
|
|
4610
5198
|
let scale = 1;
|
|
4611
5199
|
let extractedRawText = "";
|
|
@@ -4632,21 +5220,27 @@ var DocPlugin = class {
|
|
|
4632
5220
|
const rawPages = this.splitIntoPages(extractedRawText);
|
|
4633
5221
|
const totalPages = Math.max(1, rawPages.length);
|
|
4634
5222
|
let currentPage = 1;
|
|
4635
|
-
wrapper.innerHTML = "";
|
|
4636
5223
|
const pageCards = [];
|
|
4637
5224
|
for (let i = 0; i < totalPages; i++) {
|
|
4638
5225
|
const pageCard = document.createElement("div");
|
|
4639
5226
|
pageCard.className = "fp-doc-page-card";
|
|
5227
|
+
pageCard.style.width = "816px";
|
|
5228
|
+
pageCard.style.height = "1056px";
|
|
4640
5229
|
pageCard.style.backgroundColor = "#ffffff";
|
|
4641
5230
|
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4642
5231
|
pageCard.style.borderRadius = "4px";
|
|
4643
|
-
pageCard.style.padding = "
|
|
4644
|
-
pageCard.style.
|
|
5232
|
+
pageCard.style.padding = "96px 72px";
|
|
5233
|
+
pageCard.style.boxSizing = "border-box";
|
|
5234
|
+
pageCard.style.overflow = "hidden";
|
|
4645
5235
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
5236
|
+
pageCard.style.transformOrigin = "top center";
|
|
5237
|
+
pageCard.style.transition = "transform 0.2s ease";
|
|
5238
|
+
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
5239
|
+
pageCard.style.color = "#1e293b";
|
|
4646
5240
|
if (isFallback && i === 0) {
|
|
4647
5241
|
pageCard.innerHTML = `
|
|
4648
5242
|
<div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
|
|
4649
|
-
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${
|
|
5243
|
+
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify6.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
|
|
4650
5244
|
<span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
|
|
4651
5245
|
</div>
|
|
4652
5246
|
${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
|
|
@@ -4654,15 +5248,17 @@ var DocPlugin = class {
|
|
|
4654
5248
|
} else {
|
|
4655
5249
|
pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
|
|
4656
5250
|
}
|
|
4657
|
-
|
|
5251
|
+
container.appendChild(pageCard);
|
|
4658
5252
|
pageCards.push(pageCard);
|
|
4659
5253
|
}
|
|
4660
5254
|
let indicator = null;
|
|
4661
5255
|
if (totalPages > 1) {
|
|
4662
5256
|
indicator = document.createElement("div");
|
|
4663
5257
|
indicator.className = "fp-doc-page-indicator";
|
|
4664
|
-
indicator.style.position = "
|
|
5258
|
+
indicator.style.position = "fixed";
|
|
4665
5259
|
indicator.style.bottom = "16px";
|
|
5260
|
+
indicator.style.left = "50%";
|
|
5261
|
+
indicator.style.transform = "translateX(-50%)";
|
|
4666
5262
|
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4667
5263
|
indicator.style.backdropFilter = "blur(8px)";
|
|
4668
5264
|
indicator.style.color = "#f8fafc";
|
|
@@ -4676,17 +5272,25 @@ var DocPlugin = class {
|
|
|
4676
5272
|
indicator.style.userSelect = "none";
|
|
4677
5273
|
indicator.style.pointerEvents = "none";
|
|
4678
5274
|
indicator.style.textAlign = "center";
|
|
4679
|
-
indicator.style.width = "fit-content";
|
|
4680
|
-
indicator.style.margin = "16px auto 0";
|
|
4681
5275
|
container.appendChild(indicator);
|
|
4682
5276
|
}
|
|
5277
|
+
let rotation = 0;
|
|
5278
|
+
const applyTransform = () => {
|
|
5279
|
+
const activeCard = pageCards[currentPage - 1];
|
|
5280
|
+
if (activeCard) {
|
|
5281
|
+
activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5282
|
+
}
|
|
5283
|
+
};
|
|
4683
5284
|
const showPage = (pageNum) => {
|
|
4684
5285
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
card.style.display =
|
|
4688
|
-
|
|
4689
|
-
|
|
5286
|
+
pageCards.forEach((card, idx) => {
|
|
5287
|
+
if (idx + 1 === currentPage) {
|
|
5288
|
+
card.style.display = "block";
|
|
5289
|
+
card.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5290
|
+
} else {
|
|
5291
|
+
card.style.display = "none";
|
|
5292
|
+
}
|
|
5293
|
+
});
|
|
4690
5294
|
if (indicator) {
|
|
4691
5295
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4692
5296
|
}
|
|
@@ -4695,6 +5299,17 @@ var DocPlugin = class {
|
|
|
4695
5299
|
if (totalPages > 1) {
|
|
4696
5300
|
showPage(1);
|
|
4697
5301
|
}
|
|
5302
|
+
const calculateFitScale = () => {
|
|
5303
|
+
const elW = 816;
|
|
5304
|
+
const elH = 1056;
|
|
5305
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
5306
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
5307
|
+
return Math.min(1.1, Math.min(availW / elW, availH / elH));
|
|
5308
|
+
};
|
|
5309
|
+
setTimeout(() => {
|
|
5310
|
+
scale = calculateFitScale();
|
|
5311
|
+
applyTransform();
|
|
5312
|
+
}, 60);
|
|
4698
5313
|
const cleanup = () => {
|
|
4699
5314
|
indicator?.remove();
|
|
4700
5315
|
container.remove();
|
|
@@ -4707,21 +5322,30 @@ var DocPlugin = class {
|
|
|
4707
5322
|
getCurrentPage: () => currentPage,
|
|
4708
5323
|
goToPage: (page) => showPage(page),
|
|
4709
5324
|
zoomIn: () => {
|
|
4710
|
-
scale += 0.
|
|
4711
|
-
|
|
5325
|
+
scale += 0.15;
|
|
5326
|
+
applyTransform();
|
|
4712
5327
|
},
|
|
4713
5328
|
zoomOut: () => {
|
|
4714
|
-
scale = Math.max(0.2, scale - 0.
|
|
4715
|
-
|
|
5329
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
5330
|
+
applyTransform();
|
|
4716
5331
|
},
|
|
4717
5332
|
getZoom: () => scale,
|
|
4718
5333
|
setZoom: (level) => {
|
|
4719
5334
|
scale = level;
|
|
4720
|
-
|
|
5335
|
+
applyTransform();
|
|
4721
5336
|
},
|
|
4722
5337
|
fitToPage: () => {
|
|
4723
|
-
scale =
|
|
4724
|
-
|
|
5338
|
+
scale = calculateFitScale();
|
|
5339
|
+
rotation = 0;
|
|
5340
|
+
applyTransform();
|
|
5341
|
+
},
|
|
5342
|
+
rotateCW: () => {
|
|
5343
|
+
rotation = (rotation + 90) % 360;
|
|
5344
|
+
applyTransform();
|
|
5345
|
+
},
|
|
5346
|
+
rotateCCW: () => {
|
|
5347
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
5348
|
+
applyTransform();
|
|
4725
5349
|
},
|
|
4726
5350
|
copy: () => {
|
|
4727
5351
|
navigator.clipboard.writeText(extractedRawText);
|
|
@@ -4839,8 +5463,28 @@ var DocPlugin = class {
|
|
|
4839
5463
|
}
|
|
4840
5464
|
splitIntoPages(text) {
|
|
4841
5465
|
if (!text) return [""];
|
|
4842
|
-
const
|
|
4843
|
-
|
|
5466
|
+
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);
|
|
5467
|
+
if (explicitParts.length === 0) explicitParts.push(text);
|
|
5468
|
+
const maxLinesPerPage = 48;
|
|
5469
|
+
const finalPages = [];
|
|
5470
|
+
for (const part of explicitParts) {
|
|
5471
|
+
const lines = part.split(/\r?\n/);
|
|
5472
|
+
let currentLines = [];
|
|
5473
|
+
let count = 0;
|
|
5474
|
+
for (const line of lines) {
|
|
5475
|
+
currentLines.push(line);
|
|
5476
|
+
count++;
|
|
5477
|
+
if (count >= maxLinesPerPage) {
|
|
5478
|
+
finalPages.push(currentLines.join("\n"));
|
|
5479
|
+
currentLines = [];
|
|
5480
|
+
count = 0;
|
|
5481
|
+
}
|
|
5482
|
+
}
|
|
5483
|
+
if (currentLines.length > 0) {
|
|
5484
|
+
finalPages.push(currentLines.join("\n"));
|
|
5485
|
+
}
|
|
5486
|
+
}
|
|
5487
|
+
return finalPages.length > 0 ? finalPages : [text];
|
|
4844
5488
|
}
|
|
4845
5489
|
/**
|
|
4846
5490
|
* Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
|
|
@@ -4849,17 +5493,65 @@ var DocPlugin = class {
|
|
|
4849
5493
|
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
|
|
4850
5494
|
let html = "";
|
|
4851
5495
|
let inList = false;
|
|
4852
|
-
|
|
4853
|
-
|
|
5496
|
+
let tableLines = [];
|
|
5497
|
+
const flushTable = () => {
|
|
5498
|
+
if (tableLines.length > 0) {
|
|
5499
|
+
html += '<table style="width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 12px;">';
|
|
5500
|
+
for (const tLine of tableLines) {
|
|
5501
|
+
html += "<tr>";
|
|
5502
|
+
const cols = tLine.split(" ");
|
|
5503
|
+
for (const col of cols) {
|
|
5504
|
+
html += `<td style="border: 1px solid #cbd5e1; padding: 6px 8px;">${DOMPurify6.sanitize(col.trim())}</td>`;
|
|
5505
|
+
}
|
|
5506
|
+
html += "</tr>";
|
|
5507
|
+
}
|
|
5508
|
+
html += "</table>";
|
|
5509
|
+
tableLines = [];
|
|
5510
|
+
}
|
|
5511
|
+
};
|
|
5512
|
+
let i = 0;
|
|
5513
|
+
while (i < lines.length) {
|
|
5514
|
+
let line = lines[i];
|
|
5515
|
+
let tabCount = (line.match(/\t/g) || []).length;
|
|
5516
|
+
if (tabCount > 0) {
|
|
5517
|
+
let consecutiveTableLines = 1;
|
|
5518
|
+
let j = i + 1;
|
|
5519
|
+
while (j < lines.length) {
|
|
5520
|
+
const nextTabCount = (lines[j].match(/\t/g) || []).length;
|
|
5521
|
+
if (nextTabCount === tabCount) {
|
|
5522
|
+
consecutiveTableLines++;
|
|
5523
|
+
j++;
|
|
5524
|
+
} else {
|
|
5525
|
+
break;
|
|
5526
|
+
}
|
|
5527
|
+
}
|
|
5528
|
+
if (consecutiveTableLines >= 3) {
|
|
5529
|
+
if (inList) {
|
|
5530
|
+
html += "</ul>";
|
|
5531
|
+
inList = false;
|
|
5532
|
+
}
|
|
5533
|
+
tableLines = lines.slice(i, j);
|
|
5534
|
+
flushTable();
|
|
5535
|
+
i = j;
|
|
5536
|
+
continue;
|
|
5537
|
+
}
|
|
5538
|
+
}
|
|
5539
|
+
line = line.trim();
|
|
4854
5540
|
if (!line) {
|
|
4855
5541
|
if (inList) {
|
|
4856
5542
|
html += "</ul>";
|
|
4857
5543
|
inList = false;
|
|
4858
5544
|
}
|
|
5545
|
+
html += '<div style="height: 1.15em;"></div>';
|
|
5546
|
+
i++;
|
|
4859
5547
|
continue;
|
|
4860
5548
|
}
|
|
4861
|
-
if (/^[\x00-\x1F\x7F-\x9F]+$/.test(line))
|
|
4862
|
-
|
|
5549
|
+
if (/^[\x00-\x1F\x7F-\x9F]+$/.test(line)) {
|
|
5550
|
+
i++;
|
|
5551
|
+
continue;
|
|
5552
|
+
}
|
|
5553
|
+
if ((line.includes("Normal.dot") || line.includes("Microsoft Word") || line.includes("Times New Roman")) && line.length < 30) {
|
|
5554
|
+
i++;
|
|
4863
5555
|
continue;
|
|
4864
5556
|
}
|
|
4865
5557
|
if (line.length < 60 && !line.endsWith(".") && (/^[A-Z0-9\s:_-]+$/.test(line) || line.startsWith("#"))) {
|
|
@@ -4867,24 +5559,26 @@ var DocPlugin = class {
|
|
|
4867
5559
|
html += "</ul>";
|
|
4868
5560
|
inList = false;
|
|
4869
5561
|
}
|
|
4870
|
-
html += `<h2 style="font-size:
|
|
5562
|
+
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>`;
|
|
4871
5563
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
4872
5564
|
if (!inList) {
|
|
4873
5565
|
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
4874
5566
|
inList = true;
|
|
4875
5567
|
}
|
|
4876
5568
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
4877
|
-
html += `<li style="margin: 4px 0; line-height: 1.
|
|
5569
|
+
html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6.sanitize(bulletText)}</li>`;
|
|
4878
5570
|
} else {
|
|
4879
5571
|
if (inList) {
|
|
4880
5572
|
html += "</ul>";
|
|
4881
5573
|
inList = false;
|
|
4882
5574
|
}
|
|
4883
|
-
html += `<p style="line-height: 1.
|
|
5575
|
+
html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6.sanitize(line)}</p>`;
|
|
4884
5576
|
}
|
|
5577
|
+
i++;
|
|
4885
5578
|
}
|
|
4886
5579
|
if (inList) html += "</ul>";
|
|
4887
|
-
|
|
5580
|
+
flushTable();
|
|
5581
|
+
return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify6.sanitize(filename)})</p>`;
|
|
4888
5582
|
}
|
|
4889
5583
|
};
|
|
4890
5584
|
function docPlugin() {
|
|
@@ -4961,6 +5655,14 @@ var PptPlugin = class {
|
|
|
4961
5655
|
group: "zoom",
|
|
4962
5656
|
execute: () => instance.fitToPage?.()
|
|
4963
5657
|
},
|
|
5658
|
+
{
|
|
5659
|
+
id: "rotate-cw",
|
|
5660
|
+
icon: "rotate-cw",
|
|
5661
|
+
label: "Rotate",
|
|
5662
|
+
type: "button",
|
|
5663
|
+
group: "view",
|
|
5664
|
+
execute: () => instance.rotateCW?.()
|
|
5665
|
+
},
|
|
4964
5666
|
{
|
|
4965
5667
|
id: "download",
|
|
4966
5668
|
icon: "download",
|
|
@@ -4994,22 +5696,36 @@ var PptPlugin = class {
|
|
|
4994
5696
|
const slideCard = document.createElement("div");
|
|
4995
5697
|
slideCard.className = "fp-ppt-slide-card";
|
|
4996
5698
|
slideCard.style.width = "960px";
|
|
4997
|
-
slideCard.style.maxWidth = "
|
|
5699
|
+
slideCard.style.maxWidth = "calc(100% - 32px)";
|
|
5700
|
+
slideCard.style.maxHeight = "calc(100% - 48px)";
|
|
4998
5701
|
slideCard.style.aspectRatio = "16 / 9";
|
|
4999
5702
|
slideCard.style.backgroundColor = "#ffffff";
|
|
5000
5703
|
slideCard.style.boxShadow = "0 12px 40px rgba(0,0,0,0.35)";
|
|
5001
5704
|
slideCard.style.borderRadius = "8px";
|
|
5002
5705
|
slideCard.style.boxSizing = "border-box";
|
|
5003
5706
|
slideCard.style.position = "relative";
|
|
5004
|
-
slideCard.style.overflow = "hidden";
|
|
5005
|
-
slideCard.style.transformOrigin = "center center";
|
|
5006
5707
|
slideCard.style.transition = "transform 0.2s ease";
|
|
5708
|
+
slideCard.style.transformOrigin = "center center";
|
|
5709
|
+
slideCard.style.flexShrink = "0";
|
|
5007
5710
|
container.appendChild(slideCard);
|
|
5008
5711
|
ctx.container.appendChild(container);
|
|
5009
5712
|
let scale = 1;
|
|
5713
|
+
let rotation = 0;
|
|
5010
5714
|
let currentSlide = 1;
|
|
5011
5715
|
let slides = [];
|
|
5012
5716
|
const createdBlobUrls = [];
|
|
5717
|
+
const calculateFitScale = () => {
|
|
5718
|
+
const availW = Math.max(200, container.clientWidth - 48);
|
|
5719
|
+
const availH = Math.max(200, container.clientHeight - 72);
|
|
5720
|
+
return Math.min(1, Math.min(availW / 960, availH / 540));
|
|
5721
|
+
};
|
|
5722
|
+
const applyTransform = () => {
|
|
5723
|
+
slideCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5724
|
+
};
|
|
5725
|
+
setTimeout(() => {
|
|
5726
|
+
scale = calculateFitScale();
|
|
5727
|
+
applyTransform();
|
|
5728
|
+
}, 60);
|
|
5013
5729
|
try {
|
|
5014
5730
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
5015
5731
|
const pptStream = cfbf.readStream("PowerPoint Document");
|
|
@@ -5040,7 +5756,7 @@ var PptPlugin = class {
|
|
|
5040
5756
|
if (s.pictureUrl) {
|
|
5041
5757
|
contentHtml = `
|
|
5042
5758
|
<div style="flex: 1; display: flex; justify-content: center; align-items: center; padding: 12px; overflow: hidden;">
|
|
5043
|
-
<img src="${s.pictureUrl}" alt="${
|
|
5759
|
+
<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;" />
|
|
5044
5760
|
</div>
|
|
5045
5761
|
`;
|
|
5046
5762
|
} else if (s.tableColumns.length > 0) {
|
|
@@ -5050,7 +5766,7 @@ var PptPlugin = class {
|
|
|
5050
5766
|
<table style="width: 100%; border-collapse: collapse; border: 1px solid #cbd5e1; border-radius: 6px; overflow: hidden; background: #ffffff;">
|
|
5051
5767
|
<thead>
|
|
5052
5768
|
<tr style="background: #e2e8f0; color: #1e293b; font-weight: 600; font-size: 14px;">
|
|
5053
|
-
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${
|
|
5769
|
+
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify6.sanitize(c)}</th>`).join("")}
|
|
5054
5770
|
</tr>
|
|
5055
5771
|
</thead>
|
|
5056
5772
|
<tbody>
|
|
@@ -5066,7 +5782,7 @@ var PptPlugin = class {
|
|
|
5066
5782
|
} else {
|
|
5067
5783
|
const pTags = s.paragraphs.map((p) => {
|
|
5068
5784
|
const lines = p.split(/[\r\n]+/).map((l) => l.trim()).filter(Boolean);
|
|
5069
|
-
return lines.map((l) => `<p style="margin: 0 0 14px; font-size: 14px; line-height: 1.65; color: #334155; text-align: justify;">${
|
|
5785
|
+
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("");
|
|
5070
5786
|
}).join("");
|
|
5071
5787
|
contentHtml = `
|
|
5072
5788
|
<div style="flex: 1; overflow: auto; padding: 4px 8px; display: flex; flex-direction: column; justify-content: flex-start;">
|
|
@@ -5079,11 +5795,11 @@ var PptPlugin = class {
|
|
|
5079
5795
|
<!-- Header Banner matching PowerPoint design -->
|
|
5080
5796
|
<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;">
|
|
5081
5797
|
<h1 style="margin: 0; font-size: 26px; font-weight: 700; color: #1e293b; letter-spacing: -0.3px;">
|
|
5082
|
-
${
|
|
5798
|
+
${DOMPurify6.sanitize(s.title)}
|
|
5083
5799
|
</h1>
|
|
5084
5800
|
${s.subtitle ? `
|
|
5085
5801
|
<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);">
|
|
5086
|
-
${
|
|
5802
|
+
${DOMPurify6.sanitize(s.subtitle)}
|
|
5087
5803
|
</span>
|
|
5088
5804
|
` : `
|
|
5089
5805
|
<span style="font-size: 12px; color: #365314; font-weight: 600;">
|
|
@@ -5110,21 +5826,30 @@ var PptPlugin = class {
|
|
|
5110
5826
|
return {
|
|
5111
5827
|
destroy: cleanup,
|
|
5112
5828
|
zoomIn: () => {
|
|
5113
|
-
scale += 0.
|
|
5114
|
-
|
|
5829
|
+
scale += 0.15;
|
|
5830
|
+
applyTransform();
|
|
5115
5831
|
},
|
|
5116
5832
|
zoomOut: () => {
|
|
5117
|
-
scale = Math.max(0.
|
|
5118
|
-
|
|
5833
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
5834
|
+
applyTransform();
|
|
5119
5835
|
},
|
|
5120
5836
|
getZoom: () => scale,
|
|
5121
5837
|
setZoom: (level) => {
|
|
5122
5838
|
scale = level;
|
|
5123
|
-
|
|
5839
|
+
applyTransform();
|
|
5124
5840
|
},
|
|
5125
5841
|
fitToPage: () => {
|
|
5126
|
-
scale =
|
|
5127
|
-
|
|
5842
|
+
scale = calculateFitScale();
|
|
5843
|
+
rotation = 0;
|
|
5844
|
+
applyTransform();
|
|
5845
|
+
},
|
|
5846
|
+
rotateCW: () => {
|
|
5847
|
+
rotation = (rotation + 90) % 360;
|
|
5848
|
+
applyTransform();
|
|
5849
|
+
},
|
|
5850
|
+
rotateCCW: () => {
|
|
5851
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
5852
|
+
applyTransform();
|
|
5128
5853
|
},
|
|
5129
5854
|
goToPage: (page) => {
|
|
5130
5855
|
if (page >= 1 && page <= totalSlides) {
|