@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/angular.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Component, ChangeDetectionStrategy, Input, Output, ViewChild, EventEmitter as EventEmitter$1 } from '@angular/core';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
|
-
import
|
|
3
|
+
import DOMPurify6 from 'dompurify';
|
|
4
4
|
import * as pdfjsLib from 'pdfjs-dist';
|
|
5
5
|
import * as docx from 'docx-preview';
|
|
6
6
|
import { unzipSync, strFromU8, unzip } from 'fflate';
|
|
@@ -405,7 +405,7 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
405
405
|
if (magicMime === "application/zip") {
|
|
406
406
|
const ooxmlMime = detectOoxmlType(buffer);
|
|
407
407
|
if (ooxmlMime && ooxmlMime !== "application/zip") {
|
|
408
|
-
metadata.mimeType = ooxmlMime;
|
|
408
|
+
metadata.mimeType = metadata.mimeType ?? ooxmlMime;
|
|
409
409
|
if (ooxmlMime.includes("wordprocessing")) metadata.extension = metadata.extension ?? ".docx";
|
|
410
410
|
else if (ooxmlMime.includes("spreadsheet")) metadata.extension = metadata.extension ?? ".xlsx";
|
|
411
411
|
else if (ooxmlMime.includes("presentation")) metadata.extension = metadata.extension ?? ".pptx";
|
|
@@ -434,7 +434,7 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
434
434
|
return { buffer, metadata };
|
|
435
435
|
}
|
|
436
436
|
function sanitizeSVG(svg) {
|
|
437
|
-
return
|
|
437
|
+
return DOMPurify6.sanitize(svg, {
|
|
438
438
|
USE_PROFILES: { svg: true, svgFilters: true }
|
|
439
439
|
});
|
|
440
440
|
}
|
|
@@ -753,6 +753,8 @@ var FilePreviewViewer = class {
|
|
|
753
753
|
keyHandler = null;
|
|
754
754
|
currentContainer = null;
|
|
755
755
|
currentOptions = {};
|
|
756
|
+
resizeObserver = null;
|
|
757
|
+
fullscreenHandler = null;
|
|
756
758
|
/**
|
|
757
759
|
* Register a preview plugin.
|
|
758
760
|
*/
|
|
@@ -825,12 +827,31 @@ var FilePreviewViewer = class {
|
|
|
825
827
|
label: "Toggle Fullscreen",
|
|
826
828
|
type: "button",
|
|
827
829
|
group: "view",
|
|
828
|
-
execute: () => {
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
830
|
+
execute: async () => {
|
|
831
|
+
try {
|
|
832
|
+
const isNativeFs = !!document.fullscreenElement;
|
|
833
|
+
const isCssFs = this.wrapperEl?.classList.contains("fp-fullscreen-active");
|
|
834
|
+
if (!isNativeFs && !isCssFs) {
|
|
835
|
+
if (this.wrapperEl?.requestFullscreen) {
|
|
836
|
+
await this.wrapperEl.requestFullscreen().catch(() => {
|
|
837
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
838
|
+
});
|
|
839
|
+
} else {
|
|
840
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
841
|
+
}
|
|
842
|
+
} else {
|
|
843
|
+
if (document.fullscreenElement) {
|
|
844
|
+
await document.exitFullscreen().catch(() => {
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
848
|
+
}
|
|
849
|
+
} catch {
|
|
850
|
+
this.wrapperEl?.classList.toggle("fp-fullscreen-active");
|
|
833
851
|
}
|
|
852
|
+
setTimeout(() => {
|
|
853
|
+
this.activeInstance?.fitToPage?.();
|
|
854
|
+
}, 120);
|
|
834
855
|
}
|
|
835
856
|
});
|
|
836
857
|
}
|
|
@@ -880,6 +901,15 @@ var FilePreviewViewer = class {
|
|
|
880
901
|
window.removeEventListener("keydown", this.keyHandler);
|
|
881
902
|
this.keyHandler = null;
|
|
882
903
|
}
|
|
904
|
+
if (this.resizeObserver) {
|
|
905
|
+
this.resizeObserver.disconnect();
|
|
906
|
+
this.resizeObserver = null;
|
|
907
|
+
}
|
|
908
|
+
if (this.fullscreenHandler) {
|
|
909
|
+
document.removeEventListener("fullscreenchange", this.fullscreenHandler);
|
|
910
|
+
document.removeEventListener("webkitfullscreenchange", this.fullscreenHandler);
|
|
911
|
+
this.fullscreenHandler = null;
|
|
912
|
+
}
|
|
883
913
|
this.abort();
|
|
884
914
|
this.destroyInstance();
|
|
885
915
|
this.toolbar?.destroy();
|
|
@@ -959,6 +989,25 @@ var FilePreviewViewer = class {
|
|
|
959
989
|
this.thumbnailPanel = new ThumbnailPanel(thumbnailEl);
|
|
960
990
|
this.setupKeyboardShortcuts();
|
|
961
991
|
this.setupDragAndDrop(container, options);
|
|
992
|
+
this.setupResizeAndFullscreenListeners();
|
|
993
|
+
}
|
|
994
|
+
setupResizeAndFullscreenListeners() {
|
|
995
|
+
if (this.fullscreenHandler) return;
|
|
996
|
+
this.fullscreenHandler = () => {
|
|
997
|
+
setTimeout(() => {
|
|
998
|
+
this.activeInstance?.fitToPage?.();
|
|
999
|
+
}, 100);
|
|
1000
|
+
};
|
|
1001
|
+
document.addEventListener("fullscreenchange", this.fullscreenHandler);
|
|
1002
|
+
document.addEventListener("webkitfullscreenchange", this.fullscreenHandler);
|
|
1003
|
+
if (typeof ResizeObserver !== "undefined" && this.contentEl) {
|
|
1004
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
1005
|
+
if (this.activeInstance && (!this.activeInstance.getZoom || Math.abs((this.activeInstance.getZoom?.() ?? 1) - 1) < 0.05)) {
|
|
1006
|
+
this.activeInstance.fitToPage?.();
|
|
1007
|
+
}
|
|
1008
|
+
});
|
|
1009
|
+
this.resizeObserver.observe(this.contentEl);
|
|
1010
|
+
}
|
|
962
1011
|
}
|
|
963
1012
|
setupKeyboardShortcuts() {
|
|
964
1013
|
if (this.keyHandler) return;
|
|
@@ -1350,7 +1399,8 @@ var PdfPlugin = class {
|
|
|
1350
1399
|
container.style.display = "flex";
|
|
1351
1400
|
container.style.flexDirection = "column";
|
|
1352
1401
|
container.style.alignItems = "center";
|
|
1353
|
-
container.style.
|
|
1402
|
+
container.style.justifyContent = "flex-start";
|
|
1403
|
+
container.style.padding = "20px 16px";
|
|
1354
1404
|
container.style.backgroundColor = "#0f172a";
|
|
1355
1405
|
container.style.boxSizing = "border-box";
|
|
1356
1406
|
container.style.position = "relative";
|
|
@@ -1363,7 +1413,8 @@ var PdfPlugin = class {
|
|
|
1363
1413
|
pageCard.style.lineHeight = "0";
|
|
1364
1414
|
pageCard.style.transition = "transform 0.15s ease";
|
|
1365
1415
|
pageCard.style.position = "relative";
|
|
1366
|
-
|
|
1416
|
+
pageCard.style.flexShrink = "0";
|
|
1417
|
+
let canvas = document.createElement("canvas");
|
|
1367
1418
|
pageCard.appendChild(canvas);
|
|
1368
1419
|
container.appendChild(pageCard);
|
|
1369
1420
|
const indicator = document.createElement("div");
|
|
@@ -1405,14 +1456,22 @@ var PdfPlugin = class {
|
|
|
1405
1456
|
}
|
|
1406
1457
|
currentRenderTask = null;
|
|
1407
1458
|
}
|
|
1459
|
+
const newCanvas = document.createElement("canvas");
|
|
1460
|
+
pageCard.replaceChild(newCanvas, canvas);
|
|
1461
|
+
canvas = newCanvas;
|
|
1408
1462
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1409
1463
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1410
1464
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1411
1465
|
const page = await pdfDoc.getPage(currentPage);
|
|
1412
1466
|
const containerWidth = container.clientWidth || 900;
|
|
1467
|
+
const containerHeight = container.clientHeight || 700;
|
|
1413
1468
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1414
|
-
const
|
|
1415
|
-
const
|
|
1469
|
+
const availWidth = Math.max(100, containerWidth - 48);
|
|
1470
|
+
const availHeight = Math.max(100, containerHeight - 88);
|
|
1471
|
+
const scaleW = availWidth / unscaledVp.width;
|
|
1472
|
+
const scaleH = availHeight / unscaledVp.height;
|
|
1473
|
+
const fitScale = Math.min(scaleW, scaleH);
|
|
1474
|
+
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1416
1475
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
1417
1476
|
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
1418
1477
|
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
@@ -1437,7 +1496,19 @@ var PdfPlugin = class {
|
|
|
1437
1496
|
}
|
|
1438
1497
|
};
|
|
1439
1498
|
await renderPage(1);
|
|
1499
|
+
let resizeTimer = null;
|
|
1500
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
1501
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1502
|
+
resizeTimer = setTimeout(() => {
|
|
1503
|
+
if (Math.abs(zoomScale - 1) < 0.05) {
|
|
1504
|
+
renderPage(currentPage);
|
|
1505
|
+
}
|
|
1506
|
+
}, 150);
|
|
1507
|
+
});
|
|
1508
|
+
resizeObserver.observe(container);
|
|
1440
1509
|
const cleanup = () => {
|
|
1510
|
+
resizeObserver.disconnect();
|
|
1511
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1441
1512
|
if (currentRenderTask) {
|
|
1442
1513
|
try {
|
|
1443
1514
|
currentRenderTask.cancel();
|
|
@@ -1469,6 +1540,7 @@ var PdfPlugin = class {
|
|
|
1469
1540
|
},
|
|
1470
1541
|
fitToPage: () => {
|
|
1471
1542
|
zoomScale = 1;
|
|
1543
|
+
rotation = 0;
|
|
1472
1544
|
renderPage(currentPage);
|
|
1473
1545
|
},
|
|
1474
1546
|
rotateCW: () => {
|
|
@@ -1919,6 +1991,14 @@ var DocxPlugin = class {
|
|
|
1919
1991
|
group: "zoom",
|
|
1920
1992
|
execute: () => instance.fitToPage?.()
|
|
1921
1993
|
},
|
|
1994
|
+
{
|
|
1995
|
+
id: "rotate-cw",
|
|
1996
|
+
icon: "rotate-cw",
|
|
1997
|
+
label: "Rotate",
|
|
1998
|
+
type: "button",
|
|
1999
|
+
group: "view",
|
|
2000
|
+
execute: () => instance.rotateCW?.()
|
|
2001
|
+
},
|
|
1922
2002
|
{
|
|
1923
2003
|
id: "download",
|
|
1924
2004
|
icon: "download",
|
|
@@ -2055,6 +2135,26 @@ var DocxPlugin = class {
|
|
|
2055
2135
|
if (totalPages > 1) {
|
|
2056
2136
|
showPage(1);
|
|
2057
2137
|
}
|
|
2138
|
+
scale = 1;
|
|
2139
|
+
let rotation = 0;
|
|
2140
|
+
const calculateFitScale = () => {
|
|
2141
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.firstElementChild || wrapper;
|
|
2142
|
+
const elW = activeEl.offsetWidth || 816;
|
|
2143
|
+
const elH = activeEl.offsetHeight || 1056;
|
|
2144
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
2145
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
2146
|
+
const sW = availW / elW;
|
|
2147
|
+
const sH = availH / elH;
|
|
2148
|
+
return Math.min(1.1, Math.min(sW, sH));
|
|
2149
|
+
};
|
|
2150
|
+
const applyTransform = () => {
|
|
2151
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2152
|
+
wrapper.style.transformOrigin = "top center";
|
|
2153
|
+
};
|
|
2154
|
+
setTimeout(() => {
|
|
2155
|
+
scale = calculateFitScale();
|
|
2156
|
+
applyTransform();
|
|
2157
|
+
}, 60);
|
|
2058
2158
|
const cleanup = () => {
|
|
2059
2159
|
indicator?.remove();
|
|
2060
2160
|
for (const url of createdBlobUrls) {
|
|
@@ -2073,21 +2173,30 @@ var DocxPlugin = class {
|
|
|
2073
2173
|
showPage(page);
|
|
2074
2174
|
},
|
|
2075
2175
|
zoomIn: () => {
|
|
2076
|
-
scale += 0.
|
|
2077
|
-
|
|
2176
|
+
scale += 0.15;
|
|
2177
|
+
applyTransform();
|
|
2078
2178
|
},
|
|
2079
2179
|
zoomOut: () => {
|
|
2080
|
-
scale = Math.max(0.2, scale - 0.
|
|
2081
|
-
|
|
2180
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
2181
|
+
applyTransform();
|
|
2082
2182
|
},
|
|
2083
2183
|
getZoom: () => scale,
|
|
2084
2184
|
setZoom: (level) => {
|
|
2085
2185
|
scale = level;
|
|
2086
|
-
|
|
2186
|
+
applyTransform();
|
|
2087
2187
|
},
|
|
2088
2188
|
fitToPage: () => {
|
|
2089
|
-
scale =
|
|
2090
|
-
|
|
2189
|
+
scale = calculateFitScale();
|
|
2190
|
+
rotation = 0;
|
|
2191
|
+
applyTransform();
|
|
2192
|
+
},
|
|
2193
|
+
rotateCW: () => {
|
|
2194
|
+
rotation = (rotation + 90) % 360;
|
|
2195
|
+
applyTransform();
|
|
2196
|
+
},
|
|
2197
|
+
rotateCCW: () => {
|
|
2198
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
2199
|
+
applyTransform();
|
|
2091
2200
|
},
|
|
2092
2201
|
download: () => {
|
|
2093
2202
|
const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
|
|
@@ -2147,90 +2256,149 @@ var DocxPlugin = class {
|
|
|
2147
2256
|
console.warn("[DocxPlugin] Error parsing relationships:", relsErr);
|
|
2148
2257
|
}
|
|
2149
2258
|
}
|
|
2150
|
-
const
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2259
|
+
const sectPrs = Array.from(doc.getElementsByTagNameNS("*", "sectPr"));
|
|
2260
|
+
const lastSectPr = sectPrs[sectPrs.length - 1];
|
|
2261
|
+
let defaultW = 12240;
|
|
2262
|
+
let defaultH = 15840;
|
|
2263
|
+
let margins = { top: 1440, right: 1440, bottom: 1440, left: 1440 };
|
|
2264
|
+
if (lastSectPr) {
|
|
2265
|
+
const pgSz = lastSectPr.getElementsByTagNameNS("*", "pgSz")[0];
|
|
2266
|
+
if (pgSz) {
|
|
2267
|
+
defaultW = parseInt(pgSz.getAttribute("w:w") || pgSz.getAttribute("w") || "12240", 10);
|
|
2268
|
+
defaultH = parseInt(pgSz.getAttribute("w:h") || pgSz.getAttribute("h") || "15840", 10);
|
|
2269
|
+
}
|
|
2270
|
+
const pgMar = lastSectPr.getElementsByTagNameNS("*", "pgMar")[0];
|
|
2271
|
+
if (pgMar) {
|
|
2272
|
+
margins.top = parseInt(pgMar.getAttribute("w:top") || pgMar.getAttribute("top") || "1440", 10);
|
|
2273
|
+
margins.bottom = parseInt(pgMar.getAttribute("w:bottom") || pgMar.getAttribute("bottom") || "1440", 10);
|
|
2274
|
+
margins.left = parseInt(pgMar.getAttribute("w:left") || pgMar.getAttribute("left") || "1440", 10);
|
|
2275
|
+
margins.right = parseInt(pgMar.getAttribute("w:right") || pgMar.getAttribute("right") || "1440", 10);
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
const createPageCard = () => {
|
|
2279
|
+
const card = document.createElement("div");
|
|
2280
|
+
card.className = "fp-docx-page-card";
|
|
2281
|
+
card.style.backgroundColor = "#ffffff";
|
|
2282
|
+
card.style.borderRadius = "4px";
|
|
2283
|
+
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
2284
|
+
card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
2285
|
+
card.style.color = "#1e293b";
|
|
2286
|
+
card.style.lineHeight = "1.6";
|
|
2287
|
+
card.style.boxSizing = "border-box";
|
|
2288
|
+
card.style.overflow = "hidden";
|
|
2289
|
+
card.style.position = "relative";
|
|
2290
|
+
card.style.marginBottom = "24px";
|
|
2291
|
+
card.style.width = `${defaultW / 15}px`;
|
|
2292
|
+
card.style.height = `${defaultH / 15}px`;
|
|
2293
|
+
card.style.padding = `${margins.top / 15}px ${margins.right / 15}px ${margins.bottom / 15}px ${margins.left / 15}px`;
|
|
2294
|
+
return card;
|
|
2295
|
+
};
|
|
2296
|
+
let currentCard = createPageCard();
|
|
2297
|
+
let currentHtml = "";
|
|
2298
|
+
const pages = [{ card: currentCard, html: "" }];
|
|
2299
|
+
const flushHtml = () => {
|
|
2300
|
+
pages[pages.length - 1].html += currentHtml;
|
|
2301
|
+
currentHtml = "";
|
|
2302
|
+
};
|
|
2303
|
+
const newPage = () => {
|
|
2304
|
+
flushHtml();
|
|
2305
|
+
currentCard = createPageCard();
|
|
2306
|
+
pages.push({ card: currentCard, html: "" });
|
|
2307
|
+
};
|
|
2159
2308
|
const body = doc.getElementsByTagNameNS("*", "body")[0] || doc.documentElement;
|
|
2160
|
-
let html = "";
|
|
2161
2309
|
for (const child of Array.from(body.children)) {
|
|
2162
2310
|
const tag = child.localName || child.nodeName.split(":").pop();
|
|
2163
2311
|
if (tag === "p") {
|
|
2164
2312
|
const pStyle = child.getElementsByTagNameNS("*", "pStyle")[0];
|
|
2165
2313
|
const styleVal = pStyle?.getAttribute("w:val") || pStyle?.getAttribute("val") || "";
|
|
2166
2314
|
const numPr = child.getElementsByTagNameNS("*", "numPr")[0];
|
|
2167
|
-
const
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2315
|
+
const chunks = this.extractParagraphChunks(child, imageMap);
|
|
2316
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
2317
|
+
if (i > 0) {
|
|
2318
|
+
newPage();
|
|
2319
|
+
}
|
|
2320
|
+
const textContent = chunks[i];
|
|
2321
|
+
if (!textContent.trim() && !textContent.includes("<img")) {
|
|
2322
|
+
currentHtml += '<div style="height: 10px;"></div>';
|
|
2323
|
+
continue;
|
|
2324
|
+
}
|
|
2325
|
+
const lowerStyle = styleVal.toLowerCase();
|
|
2326
|
+
if (lowerStyle.includes("title")) {
|
|
2327
|
+
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>`;
|
|
2328
|
+
} else if (lowerStyle.includes("heading1") || styleVal === "1") {
|
|
2329
|
+
currentHtml += `<h2 style="font-size: 22px; font-weight: 700; color: #1e40af; margin: 20px 0 10px;">${textContent}</h2>`;
|
|
2330
|
+
} else if (lowerStyle.includes("heading2") || styleVal === "2") {
|
|
2331
|
+
currentHtml += `<h3 style="font-size: 18px; font-weight: 600; color: #2563eb; margin: 16px 0 8px;">${textContent}</h3>`;
|
|
2332
|
+
} else if (lowerStyle.includes("heading3") || styleVal === "3") {
|
|
2333
|
+
currentHtml += `<h4 style="font-size: 15px; font-weight: 600; color: #334155; margin: 12px 0 6px;">${textContent}</h4>`;
|
|
2334
|
+
} else if (numPr) {
|
|
2335
|
+
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>`;
|
|
2336
|
+
} else {
|
|
2337
|
+
currentHtml += `<p style="margin: 8px 0; font-size: 14px;">${textContent}</p>`;
|
|
2338
|
+
}
|
|
2185
2339
|
}
|
|
2186
2340
|
} else if (tag === "tbl") {
|
|
2187
|
-
|
|
2341
|
+
currentHtml += '<table style="width: 100%; border-collapse: collapse; margin: 20px 0; border: 1px solid #cbd5e1;">';
|
|
2188
2342
|
const rows = Array.from(child.getElementsByTagNameNS("*", "tr"));
|
|
2189
2343
|
rows.forEach((tr, rIdx) => {
|
|
2190
|
-
|
|
2344
|
+
currentHtml += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
|
|
2191
2345
|
const cells = Array.from(tr.getElementsByTagNameNS("*", "tc"));
|
|
2192
2346
|
cells.forEach((tc) => {
|
|
2193
2347
|
const cellText = this.extractParagraphHtml(tc, imageMap);
|
|
2194
|
-
|
|
2348
|
+
currentHtml += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || " "}</td>`;
|
|
2195
2349
|
});
|
|
2196
|
-
|
|
2350
|
+
currentHtml += "</tr>";
|
|
2197
2351
|
});
|
|
2198
|
-
|
|
2352
|
+
currentHtml += "</table>";
|
|
2199
2353
|
}
|
|
2200
2354
|
}
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2355
|
+
flushHtml();
|
|
2356
|
+
for (const page of pages) {
|
|
2357
|
+
page.card.innerHTML = DOMPurify6.sanitize(page.html, {
|
|
2358
|
+
ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "s", "strike", "img", "div", "br"],
|
|
2359
|
+
ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
|
|
2360
|
+
});
|
|
2361
|
+
wrapper.appendChild(page.card);
|
|
2362
|
+
}
|
|
2206
2363
|
}
|
|
2207
2364
|
extractParagraphHtml(pElement, imageMap = {}) {
|
|
2208
|
-
|
|
2365
|
+
return this.extractParagraphChunks(pElement, imageMap).join("<br/>");
|
|
2366
|
+
}
|
|
2367
|
+
extractParagraphChunks(pElement, imageMap = {}) {
|
|
2368
|
+
const chunks = [""];
|
|
2369
|
+
let currentChunkIndex = 0;
|
|
2209
2370
|
const drawings = Array.from(pElement.getElementsByTagNameNS("*", "drawing"));
|
|
2210
2371
|
for (const drawing of drawings) {
|
|
2211
2372
|
const blip = drawing.getElementsByTagNameNS("*", "blip")[0];
|
|
2212
2373
|
const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
|
|
2213
2374
|
if (rId && imageMap[rId]) {
|
|
2214
|
-
|
|
2375
|
+
chunks[currentChunkIndex] += `<div style="text-align:center; margin: 12px 0;"><img src="${imageMap[rId]}" style="max-width: 100%; height: auto; border-radius: 4px;" /></div>`;
|
|
2215
2376
|
}
|
|
2216
2377
|
}
|
|
2217
2378
|
const runs = Array.from(pElement.getElementsByTagNameNS("*", "r"));
|
|
2218
|
-
if (runs.length === 0 && !
|
|
2219
|
-
|
|
2379
|
+
if (runs.length === 0 && !chunks[currentChunkIndex]) {
|
|
2380
|
+
chunks[currentChunkIndex] = DOMPurify6.sanitize(pElement.textContent || "");
|
|
2381
|
+
return chunks;
|
|
2220
2382
|
}
|
|
2221
2383
|
for (const r of runs) {
|
|
2222
2384
|
const blip = r.getElementsByTagNameNS("*", "blip")[0] || r.getElementsByTagNameNS("*", "imagedata")[0];
|
|
2223
2385
|
const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
|
|
2224
2386
|
if (rId && imageMap[rId]) {
|
|
2225
|
-
|
|
2387
|
+
chunks[currentChunkIndex] += `<img src="${imageMap[rId]}" style="max-width: 100%; height: auto; display: inline-block; margin: 4px;" />`;
|
|
2226
2388
|
}
|
|
2227
|
-
const brs = r.getElementsByTagNameNS("*", "br");
|
|
2228
|
-
for (
|
|
2229
|
-
|
|
2389
|
+
const brs = Array.from(r.getElementsByTagNameNS("*", "br"));
|
|
2390
|
+
for (const br of brs) {
|
|
2391
|
+
const type = br.getAttribute("w:type") || br.getAttribute("type");
|
|
2392
|
+
if (type === "page") {
|
|
2393
|
+
chunks.push("");
|
|
2394
|
+
currentChunkIndex++;
|
|
2395
|
+
} else {
|
|
2396
|
+
chunks[currentChunkIndex] += "<br/>";
|
|
2397
|
+
}
|
|
2230
2398
|
}
|
|
2231
2399
|
const tabs = r.getElementsByTagNameNS("*", "tab");
|
|
2232
2400
|
if (tabs.length > 0) {
|
|
2233
|
-
|
|
2401
|
+
chunks[currentChunkIndex] += " ";
|
|
2234
2402
|
}
|
|
2235
2403
|
const rPr = r.getElementsByTagNameNS("*", "rPr")[0];
|
|
2236
2404
|
const isBold = !!rPr?.getElementsByTagNameNS("*", "b")[0];
|
|
@@ -2244,7 +2412,7 @@ var DocxPlugin = class {
|
|
|
2244
2412
|
const texts = Array.from(r.getElementsByTagNameNS("*", "t"));
|
|
2245
2413
|
let text = texts.map((t) => t.textContent || "").join("");
|
|
2246
2414
|
if (!text) continue;
|
|
2247
|
-
text =
|
|
2415
|
+
text = DOMPurify6.sanitize(text);
|
|
2248
2416
|
let styles = "";
|
|
2249
2417
|
if (isBold) styles += "font-weight: bold; ";
|
|
2250
2418
|
if (isItalic) styles += "font-style: italic; ";
|
|
@@ -2256,12 +2424,12 @@ var DocxPlugin = class {
|
|
|
2256
2424
|
if (!isNaN(pt) && pt > 0) styles += `font-size: ${pt}pt; `;
|
|
2257
2425
|
}
|
|
2258
2426
|
if (styles) {
|
|
2259
|
-
|
|
2427
|
+
chunks[currentChunkIndex] += `<span style="${styles}">${text}</span>`;
|
|
2260
2428
|
} else {
|
|
2261
|
-
|
|
2429
|
+
chunks[currentChunkIndex] += text;
|
|
2262
2430
|
}
|
|
2263
2431
|
}
|
|
2264
|
-
return
|
|
2432
|
+
return chunks;
|
|
2265
2433
|
}
|
|
2266
2434
|
renderBinaryDocFallback(ctx, wrapper) {
|
|
2267
2435
|
const card = document.createElement("div");
|
|
@@ -2278,14 +2446,14 @@ var DocxPlugin = class {
|
|
|
2278
2446
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
2279
2447
|
if (wordDocStream && wordDocStream.length >= 512) {
|
|
2280
2448
|
const text2 = this.extractReadableStrings(wordDocStream);
|
|
2281
|
-
card.innerHTML = `<div style="white-space: pre-wrap;">${
|
|
2449
|
+
card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6.sanitize(text2)}</div>`;
|
|
2282
2450
|
wrapper.appendChild(card);
|
|
2283
2451
|
return;
|
|
2284
2452
|
}
|
|
2285
2453
|
} catch {
|
|
2286
2454
|
}
|
|
2287
2455
|
const text = this.extractReadableStrings(new Uint8Array(ctx.buffer));
|
|
2288
|
-
card.innerHTML = `<div style="white-space: pre-wrap;">${
|
|
2456
|
+
card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6.sanitize(text)}</div>`;
|
|
2289
2457
|
wrapper.appendChild(card);
|
|
2290
2458
|
}
|
|
2291
2459
|
extractReadableStrings(bytes) {
|
|
@@ -2381,6 +2549,26 @@ var ExcelPlugin = class {
|
|
|
2381
2549
|
instance.zoomIn?.();
|
|
2382
2550
|
}
|
|
2383
2551
|
},
|
|
2552
|
+
{
|
|
2553
|
+
id: "fit-page",
|
|
2554
|
+
icon: "fit-page",
|
|
2555
|
+
label: "Fit to View",
|
|
2556
|
+
type: "button",
|
|
2557
|
+
group: "zoom",
|
|
2558
|
+
execute: () => {
|
|
2559
|
+
instance.fitToPage?.();
|
|
2560
|
+
}
|
|
2561
|
+
},
|
|
2562
|
+
{
|
|
2563
|
+
id: "rotate-cw",
|
|
2564
|
+
icon: "rotate-cw",
|
|
2565
|
+
label: "Rotate",
|
|
2566
|
+
type: "button",
|
|
2567
|
+
group: "view",
|
|
2568
|
+
execute: () => {
|
|
2569
|
+
instance.rotateCW?.();
|
|
2570
|
+
}
|
|
2571
|
+
},
|
|
2384
2572
|
{
|
|
2385
2573
|
id: "download",
|
|
2386
2574
|
icon: "download",
|
|
@@ -2431,9 +2619,23 @@ var ExcelPlugin = class {
|
|
|
2431
2619
|
container.appendChild(tabsArea);
|
|
2432
2620
|
ctx.container.appendChild(container);
|
|
2433
2621
|
let scale = 1;
|
|
2622
|
+
let rotation = 0;
|
|
2434
2623
|
let currentSheetIndex = 1;
|
|
2435
2624
|
let sheetNames = [];
|
|
2436
2625
|
let wb = null;
|
|
2626
|
+
const applyTransform = () => {
|
|
2627
|
+
contentArea.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2628
|
+
contentArea.style.transformOrigin = "top left";
|
|
2629
|
+
};
|
|
2630
|
+
const calculateFitScale = () => {
|
|
2631
|
+
const table = contentArea.querySelector("table");
|
|
2632
|
+
if (!table) return 1;
|
|
2633
|
+
const availW = Math.max(200, container.clientWidth - 48);
|
|
2634
|
+
const availH = Math.max(200, container.clientHeight - 80);
|
|
2635
|
+
const tW = table.offsetWidth || 800;
|
|
2636
|
+
const tH = table.offsetHeight || 600;
|
|
2637
|
+
return Math.min(1, Math.min(availW / tW, availH / tH));
|
|
2638
|
+
};
|
|
2437
2639
|
try {
|
|
2438
2640
|
wb = XLSX.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
|
|
2439
2641
|
sheetNames = wb.SheetNames || [];
|
|
@@ -2521,17 +2723,30 @@ var ExcelPlugin = class {
|
|
|
2521
2723
|
return {
|
|
2522
2724
|
destroy: cleanup,
|
|
2523
2725
|
zoomIn: () => {
|
|
2524
|
-
scale += 0.
|
|
2525
|
-
|
|
2726
|
+
scale += 0.15;
|
|
2727
|
+
applyTransform();
|
|
2526
2728
|
},
|
|
2527
2729
|
zoomOut: () => {
|
|
2528
|
-
scale = Math.max(0.2, scale - 0.
|
|
2529
|
-
|
|
2730
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
2731
|
+
applyTransform();
|
|
2530
2732
|
},
|
|
2531
2733
|
getZoom: () => scale,
|
|
2532
2734
|
setZoom: (level) => {
|
|
2533
2735
|
scale = level;
|
|
2534
|
-
|
|
2736
|
+
applyTransform();
|
|
2737
|
+
},
|
|
2738
|
+
fitToPage: () => {
|
|
2739
|
+
scale = calculateFitScale();
|
|
2740
|
+
rotation = 0;
|
|
2741
|
+
applyTransform();
|
|
2742
|
+
},
|
|
2743
|
+
rotateCW: () => {
|
|
2744
|
+
rotation = (rotation + 90) % 360;
|
|
2745
|
+
applyTransform();
|
|
2746
|
+
},
|
|
2747
|
+
rotateCCW: () => {
|
|
2748
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
2749
|
+
applyTransform();
|
|
2535
2750
|
},
|
|
2536
2751
|
goToPage: (page) => {
|
|
2537
2752
|
if (page > 0 && page <= sheetNames.length) {
|
|
@@ -2781,6 +2996,26 @@ var CodePlugin = class {
|
|
|
2781
2996
|
instance.zoomIn?.();
|
|
2782
2997
|
}
|
|
2783
2998
|
},
|
|
2999
|
+
{
|
|
3000
|
+
id: "fit-page",
|
|
3001
|
+
icon: "fit-page",
|
|
3002
|
+
label: "Fit to View",
|
|
3003
|
+
type: "button",
|
|
3004
|
+
group: "zoom",
|
|
3005
|
+
execute: () => {
|
|
3006
|
+
instance.fitToPage?.();
|
|
3007
|
+
}
|
|
3008
|
+
},
|
|
3009
|
+
{
|
|
3010
|
+
id: "rotate-cw",
|
|
3011
|
+
icon: "rotate-cw",
|
|
3012
|
+
label: "Rotate",
|
|
3013
|
+
type: "button",
|
|
3014
|
+
group: "view",
|
|
3015
|
+
execute: () => {
|
|
3016
|
+
instance.rotateCW?.();
|
|
3017
|
+
}
|
|
3018
|
+
},
|
|
2784
3019
|
{
|
|
2785
3020
|
id: "copy",
|
|
2786
3021
|
icon: "copy",
|
|
@@ -2817,40 +3052,94 @@ var CodePlugin = class {
|
|
|
2817
3052
|
async render(ctx) {
|
|
2818
3053
|
const decoder = new TextDecoder("utf-8");
|
|
2819
3054
|
const fullText = decoder.decode(ctx.buffer);
|
|
2820
|
-
const
|
|
2821
|
-
const
|
|
3055
|
+
const extRaw = ctx.metadata.extension?.toLowerCase();
|
|
3056
|
+
const mimeRaw = ctx.metadata.mimeType?.toLowerCase();
|
|
3057
|
+
const isTxt = extRaw === ".txt" || mimeRaw === "text/plain" && (!extRaw || !this.extensions.filter((e) => e !== ".txt").includes(extRaw));
|
|
3058
|
+
let rawPages = [];
|
|
3059
|
+
if (isTxt) {
|
|
3060
|
+
const explicitPages = fullText.split(/(?:\f|\x0C)/);
|
|
3061
|
+
for (const ep of explicitPages) {
|
|
3062
|
+
const lines = ep.split(/\r?\n/);
|
|
3063
|
+
let currentChunk = [];
|
|
3064
|
+
for (let i = 0; i < lines.length; i++) {
|
|
3065
|
+
currentChunk.push(lines[i]);
|
|
3066
|
+
if (currentChunk.length >= 46) {
|
|
3067
|
+
rawPages.push(currentChunk.join("\n"));
|
|
3068
|
+
currentChunk = [];
|
|
3069
|
+
}
|
|
3070
|
+
}
|
|
3071
|
+
if (currentChunk.length > 0 || lines.length === 0) {
|
|
3072
|
+
rawPages.push(currentChunk.join("\n"));
|
|
3073
|
+
}
|
|
3074
|
+
}
|
|
3075
|
+
if (rawPages.length === 0) rawPages = [""];
|
|
3076
|
+
} else {
|
|
3077
|
+
const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
|
|
3078
|
+
rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
3079
|
+
}
|
|
2822
3080
|
const totalPages = Math.max(1, rawPages.length);
|
|
2823
3081
|
let currentPage = 1;
|
|
2824
3082
|
const container = document.createElement("div");
|
|
2825
3083
|
container.style.width = "100%";
|
|
2826
3084
|
container.style.height = "100%";
|
|
2827
3085
|
container.style.overflow = "auto";
|
|
2828
|
-
container.style.backgroundColor = "#1e1e1e";
|
|
2829
|
-
container.style.color = "#d4d4d4";
|
|
2830
|
-
container.style.padding = "16px";
|
|
2831
|
-
container.style.boxSizing = "border-box";
|
|
2832
3086
|
let fontSize = 13;
|
|
3087
|
+
let rotation = 0;
|
|
3088
|
+
let zoomLevel = 1;
|
|
2833
3089
|
const pre = document.createElement("pre");
|
|
2834
|
-
pre.style.margin = "0";
|
|
2835
|
-
pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
|
|
2836
|
-
pre.style.fontSize = `${fontSize}px`;
|
|
2837
|
-
pre.style.lineHeight = "1.5";
|
|
2838
|
-
pre.style.whiteSpace = "pre-wrap";
|
|
2839
|
-
pre.style.wordBreak = "break-all";
|
|
2840
3090
|
const code = document.createElement("code");
|
|
3091
|
+
if (isTxt) {
|
|
3092
|
+
container.style.backgroundColor = "#f1f5f9";
|
|
3093
|
+
container.style.padding = "32px";
|
|
3094
|
+
container.style.boxSizing = "border-box";
|
|
3095
|
+
container.style.display = "flex";
|
|
3096
|
+
container.style.flexDirection = "column";
|
|
3097
|
+
container.style.alignItems = "center";
|
|
3098
|
+
pre.style.margin = "0";
|
|
3099
|
+
pre.style.fontFamily = "Consolas, 'Courier New', monospace";
|
|
3100
|
+
pre.style.fontSize = "13px";
|
|
3101
|
+
pre.style.color = "#1e293b";
|
|
3102
|
+
pre.style.lineHeight = "1.5";
|
|
3103
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3104
|
+
pre.style.wordBreak = "break-word";
|
|
3105
|
+
pre.style.backgroundColor = "#ffffff";
|
|
3106
|
+
pre.style.width = "816px";
|
|
3107
|
+
pre.style.minHeight = "1056px";
|
|
3108
|
+
pre.style.padding = "72px 56px";
|
|
3109
|
+
pre.style.boxSizing = "border-box";
|
|
3110
|
+
pre.style.boxShadow = "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)";
|
|
3111
|
+
pre.style.borderRadius = "4px";
|
|
3112
|
+
pre.style.transformOrigin = "top center";
|
|
3113
|
+
} else {
|
|
3114
|
+
container.style.backgroundColor = "#1e1e1e";
|
|
3115
|
+
container.style.color = "#d4d4d4";
|
|
3116
|
+
container.style.padding = "16px";
|
|
3117
|
+
container.style.boxSizing = "border-box";
|
|
3118
|
+
pre.style.margin = "0";
|
|
3119
|
+
pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
|
|
3120
|
+
pre.style.fontSize = `${fontSize}px`;
|
|
3121
|
+
pre.style.lineHeight = "1.5";
|
|
3122
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3123
|
+
pre.style.wordBreak = "break-all";
|
|
3124
|
+
pre.style.transformOrigin = "top left";
|
|
3125
|
+
}
|
|
2841
3126
|
const ext = (ctx.metadata.extension || "").replace(".", "");
|
|
2842
3127
|
const renderCodePage = (text) => {
|
|
2843
|
-
|
|
2844
|
-
if (ext && hljs.getLanguage(ext)) {
|
|
2845
|
-
code.innerHTML = hljs.highlight(text, { language: ext }).value;
|
|
2846
|
-
} else {
|
|
2847
|
-
code.innerHTML = hljs.highlightAuto(text).value;
|
|
2848
|
-
}
|
|
2849
|
-
} catch {
|
|
3128
|
+
if (isTxt) {
|
|
2850
3129
|
code.textContent = text;
|
|
3130
|
+
} else {
|
|
3131
|
+
try {
|
|
3132
|
+
if (ext && hljs.getLanguage(ext)) {
|
|
3133
|
+
code.innerHTML = hljs.highlight(text, { language: ext }).value;
|
|
3134
|
+
} else {
|
|
3135
|
+
code.innerHTML = hljs.highlightAuto(text).value;
|
|
3136
|
+
}
|
|
3137
|
+
} catch {
|
|
3138
|
+
code.textContent = text;
|
|
3139
|
+
}
|
|
2851
3140
|
}
|
|
2852
3141
|
};
|
|
2853
|
-
renderCodePage(rawPages[0] || fullText);
|
|
3142
|
+
renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
|
|
2854
3143
|
pre.appendChild(code);
|
|
2855
3144
|
container.appendChild(pre);
|
|
2856
3145
|
let indicator = null;
|
|
@@ -2859,15 +3148,22 @@ var CodePlugin = class {
|
|
|
2859
3148
|
indicator.className = "fp-code-page-indicator";
|
|
2860
3149
|
indicator.style.position = "sticky";
|
|
2861
3150
|
indicator.style.bottom = "16px";
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
3151
|
+
if (isTxt) {
|
|
3152
|
+
indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
|
|
3153
|
+
indicator.style.color = "#334155";
|
|
3154
|
+
indicator.style.border = "1px solid #e2e8f0";
|
|
3155
|
+
indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
|
|
3156
|
+
} else {
|
|
3157
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3158
|
+
indicator.style.color = "#f8fafc";
|
|
3159
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3160
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3161
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
3162
|
+
}
|
|
2865
3163
|
indicator.style.fontSize = "12px";
|
|
2866
3164
|
indicator.style.fontWeight = "600";
|
|
2867
3165
|
indicator.style.padding = "5px 14px";
|
|
2868
3166
|
indicator.style.borderRadius = "20px";
|
|
2869
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2870
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2871
3167
|
indicator.style.zIndex = "10";
|
|
2872
3168
|
indicator.style.userSelect = "none";
|
|
2873
3169
|
indicator.style.pointerEvents = "none";
|
|
@@ -2878,7 +3174,7 @@ var CodePlugin = class {
|
|
|
2878
3174
|
}
|
|
2879
3175
|
const showPage = (pageNum) => {
|
|
2880
3176
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2881
|
-
renderCodePage(rawPages[currentPage - 1] || fullText);
|
|
3177
|
+
renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
|
|
2882
3178
|
if (indicator) {
|
|
2883
3179
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2884
3180
|
}
|
|
@@ -2894,23 +3190,57 @@ var CodePlugin = class {
|
|
|
2894
3190
|
ctx.container.innerHTML = "";
|
|
2895
3191
|
};
|
|
2896
3192
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3193
|
+
const updateTransform = () => {
|
|
3194
|
+
if (isTxt) {
|
|
3195
|
+
pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
|
|
3196
|
+
} else {
|
|
3197
|
+
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3198
|
+
pre.style.fontSize = `${fontSize}px`;
|
|
3199
|
+
}
|
|
3200
|
+
};
|
|
2897
3201
|
return {
|
|
2898
3202
|
destroy: cleanup,
|
|
2899
3203
|
getPageCount: () => totalPages,
|
|
2900
3204
|
getCurrentPage: () => currentPage,
|
|
2901
3205
|
goToPage: (page) => showPage(page),
|
|
2902
3206
|
zoomIn: () => {
|
|
2903
|
-
|
|
2904
|
-
|
|
3207
|
+
if (isTxt) {
|
|
3208
|
+
zoomLevel = Math.min(3, zoomLevel + 0.1);
|
|
3209
|
+
} else {
|
|
3210
|
+
fontSize = Math.min(32, fontSize + 2);
|
|
3211
|
+
}
|
|
3212
|
+
updateTransform();
|
|
2905
3213
|
},
|
|
2906
3214
|
zoomOut: () => {
|
|
2907
|
-
|
|
2908
|
-
|
|
3215
|
+
if (isTxt) {
|
|
3216
|
+
zoomLevel = Math.max(0.1, zoomLevel - 0.1);
|
|
3217
|
+
} else {
|
|
3218
|
+
fontSize = Math.max(8, fontSize - 2);
|
|
3219
|
+
}
|
|
3220
|
+
updateTransform();
|
|
2909
3221
|
},
|
|
2910
|
-
getZoom: () => fontSize / 13,
|
|
3222
|
+
getZoom: () => isTxt ? zoomLevel : fontSize / 13,
|
|
2911
3223
|
setZoom: (level) => {
|
|
2912
|
-
|
|
2913
|
-
|
|
3224
|
+
if (isTxt) {
|
|
3225
|
+
zoomLevel = level;
|
|
3226
|
+
} else {
|
|
3227
|
+
fontSize = Math.round(13 * level);
|
|
3228
|
+
}
|
|
3229
|
+
updateTransform();
|
|
3230
|
+
},
|
|
3231
|
+
fitToPage: () => {
|
|
3232
|
+
fontSize = 13;
|
|
3233
|
+
rotation = 0;
|
|
3234
|
+
zoomLevel = 1;
|
|
3235
|
+
updateTransform();
|
|
3236
|
+
},
|
|
3237
|
+
rotateCW: () => {
|
|
3238
|
+
rotation = (rotation + 90) % 360;
|
|
3239
|
+
updateTransform();
|
|
3240
|
+
},
|
|
3241
|
+
rotateCCW: () => {
|
|
3242
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
3243
|
+
updateTransform();
|
|
2914
3244
|
},
|
|
2915
3245
|
download: () => {
|
|
2916
3246
|
const mimeType = ctx.metadata.mimeType || "text/plain";
|
|
@@ -3209,7 +3539,7 @@ var MarkdownPlugin = class {
|
|
|
3209
3539
|
gfm: true,
|
|
3210
3540
|
breaks: true
|
|
3211
3541
|
});
|
|
3212
|
-
const cleanHtml =
|
|
3542
|
+
const cleanHtml = DOMPurify6.sanitize(rawHtml, {
|
|
3213
3543
|
USE_PROFILES: { html: true }
|
|
3214
3544
|
});
|
|
3215
3545
|
const wrapper = document.createElement("div");
|
|
@@ -3423,6 +3753,14 @@ var PptxPlugin = class {
|
|
|
3423
3753
|
group: "zoom",
|
|
3424
3754
|
execute: () => instance.fitToPage?.()
|
|
3425
3755
|
},
|
|
3756
|
+
{
|
|
3757
|
+
id: "rotate-cw",
|
|
3758
|
+
icon: "rotate-cw",
|
|
3759
|
+
label: "Rotate",
|
|
3760
|
+
type: "button",
|
|
3761
|
+
group: "view",
|
|
3762
|
+
execute: () => instance.rotateCW?.()
|
|
3763
|
+
},
|
|
3426
3764
|
{
|
|
3427
3765
|
id: "download",
|
|
3428
3766
|
icon: "download",
|
|
@@ -3447,6 +3785,7 @@ var PptxPlugin = class {
|
|
|
3447
3785
|
const slideCount = renderer.slidePaths?.length || 1;
|
|
3448
3786
|
let currentSlide = 1;
|
|
3449
3787
|
let scale = 1;
|
|
3788
|
+
let rotation = 0;
|
|
3450
3789
|
const wrapper = document.createElement("div");
|
|
3451
3790
|
wrapper.className = "fp-pptx-wrapper";
|
|
3452
3791
|
wrapper.style.cssText = `
|
|
@@ -3469,6 +3808,8 @@ var PptxPlugin = class {
|
|
|
3469
3808
|
background: #ffffff;
|
|
3470
3809
|
transform-origin: top center;
|
|
3471
3810
|
transition: transform 0.2s ease;
|
|
3811
|
+
max-width: calc(100% - 32px);
|
|
3812
|
+
max-height: calc(100% - 48px);
|
|
3472
3813
|
`;
|
|
3473
3814
|
const canvas = document.createElement("canvas");
|
|
3474
3815
|
slideContainer.appendChild(canvas);
|
|
@@ -3476,10 +3817,22 @@ var PptxPlugin = class {
|
|
|
3476
3817
|
ctx.container.innerHTML = "";
|
|
3477
3818
|
ctx.container.style.overflow = "auto";
|
|
3478
3819
|
ctx.container.appendChild(wrapper);
|
|
3820
|
+
const calculateFitScale = () => {
|
|
3821
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
3822
|
+
const availH = Math.max(200, ctx.container.clientHeight - 72);
|
|
3823
|
+
const cW = canvas.offsetWidth || 1280;
|
|
3824
|
+
const cH = canvas.offsetHeight || 720;
|
|
3825
|
+
return Math.min(1, Math.min(availW / cW, availH / cH));
|
|
3826
|
+
};
|
|
3827
|
+
const applyTransform = () => {
|
|
3828
|
+
slideContainer.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
3829
|
+
};
|
|
3479
3830
|
const renderCurrentSlide = async () => {
|
|
3480
3831
|
try {
|
|
3481
3832
|
await renderer.renderSlide(currentSlide - 1, canvas, 1280);
|
|
3482
3833
|
ctx.emit("page-change", { page: currentSlide, totalPages: slideCount });
|
|
3834
|
+
scale = calculateFitScale();
|
|
3835
|
+
applyTransform();
|
|
3483
3836
|
} catch (err) {
|
|
3484
3837
|
console.error("[PptxPlugin] Failed to render slide:", err);
|
|
3485
3838
|
}
|
|
@@ -3502,21 +3855,30 @@ var PptxPlugin = class {
|
|
|
3502
3855
|
getPageCount: () => slideCount,
|
|
3503
3856
|
getCurrentPage: () => currentSlide,
|
|
3504
3857
|
zoomIn: () => {
|
|
3505
|
-
scale += 0.
|
|
3506
|
-
|
|
3858
|
+
scale += 0.15;
|
|
3859
|
+
applyTransform();
|
|
3507
3860
|
},
|
|
3508
3861
|
zoomOut: () => {
|
|
3509
|
-
scale = Math.max(0.2, scale - 0.
|
|
3510
|
-
|
|
3862
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
3863
|
+
applyTransform();
|
|
3511
3864
|
},
|
|
3512
3865
|
getZoom: () => scale,
|
|
3513
3866
|
setZoom: (level) => {
|
|
3514
3867
|
scale = level;
|
|
3515
|
-
|
|
3868
|
+
applyTransform();
|
|
3516
3869
|
},
|
|
3517
3870
|
fitToPage: () => {
|
|
3518
|
-
scale =
|
|
3519
|
-
|
|
3871
|
+
scale = calculateFitScale();
|
|
3872
|
+
rotation = 0;
|
|
3873
|
+
applyTransform();
|
|
3874
|
+
},
|
|
3875
|
+
rotateCW: () => {
|
|
3876
|
+
rotation = (rotation + 90) % 360;
|
|
3877
|
+
applyTransform();
|
|
3878
|
+
},
|
|
3879
|
+
rotateCCW: () => {
|
|
3880
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
3881
|
+
applyTransform();
|
|
3520
3882
|
},
|
|
3521
3883
|
getThumbnails: () => {
|
|
3522
3884
|
const list = [];
|
|
@@ -3797,6 +4159,14 @@ var RtfPlugin = class {
|
|
|
3797
4159
|
group: "zoom",
|
|
3798
4160
|
execute: () => instance.fitToPage?.()
|
|
3799
4161
|
},
|
|
4162
|
+
{
|
|
4163
|
+
id: "rotate-cw",
|
|
4164
|
+
icon: "rotate-cw",
|
|
4165
|
+
label: "Rotate",
|
|
4166
|
+
type: "button",
|
|
4167
|
+
group: "view",
|
|
4168
|
+
execute: () => instance.rotateCW?.()
|
|
4169
|
+
},
|
|
3800
4170
|
{
|
|
3801
4171
|
id: "download",
|
|
3802
4172
|
icon: "download",
|
|
@@ -3805,6 +4175,14 @@ var RtfPlugin = class {
|
|
|
3805
4175
|
group: "actions",
|
|
3806
4176
|
execute: () => instance.download?.()
|
|
3807
4177
|
},
|
|
4178
|
+
{
|
|
4179
|
+
id: "copy",
|
|
4180
|
+
icon: "copy",
|
|
4181
|
+
label: "Copy Text",
|
|
4182
|
+
type: "button",
|
|
4183
|
+
group: "actions",
|
|
4184
|
+
execute: () => instance.copy?.()
|
|
4185
|
+
},
|
|
3808
4186
|
{
|
|
3809
4187
|
id: "print",
|
|
3810
4188
|
icon: "print",
|
|
@@ -3833,7 +4211,24 @@ var RtfPlugin = class {
|
|
|
3833
4211
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
3834
4212
|
ctx.container.appendChild(wrapper);
|
|
3835
4213
|
let scale = 1;
|
|
4214
|
+
let rotation = 0;
|
|
3836
4215
|
let pageElements = [];
|
|
4216
|
+
const calculateFitScale = () => {
|
|
4217
|
+
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4218
|
+
const elW = activeEl.offsetWidth || 850;
|
|
4219
|
+
const elH = activeEl.offsetHeight || 1e3;
|
|
4220
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
4221
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
4222
|
+
return Math.min(1.1, Math.min(availW / elW, availH / elH));
|
|
4223
|
+
};
|
|
4224
|
+
const applyTransform = () => {
|
|
4225
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4226
|
+
wrapper.style.transformOrigin = "top center";
|
|
4227
|
+
};
|
|
4228
|
+
setTimeout(() => {
|
|
4229
|
+
scale = calculateFitScale();
|
|
4230
|
+
applyTransform();
|
|
4231
|
+
}, 60);
|
|
3837
4232
|
try {
|
|
3838
4233
|
if (typeof RTFJS.loggingEnabled === "function") {
|
|
3839
4234
|
RTFJS.loggingEnabled(false);
|
|
@@ -3849,14 +4244,31 @@ var RtfPlugin = class {
|
|
|
3849
4244
|
} catch (err) {
|
|
3850
4245
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
3851
4246
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
3852
|
-
const
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
4247
|
+
const rawPages = text.split(/\\page\b/).map((segment) => {
|
|
4248
|
+
return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
|
|
4249
|
+
}).filter((p) => p.length > 0);
|
|
4250
|
+
const pages = rawPages.length > 0 ? rawPages : [text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim()];
|
|
4251
|
+
for (let i = 0; i < pages.length; i++) {
|
|
4252
|
+
const pageCard = document.createElement("div");
|
|
4253
|
+
pageCard.className = "fp-rtf-page-card";
|
|
4254
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
4255
|
+
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4256
|
+
pageCard.style.borderRadius = "4px";
|
|
4257
|
+
pageCard.style.padding = "72px 56px";
|
|
4258
|
+
pageCard.style.width = "816px";
|
|
4259
|
+
pageCard.style.minHeight = "1056px";
|
|
4260
|
+
pageCard.style.maxWidth = "100%";
|
|
4261
|
+
pageCard.style.boxSizing = "border-box";
|
|
4262
|
+
pageCard.style.fontFamily = "serif";
|
|
4263
|
+
pageCard.style.fontSize = "12pt";
|
|
4264
|
+
pageCard.style.lineHeight = "1.6";
|
|
4265
|
+
pageCard.style.color = "#1e293b";
|
|
4266
|
+
pageCard.style.whiteSpace = "pre-wrap";
|
|
4267
|
+
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4268
|
+
pageCard.textContent = pages[i];
|
|
4269
|
+
wrapper.appendChild(pageCard);
|
|
4270
|
+
pageElements.push(pageCard);
|
|
4271
|
+
}
|
|
3860
4272
|
}
|
|
3861
4273
|
const totalPages = Math.max(1, pageElements.length);
|
|
3862
4274
|
let currentPage = 1;
|
|
@@ -3910,21 +4322,30 @@ var RtfPlugin = class {
|
|
|
3910
4322
|
getCurrentPage: () => currentPage,
|
|
3911
4323
|
goToPage: (page) => showPage(page),
|
|
3912
4324
|
zoomIn: () => {
|
|
3913
|
-
scale += 0.
|
|
3914
|
-
|
|
4325
|
+
scale += 0.15;
|
|
4326
|
+
applyTransform();
|
|
3915
4327
|
},
|
|
3916
4328
|
zoomOut: () => {
|
|
3917
|
-
scale = Math.max(0.2, scale - 0.
|
|
3918
|
-
|
|
4329
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
4330
|
+
applyTransform();
|
|
3919
4331
|
},
|
|
3920
4332
|
getZoom: () => scale,
|
|
3921
4333
|
setZoom: (level) => {
|
|
3922
4334
|
scale = level;
|
|
3923
|
-
|
|
4335
|
+
applyTransform();
|
|
3924
4336
|
},
|
|
3925
4337
|
fitToPage: () => {
|
|
3926
|
-
scale =
|
|
3927
|
-
|
|
4338
|
+
scale = calculateFitScale();
|
|
4339
|
+
rotation = 0;
|
|
4340
|
+
applyTransform();
|
|
4341
|
+
},
|
|
4342
|
+
rotateCW: () => {
|
|
4343
|
+
rotation = (rotation + 90) % 360;
|
|
4344
|
+
applyTransform();
|
|
4345
|
+
},
|
|
4346
|
+
rotateCCW: () => {
|
|
4347
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
4348
|
+
applyTransform();
|
|
3928
4349
|
},
|
|
3929
4350
|
download: () => {
|
|
3930
4351
|
const blob = new Blob([ctx.buffer], { type: "application/rtf" });
|
|
@@ -3935,6 +4356,10 @@ var RtfPlugin = class {
|
|
|
3935
4356
|
a.click();
|
|
3936
4357
|
URL.revokeObjectURL(url);
|
|
3937
4358
|
},
|
|
4359
|
+
copy: () => {
|
|
4360
|
+
const text = wrapper.textContent || "";
|
|
4361
|
+
navigator.clipboard?.writeText(text);
|
|
4362
|
+
},
|
|
3938
4363
|
print: () => {
|
|
3939
4364
|
window.print();
|
|
3940
4365
|
}
|
|
@@ -4009,7 +4434,7 @@ var HtmlPreviewPlugin = class {
|
|
|
4009
4434
|
}
|
|
4010
4435
|
async render(ctx) {
|
|
4011
4436
|
const rawHtml = new TextDecoder("utf-8").decode(ctx.buffer);
|
|
4012
|
-
const sanitized =
|
|
4437
|
+
const sanitized = DOMPurify6.sanitize(rawHtml, {
|
|
4013
4438
|
WHOLE_DOCUMENT: true,
|
|
4014
4439
|
ADD_TAGS: ["style", "link"],
|
|
4015
4440
|
ADD_ATTR: ["target", "rel"]
|
|
@@ -4152,11 +4577,19 @@ var OpenDocumentPlugin = class {
|
|
|
4152
4577
|
{
|
|
4153
4578
|
id: "fit-page",
|
|
4154
4579
|
icon: "fit-page",
|
|
4155
|
-
label: "Fit to Page",
|
|
4580
|
+
label: isPresentation ? "Fit to Slide" : "Fit to Page",
|
|
4156
4581
|
type: "button",
|
|
4157
4582
|
group: "zoom",
|
|
4158
4583
|
execute: () => instance.fitToPage?.()
|
|
4159
4584
|
},
|
|
4585
|
+
{
|
|
4586
|
+
id: "rotate-cw",
|
|
4587
|
+
icon: "rotate-cw",
|
|
4588
|
+
label: "Rotate",
|
|
4589
|
+
type: "button",
|
|
4590
|
+
group: "view",
|
|
4591
|
+
execute: () => instance.rotateCW?.()
|
|
4592
|
+
},
|
|
4160
4593
|
{
|
|
4161
4594
|
id: "download",
|
|
4162
4595
|
icon: "download",
|
|
@@ -4220,6 +4653,22 @@ var OpenDocumentPlugin = class {
|
|
|
4220
4653
|
container.appendChild(wrapper);
|
|
4221
4654
|
ctx.container.appendChild(container);
|
|
4222
4655
|
let scale = 1;
|
|
4656
|
+
let rotation = 0;
|
|
4657
|
+
const calculateFitScale = () => {
|
|
4658
|
+
const elW = wrapper.offsetWidth || 850;
|
|
4659
|
+
const elH = wrapper.offsetHeight || (isPresentation ? 540 : 1e3);
|
|
4660
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
4661
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
4662
|
+
return Math.min(1, Math.min(availW / elW, availH / elH));
|
|
4663
|
+
};
|
|
4664
|
+
const applyTransform = () => {
|
|
4665
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4666
|
+
wrapper.style.transformOrigin = "top center";
|
|
4667
|
+
};
|
|
4668
|
+
setTimeout(() => {
|
|
4669
|
+
scale = calculateFitScale();
|
|
4670
|
+
applyTransform();
|
|
4671
|
+
}, 60);
|
|
4223
4672
|
let currentPage = 1;
|
|
4224
4673
|
let totalPages = 1;
|
|
4225
4674
|
let slides = [];
|
|
@@ -4251,14 +4700,97 @@ var OpenDocumentPlugin = class {
|
|
|
4251
4700
|
wrapper.textContent = contentDoc.documentElement.textContent || "Formula content";
|
|
4252
4701
|
}
|
|
4253
4702
|
} else {
|
|
4254
|
-
wrapper.style.maxWidth = "
|
|
4255
|
-
wrapper.style.padding = "
|
|
4703
|
+
wrapper.style.maxWidth = "none";
|
|
4704
|
+
wrapper.style.padding = "0";
|
|
4256
4705
|
wrapper.style.minHeight = "100%";
|
|
4706
|
+
wrapper.style.backgroundColor = "transparent";
|
|
4707
|
+
wrapper.style.boxShadow = "none";
|
|
4708
|
+
wrapper.style.position = "relative";
|
|
4709
|
+
const dims = this.getPageDimensions(stylesDoc, contentDoc);
|
|
4257
4710
|
const bodyHtml = this.renderOdfBody(contentDoc, styleMap, imageUrls);
|
|
4258
|
-
|
|
4259
|
-
|
|
4711
|
+
const tempDiv = document.createElement("div");
|
|
4712
|
+
tempDiv.style.width = `${dims.width - dims.marginLeft - dims.marginRight}px`;
|
|
4713
|
+
tempDiv.style.position = "absolute";
|
|
4714
|
+
tempDiv.style.visibility = "hidden";
|
|
4715
|
+
tempDiv.innerHTML = DOMPurify6.sanitize(bodyHtml, {
|
|
4716
|
+
ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub", "hr"],
|
|
4260
4717
|
ADD_ATTR: ["style", "colspan", "rowspan"]
|
|
4261
4718
|
});
|
|
4719
|
+
document.body.appendChild(tempDiv);
|
|
4720
|
+
const contentHeight = dims.height - dims.marginTop - dims.marginBottom;
|
|
4721
|
+
const pageElements = [[]];
|
|
4722
|
+
let currentHeight = 0;
|
|
4723
|
+
let currentPageIdx = 0;
|
|
4724
|
+
Array.from(tempDiv.children).forEach((child) => {
|
|
4725
|
+
const el = child;
|
|
4726
|
+
const style = el.getAttribute("style") || "";
|
|
4727
|
+
const isBreakBefore = style.includes("page-break-before: always");
|
|
4728
|
+
const isBreakAfter = style.includes("page-break-after: always");
|
|
4729
|
+
const isSoftBreak = el.classList.contains("odf-page-break");
|
|
4730
|
+
if (isBreakBefore) {
|
|
4731
|
+
if (pageElements[currentPageIdx].length > 0) {
|
|
4732
|
+
currentPageIdx++;
|
|
4733
|
+
pageElements.push([]);
|
|
4734
|
+
currentHeight = 0;
|
|
4735
|
+
}
|
|
4736
|
+
}
|
|
4737
|
+
const h = el.offsetHeight || 0;
|
|
4738
|
+
if (currentHeight + h > contentHeight && pageElements[currentPageIdx].length > 0 && !isSoftBreak) {
|
|
4739
|
+
currentPageIdx++;
|
|
4740
|
+
pageElements.push([]);
|
|
4741
|
+
currentHeight = 0;
|
|
4742
|
+
}
|
|
4743
|
+
if (!isSoftBreak) {
|
|
4744
|
+
pageElements[currentPageIdx].push(el.cloneNode(true));
|
|
4745
|
+
currentHeight += h;
|
|
4746
|
+
}
|
|
4747
|
+
if (isBreakAfter || isSoftBreak) {
|
|
4748
|
+
currentPageIdx++;
|
|
4749
|
+
pageElements.push([]);
|
|
4750
|
+
currentHeight = 0;
|
|
4751
|
+
}
|
|
4752
|
+
});
|
|
4753
|
+
document.body.removeChild(tempDiv);
|
|
4754
|
+
if (pageElements.length > 1 && pageElements[pageElements.length - 1].length === 0) {
|
|
4755
|
+
pageElements.pop();
|
|
4756
|
+
}
|
|
4757
|
+
totalPages = Math.max(1, pageElements.length);
|
|
4758
|
+
pageElements.forEach((elements, idx) => {
|
|
4759
|
+
const page = document.createElement("div");
|
|
4760
|
+
page.className = `fp-odt-page fp-odt-page-${idx + 1}`;
|
|
4761
|
+
page.style.width = `${dims.width}px`;
|
|
4762
|
+
page.style.minHeight = `${dims.height}px`;
|
|
4763
|
+
page.style.padding = `${dims.marginTop}px ${dims.marginRight}px ${dims.marginBottom}px ${dims.marginLeft}px`;
|
|
4764
|
+
page.style.margin = "0 auto";
|
|
4765
|
+
page.style.backgroundColor = "#ffffff";
|
|
4766
|
+
page.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
|
|
4767
|
+
page.style.borderRadius = "4px";
|
|
4768
|
+
page.style.boxSizing = "border-box";
|
|
4769
|
+
page.style.display = idx === 0 ? "block" : "none";
|
|
4770
|
+
page.style.position = "absolute";
|
|
4771
|
+
page.style.top = "0";
|
|
4772
|
+
page.style.left = "50%";
|
|
4773
|
+
page.style.transform = "translateX(-50%)";
|
|
4774
|
+
elements.forEach((el) => page.appendChild(el));
|
|
4775
|
+
wrapper.appendChild(page);
|
|
4776
|
+
slides.push(page);
|
|
4777
|
+
});
|
|
4778
|
+
const pageIndicator = document.createElement("div");
|
|
4779
|
+
pageIndicator.className = "fp-odt-page-indicator";
|
|
4780
|
+
pageIndicator.style.position = "sticky";
|
|
4781
|
+
pageIndicator.style.bottom = "16px";
|
|
4782
|
+
pageIndicator.style.left = "50%";
|
|
4783
|
+
pageIndicator.style.transform = "translateX(-50%)";
|
|
4784
|
+
pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
|
4785
|
+
pageIndicator.style.color = "#fff";
|
|
4786
|
+
pageIndicator.style.padding = "6px 12px";
|
|
4787
|
+
pageIndicator.style.borderRadius = "16px";
|
|
4788
|
+
pageIndicator.style.fontSize = "12px";
|
|
4789
|
+
pageIndicator.style.zIndex = "100";
|
|
4790
|
+
pageIndicator.style.display = "inline-block";
|
|
4791
|
+
pageIndicator.style.width = "fit-content";
|
|
4792
|
+
pageIndicator.textContent = `Page 1 of ${totalPages}`;
|
|
4793
|
+
container.appendChild(pageIndicator);
|
|
4262
4794
|
}
|
|
4263
4795
|
const cleanup = () => {
|
|
4264
4796
|
imageUrls.forEach((url) => URL.revokeObjectURL(url));
|
|
@@ -4267,32 +4799,45 @@ var OpenDocumentPlugin = class {
|
|
|
4267
4799
|
};
|
|
4268
4800
|
ctx.signal.addEventListener("abort", cleanup);
|
|
4269
4801
|
const goToPage = (page) => {
|
|
4270
|
-
if (
|
|
4802
|
+
if (page < 1 || page > totalPages) return;
|
|
4271
4803
|
currentPage = page;
|
|
4272
4804
|
slides.forEach((s, idx) => {
|
|
4273
4805
|
s.style.display = idx === page - 1 ? "block" : "none";
|
|
4274
4806
|
});
|
|
4807
|
+
const indicator = container.querySelector(".fp-odt-page-indicator");
|
|
4808
|
+
if (indicator) {
|
|
4809
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4810
|
+
}
|
|
4275
4811
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4276
4812
|
};
|
|
4277
4813
|
return {
|
|
4278
4814
|
destroy: cleanup,
|
|
4279
4815
|
isPresentation,
|
|
4280
4816
|
zoomIn: () => {
|
|
4281
|
-
scale += 0.
|
|
4282
|
-
|
|
4817
|
+
scale += 0.15;
|
|
4818
|
+
applyTransform();
|
|
4283
4819
|
},
|
|
4284
4820
|
zoomOut: () => {
|
|
4285
|
-
scale = Math.max(0.2, scale - 0.
|
|
4286
|
-
|
|
4821
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
4822
|
+
applyTransform();
|
|
4287
4823
|
},
|
|
4288
4824
|
getZoom: () => scale,
|
|
4289
4825
|
setZoom: (level) => {
|
|
4290
4826
|
scale = level;
|
|
4291
|
-
|
|
4827
|
+
applyTransform();
|
|
4292
4828
|
},
|
|
4293
4829
|
fitToPage: () => {
|
|
4294
|
-
scale =
|
|
4295
|
-
|
|
4830
|
+
scale = calculateFitScale();
|
|
4831
|
+
rotation = 0;
|
|
4832
|
+
applyTransform();
|
|
4833
|
+
},
|
|
4834
|
+
rotateCW: () => {
|
|
4835
|
+
rotation = (rotation + 90) % 360;
|
|
4836
|
+
applyTransform();
|
|
4837
|
+
},
|
|
4838
|
+
rotateCCW: () => {
|
|
4839
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
4840
|
+
applyTransform();
|
|
4296
4841
|
},
|
|
4297
4842
|
goToPage,
|
|
4298
4843
|
getPageCount: () => totalPages,
|
|
@@ -4331,6 +4876,43 @@ var OpenDocumentPlugin = class {
|
|
|
4331
4876
|
}
|
|
4332
4877
|
};
|
|
4333
4878
|
}
|
|
4879
|
+
getPageDimensions(stylesDoc, contentDoc) {
|
|
4880
|
+
let width = 850;
|
|
4881
|
+
let height = 1123;
|
|
4882
|
+
let marginTop = 48;
|
|
4883
|
+
let marginBottom = 48;
|
|
4884
|
+
let marginLeft = 48;
|
|
4885
|
+
let marginRight = 48;
|
|
4886
|
+
const parseUnit = (val) => {
|
|
4887
|
+
if (!val) return null;
|
|
4888
|
+
if (val.endsWith("cm")) return parseFloat(val) * 37.8;
|
|
4889
|
+
if (val.endsWith("mm")) return parseFloat(val) * 3.78;
|
|
4890
|
+
if (val.endsWith("in")) return parseFloat(val) * 96;
|
|
4891
|
+
if (val.endsWith("pt")) return parseFloat(val) * 1.33;
|
|
4892
|
+
if (val.endsWith("px")) return parseFloat(val);
|
|
4893
|
+
return parseFloat(val);
|
|
4894
|
+
};
|
|
4895
|
+
const docs = [stylesDoc, contentDoc].filter(Boolean);
|
|
4896
|
+
for (const doc of docs) {
|
|
4897
|
+
const pageLayout = doc.querySelector("page-layout-properties, [page-width]");
|
|
4898
|
+
if (pageLayout) {
|
|
4899
|
+
const w = parseUnit(pageLayout.getAttribute("fo:page-width") || pageLayout.getAttribute("page-width"));
|
|
4900
|
+
const h = parseUnit(pageLayout.getAttribute("fo:page-height") || pageLayout.getAttribute("page-height"));
|
|
4901
|
+
const mt = parseUnit(pageLayout.getAttribute("fo:margin-top") || pageLayout.getAttribute("margin-top"));
|
|
4902
|
+
const mb = parseUnit(pageLayout.getAttribute("fo:margin-bottom") || pageLayout.getAttribute("margin-bottom"));
|
|
4903
|
+
const ml = parseUnit(pageLayout.getAttribute("fo:margin-left") || pageLayout.getAttribute("margin-left"));
|
|
4904
|
+
const mr = parseUnit(pageLayout.getAttribute("fo:margin-right") || pageLayout.getAttribute("margin-right"));
|
|
4905
|
+
if (w !== null) width = w;
|
|
4906
|
+
if (h !== null) height = h;
|
|
4907
|
+
if (mt !== null) marginTop = mt;
|
|
4908
|
+
if (mb !== null) marginBottom = mb;
|
|
4909
|
+
if (ml !== null) marginLeft = ml;
|
|
4910
|
+
if (mr !== null) marginRight = mr;
|
|
4911
|
+
break;
|
|
4912
|
+
}
|
|
4913
|
+
}
|
|
4914
|
+
return { width, height, marginTop, marginBottom, marginLeft, marginRight };
|
|
4915
|
+
}
|
|
4334
4916
|
extractStyles(stylesDoc, contentDoc) {
|
|
4335
4917
|
const map = /* @__PURE__ */ new Map();
|
|
4336
4918
|
const styleNodes = [];
|
|
@@ -4353,14 +4935,21 @@ var OpenDocumentPlugin = class {
|
|
|
4353
4935
|
if (color) css += `color: ${color}; `;
|
|
4354
4936
|
if (size) css += `font-size: ${size}; `;
|
|
4355
4937
|
}
|
|
4356
|
-
|
|
4938
|
+
let paraProp = node.querySelector("paragraph-properties, [text-align]");
|
|
4939
|
+
if (!paraProp) {
|
|
4940
|
+
paraProp = Array.from(node.children).find((c) => c.tagName.includes("paragraph-properties")) || null;
|
|
4941
|
+
}
|
|
4357
4942
|
if (paraProp) {
|
|
4358
4943
|
const align = paraProp.getAttribute("fo:text-align") || paraProp.getAttribute("text-align");
|
|
4359
4944
|
const mt = paraProp.getAttribute("fo:margin-top") || paraProp.getAttribute("margin-top");
|
|
4360
4945
|
const mb = paraProp.getAttribute("fo:margin-bottom") || paraProp.getAttribute("margin-bottom");
|
|
4946
|
+
const breakBefore = paraProp.getAttribute("fo:break-before") || paraProp.getAttribute("break-before");
|
|
4947
|
+
const breakAfter = paraProp.getAttribute("fo:break-after") || paraProp.getAttribute("break-after");
|
|
4361
4948
|
if (align) css += `text-align: ${align}; `;
|
|
4362
4949
|
if (mt) css += `margin-top: ${mt}; `;
|
|
4363
4950
|
if (mb) css += `margin-bottom: ${mb}; `;
|
|
4951
|
+
if (breakBefore === "page") css += "page-break-before: always; ";
|
|
4952
|
+
if (breakAfter === "page") css += "page-break-after: always; ";
|
|
4364
4953
|
}
|
|
4365
4954
|
if (css) map.set(name, css);
|
|
4366
4955
|
}
|
|
@@ -4445,6 +5034,8 @@ var OpenDocumentPlugin = class {
|
|
|
4445
5034
|
result += " ";
|
|
4446
5035
|
} else if (tag === "line-break") {
|
|
4447
5036
|
result += "<br/>";
|
|
5037
|
+
} else if (tag === "soft-page-break") {
|
|
5038
|
+
result += '<hr class="odf-page-break" style="page-break-after: always; border: none; margin: 0; padding: 0; height: 0;" />';
|
|
4448
5039
|
} else {
|
|
4449
5040
|
result += el.textContent || "";
|
|
4450
5041
|
}
|
|
@@ -4562,6 +5153,14 @@ var DocPlugin = class {
|
|
|
4562
5153
|
group: "zoom",
|
|
4563
5154
|
execute: () => instance.fitToPage?.()
|
|
4564
5155
|
},
|
|
5156
|
+
{
|
|
5157
|
+
id: "rotate-cw",
|
|
5158
|
+
icon: "rotate-cw",
|
|
5159
|
+
label: "Rotate",
|
|
5160
|
+
type: "button",
|
|
5161
|
+
group: "view",
|
|
5162
|
+
execute: () => instance.rotateCW?.()
|
|
5163
|
+
},
|
|
4565
5164
|
{
|
|
4566
5165
|
id: "copy",
|
|
4567
5166
|
icon: "copy",
|
|
@@ -4597,20 +5196,9 @@ var DocPlugin = class {
|
|
|
4597
5196
|
container.style.overflow = "auto";
|
|
4598
5197
|
container.style.padding = "32px 16px";
|
|
4599
5198
|
container.style.backgroundColor = "#f1f5f9";
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
wrapper.style.margin = "0 auto";
|
|
4604
|
-
wrapper.style.backgroundColor = "#ffffff";
|
|
4605
|
-
wrapper.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4606
|
-
wrapper.style.borderRadius = "4px";
|
|
4607
|
-
wrapper.style.padding = "56px 48px";
|
|
4608
|
-
wrapper.style.minHeight = "100%";
|
|
4609
|
-
wrapper.style.transformOrigin = "top center";
|
|
4610
|
-
wrapper.style.transition = "transform 0.2s ease";
|
|
4611
|
-
wrapper.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4612
|
-
wrapper.style.color = "#1e293b";
|
|
4613
|
-
container.appendChild(wrapper);
|
|
5199
|
+
container.style.display = "flex";
|
|
5200
|
+
container.style.justifyContent = "center";
|
|
5201
|
+
container.style.alignItems = "flex-start";
|
|
4614
5202
|
ctx.container.appendChild(container);
|
|
4615
5203
|
let scale = 1;
|
|
4616
5204
|
let extractedRawText = "";
|
|
@@ -4637,21 +5225,27 @@ var DocPlugin = class {
|
|
|
4637
5225
|
const rawPages = this.splitIntoPages(extractedRawText);
|
|
4638
5226
|
const totalPages = Math.max(1, rawPages.length);
|
|
4639
5227
|
let currentPage = 1;
|
|
4640
|
-
wrapper.innerHTML = "";
|
|
4641
5228
|
const pageCards = [];
|
|
4642
5229
|
for (let i = 0; i < totalPages; i++) {
|
|
4643
5230
|
const pageCard = document.createElement("div");
|
|
4644
5231
|
pageCard.className = "fp-doc-page-card";
|
|
5232
|
+
pageCard.style.width = "816px";
|
|
5233
|
+
pageCard.style.height = "1056px";
|
|
4645
5234
|
pageCard.style.backgroundColor = "#ffffff";
|
|
4646
5235
|
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4647
5236
|
pageCard.style.borderRadius = "4px";
|
|
4648
|
-
pageCard.style.padding = "
|
|
4649
|
-
pageCard.style.
|
|
5237
|
+
pageCard.style.padding = "96px 72px";
|
|
5238
|
+
pageCard.style.boxSizing = "border-box";
|
|
5239
|
+
pageCard.style.overflow = "hidden";
|
|
4650
5240
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
5241
|
+
pageCard.style.transformOrigin = "top center";
|
|
5242
|
+
pageCard.style.transition = "transform 0.2s ease";
|
|
5243
|
+
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
5244
|
+
pageCard.style.color = "#1e293b";
|
|
4651
5245
|
if (isFallback && i === 0) {
|
|
4652
5246
|
pageCard.innerHTML = `
|
|
4653
5247
|
<div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
|
|
4654
|
-
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${
|
|
5248
|
+
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify6.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
|
|
4655
5249
|
<span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
|
|
4656
5250
|
</div>
|
|
4657
5251
|
${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
|
|
@@ -4659,15 +5253,17 @@ var DocPlugin = class {
|
|
|
4659
5253
|
} else {
|
|
4660
5254
|
pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
|
|
4661
5255
|
}
|
|
4662
|
-
|
|
5256
|
+
container.appendChild(pageCard);
|
|
4663
5257
|
pageCards.push(pageCard);
|
|
4664
5258
|
}
|
|
4665
5259
|
let indicator = null;
|
|
4666
5260
|
if (totalPages > 1) {
|
|
4667
5261
|
indicator = document.createElement("div");
|
|
4668
5262
|
indicator.className = "fp-doc-page-indicator";
|
|
4669
|
-
indicator.style.position = "
|
|
5263
|
+
indicator.style.position = "fixed";
|
|
4670
5264
|
indicator.style.bottom = "16px";
|
|
5265
|
+
indicator.style.left = "50%";
|
|
5266
|
+
indicator.style.transform = "translateX(-50%)";
|
|
4671
5267
|
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4672
5268
|
indicator.style.backdropFilter = "blur(8px)";
|
|
4673
5269
|
indicator.style.color = "#f8fafc";
|
|
@@ -4681,17 +5277,25 @@ var DocPlugin = class {
|
|
|
4681
5277
|
indicator.style.userSelect = "none";
|
|
4682
5278
|
indicator.style.pointerEvents = "none";
|
|
4683
5279
|
indicator.style.textAlign = "center";
|
|
4684
|
-
indicator.style.width = "fit-content";
|
|
4685
|
-
indicator.style.margin = "16px auto 0";
|
|
4686
5280
|
container.appendChild(indicator);
|
|
4687
5281
|
}
|
|
5282
|
+
let rotation = 0;
|
|
5283
|
+
const applyTransform = () => {
|
|
5284
|
+
const activeCard = pageCards[currentPage - 1];
|
|
5285
|
+
if (activeCard) {
|
|
5286
|
+
activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5287
|
+
}
|
|
5288
|
+
};
|
|
4688
5289
|
const showPage = (pageNum) => {
|
|
4689
5290
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
card.style.display =
|
|
4693
|
-
|
|
4694
|
-
|
|
5291
|
+
pageCards.forEach((card, idx) => {
|
|
5292
|
+
if (idx + 1 === currentPage) {
|
|
5293
|
+
card.style.display = "block";
|
|
5294
|
+
card.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5295
|
+
} else {
|
|
5296
|
+
card.style.display = "none";
|
|
5297
|
+
}
|
|
5298
|
+
});
|
|
4695
5299
|
if (indicator) {
|
|
4696
5300
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4697
5301
|
}
|
|
@@ -4700,6 +5304,17 @@ var DocPlugin = class {
|
|
|
4700
5304
|
if (totalPages > 1) {
|
|
4701
5305
|
showPage(1);
|
|
4702
5306
|
}
|
|
5307
|
+
const calculateFitScale = () => {
|
|
5308
|
+
const elW = 816;
|
|
5309
|
+
const elH = 1056;
|
|
5310
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
5311
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
5312
|
+
return Math.min(1.1, Math.min(availW / elW, availH / elH));
|
|
5313
|
+
};
|
|
5314
|
+
setTimeout(() => {
|
|
5315
|
+
scale = calculateFitScale();
|
|
5316
|
+
applyTransform();
|
|
5317
|
+
}, 60);
|
|
4703
5318
|
const cleanup = () => {
|
|
4704
5319
|
indicator?.remove();
|
|
4705
5320
|
container.remove();
|
|
@@ -4712,21 +5327,30 @@ var DocPlugin = class {
|
|
|
4712
5327
|
getCurrentPage: () => currentPage,
|
|
4713
5328
|
goToPage: (page) => showPage(page),
|
|
4714
5329
|
zoomIn: () => {
|
|
4715
|
-
scale += 0.
|
|
4716
|
-
|
|
5330
|
+
scale += 0.15;
|
|
5331
|
+
applyTransform();
|
|
4717
5332
|
},
|
|
4718
5333
|
zoomOut: () => {
|
|
4719
|
-
scale = Math.max(0.2, scale - 0.
|
|
4720
|
-
|
|
5334
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
5335
|
+
applyTransform();
|
|
4721
5336
|
},
|
|
4722
5337
|
getZoom: () => scale,
|
|
4723
5338
|
setZoom: (level) => {
|
|
4724
5339
|
scale = level;
|
|
4725
|
-
|
|
5340
|
+
applyTransform();
|
|
4726
5341
|
},
|
|
4727
5342
|
fitToPage: () => {
|
|
4728
|
-
scale =
|
|
4729
|
-
|
|
5343
|
+
scale = calculateFitScale();
|
|
5344
|
+
rotation = 0;
|
|
5345
|
+
applyTransform();
|
|
5346
|
+
},
|
|
5347
|
+
rotateCW: () => {
|
|
5348
|
+
rotation = (rotation + 90) % 360;
|
|
5349
|
+
applyTransform();
|
|
5350
|
+
},
|
|
5351
|
+
rotateCCW: () => {
|
|
5352
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
5353
|
+
applyTransform();
|
|
4730
5354
|
},
|
|
4731
5355
|
copy: () => {
|
|
4732
5356
|
navigator.clipboard.writeText(extractedRawText);
|
|
@@ -4844,8 +5468,28 @@ var DocPlugin = class {
|
|
|
4844
5468
|
}
|
|
4845
5469
|
splitIntoPages(text) {
|
|
4846
5470
|
if (!text) return [""];
|
|
4847
|
-
const
|
|
4848
|
-
|
|
5471
|
+
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);
|
|
5472
|
+
if (explicitParts.length === 0) explicitParts.push(text);
|
|
5473
|
+
const maxLinesPerPage = 48;
|
|
5474
|
+
const finalPages = [];
|
|
5475
|
+
for (const part of explicitParts) {
|
|
5476
|
+
const lines = part.split(/\r?\n/);
|
|
5477
|
+
let currentLines = [];
|
|
5478
|
+
let count = 0;
|
|
5479
|
+
for (const line of lines) {
|
|
5480
|
+
currentLines.push(line);
|
|
5481
|
+
count++;
|
|
5482
|
+
if (count >= maxLinesPerPage) {
|
|
5483
|
+
finalPages.push(currentLines.join("\n"));
|
|
5484
|
+
currentLines = [];
|
|
5485
|
+
count = 0;
|
|
5486
|
+
}
|
|
5487
|
+
}
|
|
5488
|
+
if (currentLines.length > 0) {
|
|
5489
|
+
finalPages.push(currentLines.join("\n"));
|
|
5490
|
+
}
|
|
5491
|
+
}
|
|
5492
|
+
return finalPages.length > 0 ? finalPages : [text];
|
|
4849
5493
|
}
|
|
4850
5494
|
/**
|
|
4851
5495
|
* Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
|
|
@@ -4854,17 +5498,65 @@ var DocPlugin = class {
|
|
|
4854
5498
|
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
|
|
4855
5499
|
let html = "";
|
|
4856
5500
|
let inList = false;
|
|
4857
|
-
|
|
4858
|
-
|
|
5501
|
+
let tableLines = [];
|
|
5502
|
+
const flushTable = () => {
|
|
5503
|
+
if (tableLines.length > 0) {
|
|
5504
|
+
html += '<table style="width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 12px;">';
|
|
5505
|
+
for (const tLine of tableLines) {
|
|
5506
|
+
html += "<tr>";
|
|
5507
|
+
const cols = tLine.split(" ");
|
|
5508
|
+
for (const col of cols) {
|
|
5509
|
+
html += `<td style="border: 1px solid #cbd5e1; padding: 6px 8px;">${DOMPurify6.sanitize(col.trim())}</td>`;
|
|
5510
|
+
}
|
|
5511
|
+
html += "</tr>";
|
|
5512
|
+
}
|
|
5513
|
+
html += "</table>";
|
|
5514
|
+
tableLines = [];
|
|
5515
|
+
}
|
|
5516
|
+
};
|
|
5517
|
+
let i = 0;
|
|
5518
|
+
while (i < lines.length) {
|
|
5519
|
+
let line = lines[i];
|
|
5520
|
+
let tabCount = (line.match(/\t/g) || []).length;
|
|
5521
|
+
if (tabCount > 0) {
|
|
5522
|
+
let consecutiveTableLines = 1;
|
|
5523
|
+
let j = i + 1;
|
|
5524
|
+
while (j < lines.length) {
|
|
5525
|
+
const nextTabCount = (lines[j].match(/\t/g) || []).length;
|
|
5526
|
+
if (nextTabCount === tabCount) {
|
|
5527
|
+
consecutiveTableLines++;
|
|
5528
|
+
j++;
|
|
5529
|
+
} else {
|
|
5530
|
+
break;
|
|
5531
|
+
}
|
|
5532
|
+
}
|
|
5533
|
+
if (consecutiveTableLines >= 3) {
|
|
5534
|
+
if (inList) {
|
|
5535
|
+
html += "</ul>";
|
|
5536
|
+
inList = false;
|
|
5537
|
+
}
|
|
5538
|
+
tableLines = lines.slice(i, j);
|
|
5539
|
+
flushTable();
|
|
5540
|
+
i = j;
|
|
5541
|
+
continue;
|
|
5542
|
+
}
|
|
5543
|
+
}
|
|
5544
|
+
line = line.trim();
|
|
4859
5545
|
if (!line) {
|
|
4860
5546
|
if (inList) {
|
|
4861
5547
|
html += "</ul>";
|
|
4862
5548
|
inList = false;
|
|
4863
5549
|
}
|
|
5550
|
+
html += '<div style="height: 1.15em;"></div>';
|
|
5551
|
+
i++;
|
|
4864
5552
|
continue;
|
|
4865
5553
|
}
|
|
4866
|
-
if (/^[\x00-\x1F\x7F-\x9F]+$/.test(line))
|
|
4867
|
-
|
|
5554
|
+
if (/^[\x00-\x1F\x7F-\x9F]+$/.test(line)) {
|
|
5555
|
+
i++;
|
|
5556
|
+
continue;
|
|
5557
|
+
}
|
|
5558
|
+
if ((line.includes("Normal.dot") || line.includes("Microsoft Word") || line.includes("Times New Roman")) && line.length < 30) {
|
|
5559
|
+
i++;
|
|
4868
5560
|
continue;
|
|
4869
5561
|
}
|
|
4870
5562
|
if (line.length < 60 && !line.endsWith(".") && (/^[A-Z0-9\s:_-]+$/.test(line) || line.startsWith("#"))) {
|
|
@@ -4872,24 +5564,26 @@ var DocPlugin = class {
|
|
|
4872
5564
|
html += "</ul>";
|
|
4873
5565
|
inList = false;
|
|
4874
5566
|
}
|
|
4875
|
-
html += `<h2 style="font-size:
|
|
5567
|
+
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>`;
|
|
4876
5568
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
4877
5569
|
if (!inList) {
|
|
4878
5570
|
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
4879
5571
|
inList = true;
|
|
4880
5572
|
}
|
|
4881
5573
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
4882
|
-
html += `<li style="margin: 4px 0; line-height: 1.
|
|
5574
|
+
html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6.sanitize(bulletText)}</li>`;
|
|
4883
5575
|
} else {
|
|
4884
5576
|
if (inList) {
|
|
4885
5577
|
html += "</ul>";
|
|
4886
5578
|
inList = false;
|
|
4887
5579
|
}
|
|
4888
|
-
html += `<p style="line-height: 1.
|
|
5580
|
+
html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6.sanitize(line)}</p>`;
|
|
4889
5581
|
}
|
|
5582
|
+
i++;
|
|
4890
5583
|
}
|
|
4891
5584
|
if (inList) html += "</ul>";
|
|
4892
|
-
|
|
5585
|
+
flushTable();
|
|
5586
|
+
return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify6.sanitize(filename)})</p>`;
|
|
4893
5587
|
}
|
|
4894
5588
|
};
|
|
4895
5589
|
function docPlugin() {
|
|
@@ -4966,6 +5660,14 @@ var PptPlugin = class {
|
|
|
4966
5660
|
group: "zoom",
|
|
4967
5661
|
execute: () => instance.fitToPage?.()
|
|
4968
5662
|
},
|
|
5663
|
+
{
|
|
5664
|
+
id: "rotate-cw",
|
|
5665
|
+
icon: "rotate-cw",
|
|
5666
|
+
label: "Rotate",
|
|
5667
|
+
type: "button",
|
|
5668
|
+
group: "view",
|
|
5669
|
+
execute: () => instance.rotateCW?.()
|
|
5670
|
+
},
|
|
4969
5671
|
{
|
|
4970
5672
|
id: "download",
|
|
4971
5673
|
icon: "download",
|
|
@@ -4999,22 +5701,36 @@ var PptPlugin = class {
|
|
|
4999
5701
|
const slideCard = document.createElement("div");
|
|
5000
5702
|
slideCard.className = "fp-ppt-slide-card";
|
|
5001
5703
|
slideCard.style.width = "960px";
|
|
5002
|
-
slideCard.style.maxWidth = "
|
|
5704
|
+
slideCard.style.maxWidth = "calc(100% - 32px)";
|
|
5705
|
+
slideCard.style.maxHeight = "calc(100% - 48px)";
|
|
5003
5706
|
slideCard.style.aspectRatio = "16 / 9";
|
|
5004
5707
|
slideCard.style.backgroundColor = "#ffffff";
|
|
5005
5708
|
slideCard.style.boxShadow = "0 12px 40px rgba(0,0,0,0.35)";
|
|
5006
5709
|
slideCard.style.borderRadius = "8px";
|
|
5007
5710
|
slideCard.style.boxSizing = "border-box";
|
|
5008
5711
|
slideCard.style.position = "relative";
|
|
5009
|
-
slideCard.style.overflow = "hidden";
|
|
5010
|
-
slideCard.style.transformOrigin = "center center";
|
|
5011
5712
|
slideCard.style.transition = "transform 0.2s ease";
|
|
5713
|
+
slideCard.style.transformOrigin = "center center";
|
|
5714
|
+
slideCard.style.flexShrink = "0";
|
|
5012
5715
|
container.appendChild(slideCard);
|
|
5013
5716
|
ctx.container.appendChild(container);
|
|
5014
5717
|
let scale = 1;
|
|
5718
|
+
let rotation = 0;
|
|
5015
5719
|
let currentSlide = 1;
|
|
5016
5720
|
let slides = [];
|
|
5017
5721
|
const createdBlobUrls = [];
|
|
5722
|
+
const calculateFitScale = () => {
|
|
5723
|
+
const availW = Math.max(200, container.clientWidth - 48);
|
|
5724
|
+
const availH = Math.max(200, container.clientHeight - 72);
|
|
5725
|
+
return Math.min(1, Math.min(availW / 960, availH / 540));
|
|
5726
|
+
};
|
|
5727
|
+
const applyTransform = () => {
|
|
5728
|
+
slideCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5729
|
+
};
|
|
5730
|
+
setTimeout(() => {
|
|
5731
|
+
scale = calculateFitScale();
|
|
5732
|
+
applyTransform();
|
|
5733
|
+
}, 60);
|
|
5018
5734
|
try {
|
|
5019
5735
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
5020
5736
|
const pptStream = cfbf.readStream("PowerPoint Document");
|
|
@@ -5045,7 +5761,7 @@ var PptPlugin = class {
|
|
|
5045
5761
|
if (s.pictureUrl) {
|
|
5046
5762
|
contentHtml = `
|
|
5047
5763
|
<div style="flex: 1; display: flex; justify-content: center; align-items: center; padding: 12px; overflow: hidden;">
|
|
5048
|
-
<img src="${s.pictureUrl}" alt="${
|
|
5764
|
+
<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;" />
|
|
5049
5765
|
</div>
|
|
5050
5766
|
`;
|
|
5051
5767
|
} else if (s.tableColumns.length > 0) {
|
|
@@ -5055,7 +5771,7 @@ var PptPlugin = class {
|
|
|
5055
5771
|
<table style="width: 100%; border-collapse: collapse; border: 1px solid #cbd5e1; border-radius: 6px; overflow: hidden; background: #ffffff;">
|
|
5056
5772
|
<thead>
|
|
5057
5773
|
<tr style="background: #e2e8f0; color: #1e293b; font-weight: 600; font-size: 14px;">
|
|
5058
|
-
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${
|
|
5774
|
+
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify6.sanitize(c)}</th>`).join("")}
|
|
5059
5775
|
</tr>
|
|
5060
5776
|
</thead>
|
|
5061
5777
|
<tbody>
|
|
@@ -5071,7 +5787,7 @@ var PptPlugin = class {
|
|
|
5071
5787
|
} else {
|
|
5072
5788
|
const pTags = s.paragraphs.map((p) => {
|
|
5073
5789
|
const lines = p.split(/[\r\n]+/).map((l) => l.trim()).filter(Boolean);
|
|
5074
|
-
return lines.map((l) => `<p style="margin: 0 0 14px; font-size: 14px; line-height: 1.65; color: #334155; text-align: justify;">${
|
|
5790
|
+
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("");
|
|
5075
5791
|
}).join("");
|
|
5076
5792
|
contentHtml = `
|
|
5077
5793
|
<div style="flex: 1; overflow: auto; padding: 4px 8px; display: flex; flex-direction: column; justify-content: flex-start;">
|
|
@@ -5084,11 +5800,11 @@ var PptPlugin = class {
|
|
|
5084
5800
|
<!-- Header Banner matching PowerPoint design -->
|
|
5085
5801
|
<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;">
|
|
5086
5802
|
<h1 style="margin: 0; font-size: 26px; font-weight: 700; color: #1e293b; letter-spacing: -0.3px;">
|
|
5087
|
-
${
|
|
5803
|
+
${DOMPurify6.sanitize(s.title)}
|
|
5088
5804
|
</h1>
|
|
5089
5805
|
${s.subtitle ? `
|
|
5090
5806
|
<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);">
|
|
5091
|
-
${
|
|
5807
|
+
${DOMPurify6.sanitize(s.subtitle)}
|
|
5092
5808
|
</span>
|
|
5093
5809
|
` : `
|
|
5094
5810
|
<span style="font-size: 12px; color: #365314; font-weight: 600;">
|
|
@@ -5115,21 +5831,30 @@ var PptPlugin = class {
|
|
|
5115
5831
|
return {
|
|
5116
5832
|
destroy: cleanup,
|
|
5117
5833
|
zoomIn: () => {
|
|
5118
|
-
scale += 0.
|
|
5119
|
-
|
|
5834
|
+
scale += 0.15;
|
|
5835
|
+
applyTransform();
|
|
5120
5836
|
},
|
|
5121
5837
|
zoomOut: () => {
|
|
5122
|
-
scale = Math.max(0.
|
|
5123
|
-
|
|
5838
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
5839
|
+
applyTransform();
|
|
5124
5840
|
},
|
|
5125
5841
|
getZoom: () => scale,
|
|
5126
5842
|
setZoom: (level) => {
|
|
5127
5843
|
scale = level;
|
|
5128
|
-
|
|
5844
|
+
applyTransform();
|
|
5129
5845
|
},
|
|
5130
5846
|
fitToPage: () => {
|
|
5131
|
-
scale =
|
|
5132
|
-
|
|
5847
|
+
scale = calculateFitScale();
|
|
5848
|
+
rotation = 0;
|
|
5849
|
+
applyTransform();
|
|
5850
|
+
},
|
|
5851
|
+
rotateCW: () => {
|
|
5852
|
+
rotation = (rotation + 90) % 360;
|
|
5853
|
+
applyTransform();
|
|
5854
|
+
},
|
|
5855
|
+
rotateCCW: () => {
|
|
5856
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
5857
|
+
applyTransform();
|
|
5133
5858
|
},
|
|
5134
5859
|
goToPage: (page) => {
|
|
5135
5860
|
if (page >= 1 && page <= totalSlides) {
|