@files-preview-app/preview-file 1.2.6 → 1.2.8
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 +665 -200
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.js +664 -199
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +666 -201
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +665 -200
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +665 -200
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +664 -199
- package/dist/react.js.map +1 -1
- package/dist/vue.cjs +665 -200
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +664 -199
- package/dist/vue.js.map +1 -1
- package/package.json +179 -169
package/dist/react.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { memo, forwardRef, useRef, useImperativeHandle, useEffect } from 'react';
|
|
2
|
-
import
|
|
2
|
+
import DOMPurify6 from 'dompurify';
|
|
3
3
|
import * as pdfjsLib from 'pdfjs-dist';
|
|
4
4
|
import * as docx from 'docx-preview';
|
|
5
5
|
import { unzipSync, strFromU8, unzip } from 'fflate';
|
|
@@ -358,7 +358,7 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
358
358
|
if (magicMime === "application/zip") {
|
|
359
359
|
const ooxmlMime = detectOoxmlType(buffer);
|
|
360
360
|
if (ooxmlMime && ooxmlMime !== "application/zip") {
|
|
361
|
-
metadata.mimeType = ooxmlMime;
|
|
361
|
+
metadata.mimeType = metadata.mimeType ?? ooxmlMime;
|
|
362
362
|
if (ooxmlMime.includes("wordprocessing")) metadata.extension = metadata.extension ?? ".docx";
|
|
363
363
|
else if (ooxmlMime.includes("spreadsheet")) metadata.extension = metadata.extension ?? ".xlsx";
|
|
364
364
|
else if (ooxmlMime.includes("presentation")) metadata.extension = metadata.extension ?? ".pptx";
|
|
@@ -387,7 +387,7 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
387
387
|
return { buffer, metadata };
|
|
388
388
|
}
|
|
389
389
|
function sanitizeSVG(svg) {
|
|
390
|
-
return
|
|
390
|
+
return DOMPurify6.sanitize(svg, {
|
|
391
391
|
USE_PROFILES: { svg: true, svgFilters: true }
|
|
392
392
|
});
|
|
393
393
|
}
|
|
@@ -434,7 +434,8 @@ function createElement(tag, attrs, ...children) {
|
|
|
434
434
|
}
|
|
435
435
|
var ICON_ZOOM_IN = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line><line x1="11" y1="8" x2="11" y2="14"></line><line x1="8" y1="11" x2="14" y2="11"></line></svg>`;
|
|
436
436
|
var ICON_ZOOM_OUT = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line><line x1="8" y1="11" x2="14" y2="11"></line></svg>`;
|
|
437
|
-
var ICON_FIT_PAGE = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><
|
|
437
|
+
var ICON_FIT_PAGE = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"></rect><line x1="8" y1="12" x2="16" y2="12"></line><polyline points="11 9 8 12 11 15"></polyline><polyline points="13 9 16 12 13 15"></polyline></svg>`;
|
|
438
|
+
var ICON_FIT_WIDTH = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="2" y1="12" x2="22" y2="12"></line><polyline points="5 9 2 12 5 15"></polyline><polyline points="19 9 22 12 19 15"></polyline><line x1="2" y1="5" x2="2" y2="19"></line><line x1="22" y1="5" x2="22" y2="19"></line></svg>`;
|
|
438
439
|
var ICON_ROTATE_CW = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"></polyline><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path></svg>`;
|
|
439
440
|
var ICON_ROTATE_CCW = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="1 4 1 10 7 10"></polyline><path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"></path></svg>`;
|
|
440
441
|
var ICON_DOWNLOAD = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>`;
|
|
@@ -454,6 +455,7 @@ var ICON_MAP = {
|
|
|
454
455
|
"zoom-in": ICON_ZOOM_IN,
|
|
455
456
|
"zoom-out": ICON_ZOOM_OUT,
|
|
456
457
|
"fit-page": ICON_FIT_PAGE,
|
|
458
|
+
"fit-width": ICON_FIT_WIDTH,
|
|
457
459
|
"fit-slide": ICON_FIT_PAGE,
|
|
458
460
|
"rotate-cw": ICON_ROTATE_CW,
|
|
459
461
|
"rotate-ccw": ICON_ROTATE_CCW,
|
|
@@ -1400,6 +1402,7 @@ var PdfPlugin = class {
|
|
|
1400
1402
|
let currentPage = 1;
|
|
1401
1403
|
let zoomScale = 1;
|
|
1402
1404
|
let rotation = 0;
|
|
1405
|
+
let fitMode = "width";
|
|
1403
1406
|
let currentRenderTask = null;
|
|
1404
1407
|
const renderPage = async (pageNum) => {
|
|
1405
1408
|
if (currentRenderTask) {
|
|
@@ -1419,11 +1422,16 @@ var PdfPlugin = class {
|
|
|
1419
1422
|
const containerWidth = container.clientWidth || 900;
|
|
1420
1423
|
const containerHeight = container.clientHeight || 700;
|
|
1421
1424
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1422
|
-
const availWidth = Math.max(
|
|
1423
|
-
const availHeight = Math.max(
|
|
1425
|
+
const availWidth = Math.max(280, containerWidth - 48);
|
|
1426
|
+
const availHeight = Math.max(280, containerHeight - 88);
|
|
1424
1427
|
const scaleW = availWidth / unscaledVp.width;
|
|
1425
1428
|
const scaleH = availHeight / unscaledVp.height;
|
|
1426
|
-
|
|
1429
|
+
let fitScale;
|
|
1430
|
+
if (fitMode === "page") {
|
|
1431
|
+
fitScale = Math.max(0.5, Math.min(scaleW, scaleH));
|
|
1432
|
+
} else {
|
|
1433
|
+
fitScale = Math.max(0.65, Math.min(1.15, scaleW));
|
|
1434
|
+
}
|
|
1427
1435
|
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1428
1436
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
1429
1437
|
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
@@ -1449,7 +1457,19 @@ var PdfPlugin = class {
|
|
|
1449
1457
|
}
|
|
1450
1458
|
};
|
|
1451
1459
|
await renderPage(1);
|
|
1460
|
+
let resizeTimer = null;
|
|
1461
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
1462
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1463
|
+
resizeTimer = setTimeout(() => {
|
|
1464
|
+
if (Math.abs(zoomScale - 1) < 0.05) {
|
|
1465
|
+
renderPage(currentPage);
|
|
1466
|
+
}
|
|
1467
|
+
}, 150);
|
|
1468
|
+
});
|
|
1469
|
+
resizeObserver.observe(container);
|
|
1452
1470
|
const cleanup = () => {
|
|
1471
|
+
resizeObserver.disconnect();
|
|
1472
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1453
1473
|
if (currentRenderTask) {
|
|
1454
1474
|
try {
|
|
1455
1475
|
currentRenderTask.cancel();
|
|
@@ -1480,6 +1500,7 @@ var PdfPlugin = class {
|
|
|
1480
1500
|
renderPage(currentPage);
|
|
1481
1501
|
},
|
|
1482
1502
|
fitToPage: () => {
|
|
1503
|
+
fitMode = fitMode === "width" ? "page" : "width";
|
|
1483
1504
|
zoomScale = 1;
|
|
1484
1505
|
rotation = 0;
|
|
1485
1506
|
renderPage(currentPage);
|
|
@@ -2033,8 +2054,53 @@ var DocxPlugin = class {
|
|
|
2033
2054
|
}
|
|
2034
2055
|
}
|
|
2035
2056
|
}
|
|
2036
|
-
|
|
2037
|
-
const cards = wrapper.querySelectorAll(".fp-docx-page-card");
|
|
2057
|
+
let sections = Array.from(wrapper.querySelectorAll("section.docx"));
|
|
2058
|
+
const cards = Array.from(wrapper.querySelectorAll(".fp-docx-page-card"));
|
|
2059
|
+
if (sections.length === 1 && cards.length === 0) {
|
|
2060
|
+
const singleSec = sections[0];
|
|
2061
|
+
const pageH = 1056;
|
|
2062
|
+
const secH = singleSec.offsetHeight || singleSec.scrollHeight;
|
|
2063
|
+
if (secH > pageH * 1.25) {
|
|
2064
|
+
const children = Array.from(singleSec.children);
|
|
2065
|
+
if (children.length > 1) {
|
|
2066
|
+
const parent = singleSec.parentElement || wrapper;
|
|
2067
|
+
const newSections = [singleSec];
|
|
2068
|
+
singleSec.innerHTML = "";
|
|
2069
|
+
singleSec.style.minHeight = `${pageH}px`;
|
|
2070
|
+
singleSec.style.maxHeight = `${pageH}px`;
|
|
2071
|
+
singleSec.style.overflow = "hidden";
|
|
2072
|
+
singleSec.style.boxSizing = "border-box";
|
|
2073
|
+
let curSec = singleSec;
|
|
2074
|
+
let curH = 0;
|
|
2075
|
+
const maxH = pageH - 96;
|
|
2076
|
+
for (let i = 0; i < children.length; i++) {
|
|
2077
|
+
const child = children[i];
|
|
2078
|
+
curSec.appendChild(child);
|
|
2079
|
+
const chH = child.offsetHeight || 28;
|
|
2080
|
+
curH += chH;
|
|
2081
|
+
if (curH >= maxH && i < children.length - 1) {
|
|
2082
|
+
const nextSec = document.createElement("section");
|
|
2083
|
+
nextSec.className = singleSec.className;
|
|
2084
|
+
nextSec.style.cssText = singleSec.style.cssText;
|
|
2085
|
+
nextSec.style.width = singleSec.style.width || "816px";
|
|
2086
|
+
nextSec.style.minHeight = `${pageH}px`;
|
|
2087
|
+
nextSec.style.maxHeight = `${pageH}px`;
|
|
2088
|
+
nextSec.style.overflow = "hidden";
|
|
2089
|
+
nextSec.style.boxSizing = "border-box";
|
|
2090
|
+
nextSec.style.backgroundColor = "#ffffff";
|
|
2091
|
+
nextSec.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
|
|
2092
|
+
nextSec.style.borderRadius = "4px";
|
|
2093
|
+
nextSec.style.marginBottom = "24px";
|
|
2094
|
+
parent.appendChild(nextSec);
|
|
2095
|
+
newSections.push(nextSec);
|
|
2096
|
+
curSec = nextSec;
|
|
2097
|
+
curH = 0;
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
sections = newSections;
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2038
2104
|
const pageElements = sections.length > 0 ? sections : cards;
|
|
2039
2105
|
const totalPages = Math.max(1, pageElements.length);
|
|
2040
2106
|
let currentPage = 1;
|
|
@@ -2078,22 +2144,27 @@ var DocxPlugin = class {
|
|
|
2078
2144
|
}
|
|
2079
2145
|
scale = 1;
|
|
2080
2146
|
let rotation = 0;
|
|
2081
|
-
|
|
2147
|
+
let fitMode = "width";
|
|
2148
|
+
const calculateFitScale = (mode = fitMode) => {
|
|
2082
2149
|
const activeEl = pageElements[currentPage - 1] || wrapper.firstElementChild || wrapper;
|
|
2083
2150
|
const elW = activeEl.offsetWidth || 816;
|
|
2084
|
-
const
|
|
2085
|
-
const availW = Math.max(
|
|
2086
|
-
const availH = Math.max(
|
|
2151
|
+
const singlePageH = Math.min(activeEl.offsetHeight || 1056, Math.round(elW * 1.32));
|
|
2152
|
+
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
2153
|
+
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
2087
2154
|
const sW = availW / elW;
|
|
2088
|
-
const sH = availH /
|
|
2089
|
-
|
|
2155
|
+
const sH = availH / singlePageH;
|
|
2156
|
+
if (mode === "page") {
|
|
2157
|
+
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
2158
|
+
}
|
|
2159
|
+
return Math.max(0.65, Math.min(1.05, sW));
|
|
2090
2160
|
};
|
|
2091
2161
|
const applyTransform = () => {
|
|
2092
2162
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2093
2163
|
wrapper.style.transformOrigin = "top center";
|
|
2094
2164
|
};
|
|
2095
2165
|
setTimeout(() => {
|
|
2096
|
-
|
|
2166
|
+
fitMode = "width";
|
|
2167
|
+
scale = calculateFitScale("width");
|
|
2097
2168
|
applyTransform();
|
|
2098
2169
|
}, 60);
|
|
2099
2170
|
const cleanup = () => {
|
|
@@ -2127,7 +2198,8 @@ var DocxPlugin = class {
|
|
|
2127
2198
|
applyTransform();
|
|
2128
2199
|
},
|
|
2129
2200
|
fitToPage: () => {
|
|
2130
|
-
|
|
2201
|
+
fitMode = fitMode === "width" ? "page" : "width";
|
|
2202
|
+
scale = calculateFitScale(fitMode);
|
|
2131
2203
|
rotation = 0;
|
|
2132
2204
|
applyTransform();
|
|
2133
2205
|
},
|
|
@@ -2197,90 +2269,149 @@ var DocxPlugin = class {
|
|
|
2197
2269
|
console.warn("[DocxPlugin] Error parsing relationships:", relsErr);
|
|
2198
2270
|
}
|
|
2199
2271
|
}
|
|
2200
|
-
const
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2272
|
+
const sectPrs = Array.from(doc.getElementsByTagNameNS("*", "sectPr"));
|
|
2273
|
+
const lastSectPr = sectPrs[sectPrs.length - 1];
|
|
2274
|
+
let defaultW = 12240;
|
|
2275
|
+
let defaultH = 15840;
|
|
2276
|
+
let margins = { top: 1440, right: 1440, bottom: 1440, left: 1440 };
|
|
2277
|
+
if (lastSectPr) {
|
|
2278
|
+
const pgSz = lastSectPr.getElementsByTagNameNS("*", "pgSz")[0];
|
|
2279
|
+
if (pgSz) {
|
|
2280
|
+
defaultW = parseInt(pgSz.getAttribute("w:w") || pgSz.getAttribute("w") || "12240", 10);
|
|
2281
|
+
defaultH = parseInt(pgSz.getAttribute("w:h") || pgSz.getAttribute("h") || "15840", 10);
|
|
2282
|
+
}
|
|
2283
|
+
const pgMar = lastSectPr.getElementsByTagNameNS("*", "pgMar")[0];
|
|
2284
|
+
if (pgMar) {
|
|
2285
|
+
margins.top = parseInt(pgMar.getAttribute("w:top") || pgMar.getAttribute("top") || "1440", 10);
|
|
2286
|
+
margins.bottom = parseInt(pgMar.getAttribute("w:bottom") || pgMar.getAttribute("bottom") || "1440", 10);
|
|
2287
|
+
margins.left = parseInt(pgMar.getAttribute("w:left") || pgMar.getAttribute("left") || "1440", 10);
|
|
2288
|
+
margins.right = parseInt(pgMar.getAttribute("w:right") || pgMar.getAttribute("right") || "1440", 10);
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
const createPageCard = () => {
|
|
2292
|
+
const card = document.createElement("div");
|
|
2293
|
+
card.className = "fp-docx-page-card";
|
|
2294
|
+
card.style.backgroundColor = "#ffffff";
|
|
2295
|
+
card.style.borderRadius = "4px";
|
|
2296
|
+
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
2297
|
+
card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
2298
|
+
card.style.color = "#1e293b";
|
|
2299
|
+
card.style.lineHeight = "1.6";
|
|
2300
|
+
card.style.boxSizing = "border-box";
|
|
2301
|
+
card.style.overflow = "hidden";
|
|
2302
|
+
card.style.position = "relative";
|
|
2303
|
+
card.style.marginBottom = "24px";
|
|
2304
|
+
card.style.width = `${defaultW / 15}px`;
|
|
2305
|
+
card.style.height = `${defaultH / 15}px`;
|
|
2306
|
+
card.style.padding = `${margins.top / 15}px ${margins.right / 15}px ${margins.bottom / 15}px ${margins.left / 15}px`;
|
|
2307
|
+
return card;
|
|
2308
|
+
};
|
|
2309
|
+
let currentCard = createPageCard();
|
|
2310
|
+
let currentHtml = "";
|
|
2311
|
+
const pages = [{ card: currentCard, html: "" }];
|
|
2312
|
+
const flushHtml = () => {
|
|
2313
|
+
pages[pages.length - 1].html += currentHtml;
|
|
2314
|
+
currentHtml = "";
|
|
2315
|
+
};
|
|
2316
|
+
const newPage = () => {
|
|
2317
|
+
flushHtml();
|
|
2318
|
+
currentCard = createPageCard();
|
|
2319
|
+
pages.push({ card: currentCard, html: "" });
|
|
2320
|
+
};
|
|
2209
2321
|
const body = doc.getElementsByTagNameNS("*", "body")[0] || doc.documentElement;
|
|
2210
|
-
let html = "";
|
|
2211
2322
|
for (const child of Array.from(body.children)) {
|
|
2212
2323
|
const tag = child.localName || child.nodeName.split(":").pop();
|
|
2213
2324
|
if (tag === "p") {
|
|
2214
2325
|
const pStyle = child.getElementsByTagNameNS("*", "pStyle")[0];
|
|
2215
2326
|
const styleVal = pStyle?.getAttribute("w:val") || pStyle?.getAttribute("val") || "";
|
|
2216
2327
|
const numPr = child.getElementsByTagNameNS("*", "numPr")[0];
|
|
2217
|
-
const
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2328
|
+
const chunks = this.extractParagraphChunks(child, imageMap);
|
|
2329
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
2330
|
+
if (i > 0) {
|
|
2331
|
+
newPage();
|
|
2332
|
+
}
|
|
2333
|
+
const textContent = chunks[i];
|
|
2334
|
+
if (!textContent.trim() && !textContent.includes("<img")) {
|
|
2335
|
+
currentHtml += '<div style="height: 10px;"></div>';
|
|
2336
|
+
continue;
|
|
2337
|
+
}
|
|
2338
|
+
const lowerStyle = styleVal.toLowerCase();
|
|
2339
|
+
if (lowerStyle.includes("title")) {
|
|
2340
|
+
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>`;
|
|
2341
|
+
} else if (lowerStyle.includes("heading1") || styleVal === "1") {
|
|
2342
|
+
currentHtml += `<h2 style="font-size: 22px; font-weight: 700; color: #1e40af; margin: 20px 0 10px;">${textContent}</h2>`;
|
|
2343
|
+
} else if (lowerStyle.includes("heading2") || styleVal === "2") {
|
|
2344
|
+
currentHtml += `<h3 style="font-size: 18px; font-weight: 600; color: #2563eb; margin: 16px 0 8px;">${textContent}</h3>`;
|
|
2345
|
+
} else if (lowerStyle.includes("heading3") || styleVal === "3") {
|
|
2346
|
+
currentHtml += `<h4 style="font-size: 15px; font-weight: 600; color: #334155; margin: 12px 0 6px;">${textContent}</h4>`;
|
|
2347
|
+
} else if (numPr) {
|
|
2348
|
+
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>`;
|
|
2349
|
+
} else {
|
|
2350
|
+
currentHtml += `<p style="margin: 8px 0; font-size: 14px;">${textContent}</p>`;
|
|
2351
|
+
}
|
|
2235
2352
|
}
|
|
2236
2353
|
} else if (tag === "tbl") {
|
|
2237
|
-
|
|
2354
|
+
currentHtml += '<table style="width: 100%; border-collapse: collapse; margin: 20px 0; border: 1px solid #cbd5e1;">';
|
|
2238
2355
|
const rows = Array.from(child.getElementsByTagNameNS("*", "tr"));
|
|
2239
2356
|
rows.forEach((tr, rIdx) => {
|
|
2240
|
-
|
|
2357
|
+
currentHtml += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
|
|
2241
2358
|
const cells = Array.from(tr.getElementsByTagNameNS("*", "tc"));
|
|
2242
2359
|
cells.forEach((tc) => {
|
|
2243
2360
|
const cellText = this.extractParagraphHtml(tc, imageMap);
|
|
2244
|
-
|
|
2361
|
+
currentHtml += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || " "}</td>`;
|
|
2245
2362
|
});
|
|
2246
|
-
|
|
2363
|
+
currentHtml += "</tr>";
|
|
2247
2364
|
});
|
|
2248
|
-
|
|
2365
|
+
currentHtml += "</table>";
|
|
2249
2366
|
}
|
|
2250
2367
|
}
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2368
|
+
flushHtml();
|
|
2369
|
+
for (const page of pages) {
|
|
2370
|
+
page.card.innerHTML = DOMPurify6.sanitize(page.html, {
|
|
2371
|
+
ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "s", "strike", "img", "div", "br"],
|
|
2372
|
+
ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
|
|
2373
|
+
});
|
|
2374
|
+
wrapper.appendChild(page.card);
|
|
2375
|
+
}
|
|
2256
2376
|
}
|
|
2257
2377
|
extractParagraphHtml(pElement, imageMap = {}) {
|
|
2258
|
-
|
|
2378
|
+
return this.extractParagraphChunks(pElement, imageMap).join("<br/>");
|
|
2379
|
+
}
|
|
2380
|
+
extractParagraphChunks(pElement, imageMap = {}) {
|
|
2381
|
+
const chunks = [""];
|
|
2382
|
+
let currentChunkIndex = 0;
|
|
2259
2383
|
const drawings = Array.from(pElement.getElementsByTagNameNS("*", "drawing"));
|
|
2260
2384
|
for (const drawing of drawings) {
|
|
2261
2385
|
const blip = drawing.getElementsByTagNameNS("*", "blip")[0];
|
|
2262
2386
|
const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
|
|
2263
2387
|
if (rId && imageMap[rId]) {
|
|
2264
|
-
|
|
2388
|
+
chunks[currentChunkIndex] += `<div style="text-align:center; margin: 12px 0;"><img src="${imageMap[rId]}" style="max-width: 100%; height: auto; border-radius: 4px;" /></div>`;
|
|
2265
2389
|
}
|
|
2266
2390
|
}
|
|
2267
2391
|
const runs = Array.from(pElement.getElementsByTagNameNS("*", "r"));
|
|
2268
|
-
if (runs.length === 0 && !
|
|
2269
|
-
|
|
2392
|
+
if (runs.length === 0 && !chunks[currentChunkIndex]) {
|
|
2393
|
+
chunks[currentChunkIndex] = DOMPurify6.sanitize(pElement.textContent || "");
|
|
2394
|
+
return chunks;
|
|
2270
2395
|
}
|
|
2271
2396
|
for (const r of runs) {
|
|
2272
2397
|
const blip = r.getElementsByTagNameNS("*", "blip")[0] || r.getElementsByTagNameNS("*", "imagedata")[0];
|
|
2273
2398
|
const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
|
|
2274
2399
|
if (rId && imageMap[rId]) {
|
|
2275
|
-
|
|
2400
|
+
chunks[currentChunkIndex] += `<img src="${imageMap[rId]}" style="max-width: 100%; height: auto; display: inline-block; margin: 4px;" />`;
|
|
2276
2401
|
}
|
|
2277
|
-
const brs = r.getElementsByTagNameNS("*", "br");
|
|
2278
|
-
for (
|
|
2279
|
-
|
|
2402
|
+
const brs = Array.from(r.getElementsByTagNameNS("*", "br"));
|
|
2403
|
+
for (const br of brs) {
|
|
2404
|
+
const type = br.getAttribute("w:type") || br.getAttribute("type");
|
|
2405
|
+
if (type === "page") {
|
|
2406
|
+
chunks.push("");
|
|
2407
|
+
currentChunkIndex++;
|
|
2408
|
+
} else {
|
|
2409
|
+
chunks[currentChunkIndex] += "<br/>";
|
|
2410
|
+
}
|
|
2280
2411
|
}
|
|
2281
2412
|
const tabs = r.getElementsByTagNameNS("*", "tab");
|
|
2282
2413
|
if (tabs.length > 0) {
|
|
2283
|
-
|
|
2414
|
+
chunks[currentChunkIndex] += " ";
|
|
2284
2415
|
}
|
|
2285
2416
|
const rPr = r.getElementsByTagNameNS("*", "rPr")[0];
|
|
2286
2417
|
const isBold = !!rPr?.getElementsByTagNameNS("*", "b")[0];
|
|
@@ -2294,7 +2425,7 @@ var DocxPlugin = class {
|
|
|
2294
2425
|
const texts = Array.from(r.getElementsByTagNameNS("*", "t"));
|
|
2295
2426
|
let text = texts.map((t) => t.textContent || "").join("");
|
|
2296
2427
|
if (!text) continue;
|
|
2297
|
-
text =
|
|
2428
|
+
text = DOMPurify6.sanitize(text);
|
|
2298
2429
|
let styles = "";
|
|
2299
2430
|
if (isBold) styles += "font-weight: bold; ";
|
|
2300
2431
|
if (isItalic) styles += "font-style: italic; ";
|
|
@@ -2306,12 +2437,12 @@ var DocxPlugin = class {
|
|
|
2306
2437
|
if (!isNaN(pt) && pt > 0) styles += `font-size: ${pt}pt; `;
|
|
2307
2438
|
}
|
|
2308
2439
|
if (styles) {
|
|
2309
|
-
|
|
2440
|
+
chunks[currentChunkIndex] += `<span style="${styles}">${text}</span>`;
|
|
2310
2441
|
} else {
|
|
2311
|
-
|
|
2442
|
+
chunks[currentChunkIndex] += text;
|
|
2312
2443
|
}
|
|
2313
2444
|
}
|
|
2314
|
-
return
|
|
2445
|
+
return chunks;
|
|
2315
2446
|
}
|
|
2316
2447
|
renderBinaryDocFallback(ctx, wrapper) {
|
|
2317
2448
|
const card = document.createElement("div");
|
|
@@ -2328,14 +2459,14 @@ var DocxPlugin = class {
|
|
|
2328
2459
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
2329
2460
|
if (wordDocStream && wordDocStream.length >= 512) {
|
|
2330
2461
|
const text2 = this.extractReadableStrings(wordDocStream);
|
|
2331
|
-
card.innerHTML = `<div style="white-space: pre-wrap;">${
|
|
2462
|
+
card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6.sanitize(text2)}</div>`;
|
|
2332
2463
|
wrapper.appendChild(card);
|
|
2333
2464
|
return;
|
|
2334
2465
|
}
|
|
2335
2466
|
} catch {
|
|
2336
2467
|
}
|
|
2337
2468
|
const text = this.extractReadableStrings(new Uint8Array(ctx.buffer));
|
|
2338
|
-
card.innerHTML = `<div style="white-space: pre-wrap;">${
|
|
2469
|
+
card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6.sanitize(text)}</div>`;
|
|
2339
2470
|
wrapper.appendChild(card);
|
|
2340
2471
|
}
|
|
2341
2472
|
extractReadableStrings(bytes) {
|
|
@@ -2512,11 +2643,9 @@ var ExcelPlugin = class {
|
|
|
2512
2643
|
const calculateFitScale = () => {
|
|
2513
2644
|
const table = contentArea.querySelector("table");
|
|
2514
2645
|
if (!table) return 1;
|
|
2515
|
-
const availW = Math.max(
|
|
2516
|
-
const availH = Math.max(200, container.clientHeight - 80);
|
|
2646
|
+
const availW = Math.max(280, container.clientWidth - 48);
|
|
2517
2647
|
const tW = table.offsetWidth || 800;
|
|
2518
|
-
|
|
2519
|
-
return Math.min(1, Math.min(availW / tW, availH / tH));
|
|
2648
|
+
return Math.max(0.65, Math.min(1, availW / tW));
|
|
2520
2649
|
};
|
|
2521
2650
|
try {
|
|
2522
2651
|
wb = XLSX.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
|
|
@@ -2934,41 +3063,94 @@ var CodePlugin = class {
|
|
|
2934
3063
|
async render(ctx) {
|
|
2935
3064
|
const decoder = new TextDecoder("utf-8");
|
|
2936
3065
|
const fullText = decoder.decode(ctx.buffer);
|
|
2937
|
-
const
|
|
2938
|
-
const
|
|
3066
|
+
const extRaw = ctx.metadata.extension?.toLowerCase();
|
|
3067
|
+
const mimeRaw = ctx.metadata.mimeType?.toLowerCase();
|
|
3068
|
+
const isTxt = extRaw === ".txt" || mimeRaw === "text/plain" && (!extRaw || !this.extensions.filter((e) => e !== ".txt").includes(extRaw));
|
|
3069
|
+
let rawPages = [];
|
|
3070
|
+
if (isTxt) {
|
|
3071
|
+
const explicitPages = fullText.split(/(?:\f|\x0C)/);
|
|
3072
|
+
for (const ep of explicitPages) {
|
|
3073
|
+
const lines = ep.split(/\r?\n/);
|
|
3074
|
+
let currentChunk = [];
|
|
3075
|
+
for (let i = 0; i < lines.length; i++) {
|
|
3076
|
+
currentChunk.push(lines[i]);
|
|
3077
|
+
if (currentChunk.length >= 46) {
|
|
3078
|
+
rawPages.push(currentChunk.join("\n"));
|
|
3079
|
+
currentChunk = [];
|
|
3080
|
+
}
|
|
3081
|
+
}
|
|
3082
|
+
if (currentChunk.length > 0 || lines.length === 0) {
|
|
3083
|
+
rawPages.push(currentChunk.join("\n"));
|
|
3084
|
+
}
|
|
3085
|
+
}
|
|
3086
|
+
if (rawPages.length === 0) rawPages = [""];
|
|
3087
|
+
} else {
|
|
3088
|
+
const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
|
|
3089
|
+
rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
3090
|
+
}
|
|
2939
3091
|
const totalPages = Math.max(1, rawPages.length);
|
|
2940
3092
|
let currentPage = 1;
|
|
2941
3093
|
const container = document.createElement("div");
|
|
2942
3094
|
container.style.width = "100%";
|
|
2943
3095
|
container.style.height = "100%";
|
|
2944
3096
|
container.style.overflow = "auto";
|
|
2945
|
-
container.style.backgroundColor = "#1e1e1e";
|
|
2946
|
-
container.style.color = "#d4d4d4";
|
|
2947
|
-
container.style.padding = "16px";
|
|
2948
|
-
container.style.boxSizing = "border-box";
|
|
2949
3097
|
let fontSize = 13;
|
|
2950
3098
|
let rotation = 0;
|
|
3099
|
+
let zoomLevel = 1;
|
|
2951
3100
|
const pre = document.createElement("pre");
|
|
2952
|
-
pre.style.margin = "0";
|
|
2953
|
-
pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
|
|
2954
|
-
pre.style.fontSize = `${fontSize}px`;
|
|
2955
|
-
pre.style.lineHeight = "1.5";
|
|
2956
|
-
pre.style.whiteSpace = "pre-wrap";
|
|
2957
|
-
pre.style.wordBreak = "break-all";
|
|
2958
3101
|
const code = document.createElement("code");
|
|
3102
|
+
if (isTxt) {
|
|
3103
|
+
container.style.backgroundColor = "#f1f5f9";
|
|
3104
|
+
container.style.padding = "32px";
|
|
3105
|
+
container.style.boxSizing = "border-box";
|
|
3106
|
+
container.style.display = "flex";
|
|
3107
|
+
container.style.flexDirection = "column";
|
|
3108
|
+
container.style.alignItems = "center";
|
|
3109
|
+
pre.style.margin = "0";
|
|
3110
|
+
pre.style.fontFamily = "Consolas, 'Courier New', monospace";
|
|
3111
|
+
pre.style.fontSize = "13px";
|
|
3112
|
+
pre.style.color = "#1e293b";
|
|
3113
|
+
pre.style.lineHeight = "1.5";
|
|
3114
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3115
|
+
pre.style.wordBreak = "break-word";
|
|
3116
|
+
pre.style.backgroundColor = "#ffffff";
|
|
3117
|
+
pre.style.width = "816px";
|
|
3118
|
+
pre.style.minHeight = "1056px";
|
|
3119
|
+
pre.style.padding = "72px 56px";
|
|
3120
|
+
pre.style.boxSizing = "border-box";
|
|
3121
|
+
pre.style.boxShadow = "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)";
|
|
3122
|
+
pre.style.borderRadius = "4px";
|
|
3123
|
+
pre.style.transformOrigin = "top center";
|
|
3124
|
+
} else {
|
|
3125
|
+
container.style.backgroundColor = "#1e1e1e";
|
|
3126
|
+
container.style.color = "#d4d4d4";
|
|
3127
|
+
container.style.padding = "16px";
|
|
3128
|
+
container.style.boxSizing = "border-box";
|
|
3129
|
+
pre.style.margin = "0";
|
|
3130
|
+
pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
|
|
3131
|
+
pre.style.fontSize = `${fontSize}px`;
|
|
3132
|
+
pre.style.lineHeight = "1.5";
|
|
3133
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3134
|
+
pre.style.wordBreak = "break-all";
|
|
3135
|
+
pre.style.transformOrigin = "top left";
|
|
3136
|
+
}
|
|
2959
3137
|
const ext = (ctx.metadata.extension || "").replace(".", "");
|
|
2960
3138
|
const renderCodePage = (text) => {
|
|
2961
|
-
|
|
2962
|
-
if (ext && hljs.getLanguage(ext)) {
|
|
2963
|
-
code.innerHTML = hljs.highlight(text, { language: ext }).value;
|
|
2964
|
-
} else {
|
|
2965
|
-
code.innerHTML = hljs.highlightAuto(text).value;
|
|
2966
|
-
}
|
|
2967
|
-
} catch {
|
|
3139
|
+
if (isTxt) {
|
|
2968
3140
|
code.textContent = text;
|
|
3141
|
+
} else {
|
|
3142
|
+
try {
|
|
3143
|
+
if (ext && hljs.getLanguage(ext)) {
|
|
3144
|
+
code.innerHTML = hljs.highlight(text, { language: ext }).value;
|
|
3145
|
+
} else {
|
|
3146
|
+
code.innerHTML = hljs.highlightAuto(text).value;
|
|
3147
|
+
}
|
|
3148
|
+
} catch {
|
|
3149
|
+
code.textContent = text;
|
|
3150
|
+
}
|
|
2969
3151
|
}
|
|
2970
3152
|
};
|
|
2971
|
-
renderCodePage(rawPages[0] || fullText);
|
|
3153
|
+
renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
|
|
2972
3154
|
pre.appendChild(code);
|
|
2973
3155
|
container.appendChild(pre);
|
|
2974
3156
|
let indicator = null;
|
|
@@ -2977,15 +3159,22 @@ var CodePlugin = class {
|
|
|
2977
3159
|
indicator.className = "fp-code-page-indicator";
|
|
2978
3160
|
indicator.style.position = "sticky";
|
|
2979
3161
|
indicator.style.bottom = "16px";
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
3162
|
+
if (isTxt) {
|
|
3163
|
+
indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
|
|
3164
|
+
indicator.style.color = "#334155";
|
|
3165
|
+
indicator.style.border = "1px solid #e2e8f0";
|
|
3166
|
+
indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
|
|
3167
|
+
} else {
|
|
3168
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3169
|
+
indicator.style.color = "#f8fafc";
|
|
3170
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3171
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3172
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
3173
|
+
}
|
|
2983
3174
|
indicator.style.fontSize = "12px";
|
|
2984
3175
|
indicator.style.fontWeight = "600";
|
|
2985
3176
|
indicator.style.padding = "5px 14px";
|
|
2986
3177
|
indicator.style.borderRadius = "20px";
|
|
2987
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2988
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2989
3178
|
indicator.style.zIndex = "10";
|
|
2990
3179
|
indicator.style.userSelect = "none";
|
|
2991
3180
|
indicator.style.pointerEvents = "none";
|
|
@@ -2996,7 +3185,7 @@ var CodePlugin = class {
|
|
|
2996
3185
|
}
|
|
2997
3186
|
const showPage = (pageNum) => {
|
|
2998
3187
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2999
|
-
renderCodePage(rawPages[currentPage - 1] || fullText);
|
|
3188
|
+
renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
|
|
3000
3189
|
if (indicator) {
|
|
3001
3190
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3002
3191
|
}
|
|
@@ -3012,39 +3201,57 @@ var CodePlugin = class {
|
|
|
3012
3201
|
ctx.container.innerHTML = "";
|
|
3013
3202
|
};
|
|
3014
3203
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3204
|
+
const updateTransform = () => {
|
|
3205
|
+
if (isTxt) {
|
|
3206
|
+
pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
|
|
3207
|
+
} else {
|
|
3208
|
+
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3209
|
+
pre.style.fontSize = `${fontSize}px`;
|
|
3210
|
+
}
|
|
3211
|
+
};
|
|
3015
3212
|
return {
|
|
3016
3213
|
destroy: cleanup,
|
|
3017
3214
|
getPageCount: () => totalPages,
|
|
3018
3215
|
getCurrentPage: () => currentPage,
|
|
3019
3216
|
goToPage: (page) => showPage(page),
|
|
3020
3217
|
zoomIn: () => {
|
|
3021
|
-
|
|
3022
|
-
|
|
3218
|
+
if (isTxt) {
|
|
3219
|
+
zoomLevel = Math.min(3, zoomLevel + 0.1);
|
|
3220
|
+
} else {
|
|
3221
|
+
fontSize = Math.min(32, fontSize + 2);
|
|
3222
|
+
}
|
|
3223
|
+
updateTransform();
|
|
3023
3224
|
},
|
|
3024
3225
|
zoomOut: () => {
|
|
3025
|
-
|
|
3026
|
-
|
|
3226
|
+
if (isTxt) {
|
|
3227
|
+
zoomLevel = Math.max(0.1, zoomLevel - 0.1);
|
|
3228
|
+
} else {
|
|
3229
|
+
fontSize = Math.max(8, fontSize - 2);
|
|
3230
|
+
}
|
|
3231
|
+
updateTransform();
|
|
3027
3232
|
},
|
|
3028
|
-
getZoom: () => fontSize / 13,
|
|
3233
|
+
getZoom: () => isTxt ? zoomLevel : fontSize / 13,
|
|
3029
3234
|
setZoom: (level) => {
|
|
3030
|
-
|
|
3031
|
-
|
|
3235
|
+
if (isTxt) {
|
|
3236
|
+
zoomLevel = level;
|
|
3237
|
+
} else {
|
|
3238
|
+
fontSize = Math.round(13 * level);
|
|
3239
|
+
}
|
|
3240
|
+
updateTransform();
|
|
3032
3241
|
},
|
|
3033
3242
|
fitToPage: () => {
|
|
3034
3243
|
fontSize = 13;
|
|
3035
3244
|
rotation = 0;
|
|
3036
|
-
|
|
3037
|
-
|
|
3245
|
+
zoomLevel = isTxt ? Math.max(0.65, Math.min(1.05, (container.clientWidth - 48) / 816)) : 1;
|
|
3246
|
+
updateTransform();
|
|
3038
3247
|
},
|
|
3039
3248
|
rotateCW: () => {
|
|
3040
3249
|
rotation = (rotation + 90) % 360;
|
|
3041
|
-
|
|
3042
|
-
pre.style.transformOrigin = "top left";
|
|
3250
|
+
updateTransform();
|
|
3043
3251
|
},
|
|
3044
3252
|
rotateCCW: () => {
|
|
3045
3253
|
rotation = (rotation - 90 + 360) % 360;
|
|
3046
|
-
|
|
3047
|
-
pre.style.transformOrigin = "top left";
|
|
3254
|
+
updateTransform();
|
|
3048
3255
|
},
|
|
3049
3256
|
download: () => {
|
|
3050
3257
|
const mimeType = ctx.metadata.mimeType || "text/plain";
|
|
@@ -3343,7 +3550,7 @@ var MarkdownPlugin = class {
|
|
|
3343
3550
|
gfm: true,
|
|
3344
3551
|
breaks: true
|
|
3345
3552
|
});
|
|
3346
|
-
const cleanHtml =
|
|
3553
|
+
const cleanHtml = DOMPurify6.sanitize(rawHtml, {
|
|
3347
3554
|
USE_PROFILES: { html: true }
|
|
3348
3555
|
});
|
|
3349
3556
|
const wrapper = document.createElement("div");
|
|
@@ -3979,6 +4186,14 @@ var RtfPlugin = class {
|
|
|
3979
4186
|
group: "actions",
|
|
3980
4187
|
execute: () => instance.download?.()
|
|
3981
4188
|
},
|
|
4189
|
+
{
|
|
4190
|
+
id: "copy",
|
|
4191
|
+
icon: "copy",
|
|
4192
|
+
label: "Copy Text",
|
|
4193
|
+
type: "button",
|
|
4194
|
+
group: "actions",
|
|
4195
|
+
execute: () => instance.copy?.()
|
|
4196
|
+
},
|
|
3982
4197
|
{
|
|
3983
4198
|
id: "print",
|
|
3984
4199
|
icon: "print",
|
|
@@ -4009,20 +4224,27 @@ var RtfPlugin = class {
|
|
|
4009
4224
|
let scale = 1;
|
|
4010
4225
|
let rotation = 0;
|
|
4011
4226
|
let pageElements = [];
|
|
4012
|
-
|
|
4227
|
+
let fitMode = "width";
|
|
4228
|
+
const calculateFitScale = (mode = fitMode) => {
|
|
4013
4229
|
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4014
4230
|
const elW = activeEl.offsetWidth || 850;
|
|
4015
|
-
const
|
|
4016
|
-
const availW = Math.max(
|
|
4017
|
-
const availH = Math.max(
|
|
4018
|
-
|
|
4231
|
+
const singlePageH = Math.min(activeEl.offsetHeight || 1056, Math.round(elW * 1.32));
|
|
4232
|
+
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
4233
|
+
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
4234
|
+
const sW = availW / elW;
|
|
4235
|
+
const sH = availH / singlePageH;
|
|
4236
|
+
if (mode === "page") {
|
|
4237
|
+
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
4238
|
+
}
|
|
4239
|
+
return Math.max(0.65, Math.min(1.05, sW));
|
|
4019
4240
|
};
|
|
4020
4241
|
const applyTransform = () => {
|
|
4021
4242
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4022
4243
|
wrapper.style.transformOrigin = "top center";
|
|
4023
4244
|
};
|
|
4024
4245
|
setTimeout(() => {
|
|
4025
|
-
|
|
4246
|
+
fitMode = "width";
|
|
4247
|
+
scale = calculateFitScale("width");
|
|
4026
4248
|
applyTransform();
|
|
4027
4249
|
}, 60);
|
|
4028
4250
|
try {
|
|
@@ -4040,14 +4262,31 @@ var RtfPlugin = class {
|
|
|
4040
4262
|
} catch (err) {
|
|
4041
4263
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
4042
4264
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
4043
|
-
const
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4265
|
+
const rawPages = text.split(/\\page\b/).map((segment) => {
|
|
4266
|
+
return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
|
|
4267
|
+
}).filter((p) => p.length > 0);
|
|
4268
|
+
const pages = rawPages.length > 0 ? rawPages : [text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim()];
|
|
4269
|
+
for (let i = 0; i < pages.length; i++) {
|
|
4270
|
+
const pageCard = document.createElement("div");
|
|
4271
|
+
pageCard.className = "fp-rtf-page-card";
|
|
4272
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
4273
|
+
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4274
|
+
pageCard.style.borderRadius = "4px";
|
|
4275
|
+
pageCard.style.padding = "72px 56px";
|
|
4276
|
+
pageCard.style.width = "816px";
|
|
4277
|
+
pageCard.style.minHeight = "1056px";
|
|
4278
|
+
pageCard.style.maxWidth = "100%";
|
|
4279
|
+
pageCard.style.boxSizing = "border-box";
|
|
4280
|
+
pageCard.style.fontFamily = "serif";
|
|
4281
|
+
pageCard.style.fontSize = "12pt";
|
|
4282
|
+
pageCard.style.lineHeight = "1.6";
|
|
4283
|
+
pageCard.style.color = "#1e293b";
|
|
4284
|
+
pageCard.style.whiteSpace = "pre-wrap";
|
|
4285
|
+
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4286
|
+
pageCard.textContent = pages[i];
|
|
4287
|
+
wrapper.appendChild(pageCard);
|
|
4288
|
+
pageElements.push(pageCard);
|
|
4289
|
+
}
|
|
4051
4290
|
}
|
|
4052
4291
|
const totalPages = Math.max(1, pageElements.length);
|
|
4053
4292
|
let currentPage = 1;
|
|
@@ -4114,7 +4353,8 @@ var RtfPlugin = class {
|
|
|
4114
4353
|
applyTransform();
|
|
4115
4354
|
},
|
|
4116
4355
|
fitToPage: () => {
|
|
4117
|
-
|
|
4356
|
+
fitMode = fitMode === "width" ? "page" : "width";
|
|
4357
|
+
scale = calculateFitScale(fitMode);
|
|
4118
4358
|
rotation = 0;
|
|
4119
4359
|
applyTransform();
|
|
4120
4360
|
},
|
|
@@ -4135,6 +4375,10 @@ var RtfPlugin = class {
|
|
|
4135
4375
|
a.click();
|
|
4136
4376
|
URL.revokeObjectURL(url);
|
|
4137
4377
|
},
|
|
4378
|
+
copy: () => {
|
|
4379
|
+
const text = wrapper.textContent || "";
|
|
4380
|
+
navigator.clipboard?.writeText(text);
|
|
4381
|
+
},
|
|
4138
4382
|
print: () => {
|
|
4139
4383
|
window.print();
|
|
4140
4384
|
}
|
|
@@ -4209,7 +4453,7 @@ var HtmlPreviewPlugin = class {
|
|
|
4209
4453
|
}
|
|
4210
4454
|
async render(ctx) {
|
|
4211
4455
|
const rawHtml = new TextDecoder("utf-8").decode(ctx.buffer);
|
|
4212
|
-
const sanitized =
|
|
4456
|
+
const sanitized = DOMPurify6.sanitize(rawHtml, {
|
|
4213
4457
|
WHOLE_DOCUMENT: true,
|
|
4214
4458
|
ADD_TAGS: ["style", "link"],
|
|
4215
4459
|
ADD_ATTR: ["target", "rel"]
|
|
@@ -4429,19 +4673,29 @@ var OpenDocumentPlugin = class {
|
|
|
4429
4673
|
ctx.container.appendChild(container);
|
|
4430
4674
|
let scale = 1;
|
|
4431
4675
|
let rotation = 0;
|
|
4432
|
-
|
|
4676
|
+
let fitMode = "width";
|
|
4677
|
+
const calculateFitScale = (mode = fitMode) => {
|
|
4433
4678
|
const elW = wrapper.offsetWidth || 850;
|
|
4434
|
-
const
|
|
4435
|
-
const availW = Math.max(
|
|
4436
|
-
const availH = Math.max(
|
|
4437
|
-
|
|
4679
|
+
const singlePageH = Math.min(wrapper.offsetHeight || 1056, Math.round(elW * 1.32));
|
|
4680
|
+
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
4681
|
+
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
4682
|
+
const sW = availW / elW;
|
|
4683
|
+
const sH = availH / (isPresentation ? 540 : singlePageH);
|
|
4684
|
+
if (isPresentation) {
|
|
4685
|
+
return Math.min(1, Math.min(sW, sH));
|
|
4686
|
+
}
|
|
4687
|
+
if (mode === "page") {
|
|
4688
|
+
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
4689
|
+
}
|
|
4690
|
+
return Math.max(0.65, Math.min(1.05, sW));
|
|
4438
4691
|
};
|
|
4439
4692
|
const applyTransform = () => {
|
|
4440
4693
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4441
4694
|
wrapper.style.transformOrigin = "top center";
|
|
4442
4695
|
};
|
|
4443
4696
|
setTimeout(() => {
|
|
4444
|
-
|
|
4697
|
+
fitMode = "width";
|
|
4698
|
+
scale = calculateFitScale("width");
|
|
4445
4699
|
applyTransform();
|
|
4446
4700
|
}, 60);
|
|
4447
4701
|
let currentPage = 1;
|
|
@@ -4475,14 +4729,97 @@ var OpenDocumentPlugin = class {
|
|
|
4475
4729
|
wrapper.textContent = contentDoc.documentElement.textContent || "Formula content";
|
|
4476
4730
|
}
|
|
4477
4731
|
} else {
|
|
4478
|
-
wrapper.style.maxWidth = "
|
|
4479
|
-
wrapper.style.padding = "
|
|
4732
|
+
wrapper.style.maxWidth = "none";
|
|
4733
|
+
wrapper.style.padding = "0";
|
|
4480
4734
|
wrapper.style.minHeight = "100%";
|
|
4735
|
+
wrapper.style.backgroundColor = "transparent";
|
|
4736
|
+
wrapper.style.boxShadow = "none";
|
|
4737
|
+
wrapper.style.position = "relative";
|
|
4738
|
+
const dims = this.getPageDimensions(stylesDoc, contentDoc);
|
|
4481
4739
|
const bodyHtml = this.renderOdfBody(contentDoc, styleMap, imageUrls);
|
|
4482
|
-
|
|
4483
|
-
|
|
4740
|
+
const tempDiv = document.createElement("div");
|
|
4741
|
+
tempDiv.style.width = `${dims.width - dims.marginLeft - dims.marginRight}px`;
|
|
4742
|
+
tempDiv.style.position = "absolute";
|
|
4743
|
+
tempDiv.style.visibility = "hidden";
|
|
4744
|
+
tempDiv.innerHTML = DOMPurify6.sanitize(bodyHtml, {
|
|
4745
|
+
ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub", "hr"],
|
|
4484
4746
|
ADD_ATTR: ["style", "colspan", "rowspan"]
|
|
4485
4747
|
});
|
|
4748
|
+
document.body.appendChild(tempDiv);
|
|
4749
|
+
const contentHeight = dims.height - dims.marginTop - dims.marginBottom;
|
|
4750
|
+
const pageElements = [[]];
|
|
4751
|
+
let currentHeight = 0;
|
|
4752
|
+
let currentPageIdx = 0;
|
|
4753
|
+
Array.from(tempDiv.children).forEach((child) => {
|
|
4754
|
+
const el = child;
|
|
4755
|
+
const style = el.getAttribute("style") || "";
|
|
4756
|
+
const isBreakBefore = style.includes("page-break-before: always");
|
|
4757
|
+
const isBreakAfter = style.includes("page-break-after: always");
|
|
4758
|
+
const isSoftBreak = el.classList.contains("odf-page-break");
|
|
4759
|
+
if (isBreakBefore) {
|
|
4760
|
+
if (pageElements[currentPageIdx].length > 0) {
|
|
4761
|
+
currentPageIdx++;
|
|
4762
|
+
pageElements.push([]);
|
|
4763
|
+
currentHeight = 0;
|
|
4764
|
+
}
|
|
4765
|
+
}
|
|
4766
|
+
const h = el.offsetHeight || 0;
|
|
4767
|
+
if (currentHeight + h > contentHeight && pageElements[currentPageIdx].length > 0 && !isSoftBreak) {
|
|
4768
|
+
currentPageIdx++;
|
|
4769
|
+
pageElements.push([]);
|
|
4770
|
+
currentHeight = 0;
|
|
4771
|
+
}
|
|
4772
|
+
if (!isSoftBreak) {
|
|
4773
|
+
pageElements[currentPageIdx].push(el.cloneNode(true));
|
|
4774
|
+
currentHeight += h;
|
|
4775
|
+
}
|
|
4776
|
+
if (isBreakAfter || isSoftBreak) {
|
|
4777
|
+
currentPageIdx++;
|
|
4778
|
+
pageElements.push([]);
|
|
4779
|
+
currentHeight = 0;
|
|
4780
|
+
}
|
|
4781
|
+
});
|
|
4782
|
+
document.body.removeChild(tempDiv);
|
|
4783
|
+
if (pageElements.length > 1 && pageElements[pageElements.length - 1].length === 0) {
|
|
4784
|
+
pageElements.pop();
|
|
4785
|
+
}
|
|
4786
|
+
totalPages = Math.max(1, pageElements.length);
|
|
4787
|
+
pageElements.forEach((elements, idx) => {
|
|
4788
|
+
const page = document.createElement("div");
|
|
4789
|
+
page.className = `fp-odt-page fp-odt-page-${idx + 1}`;
|
|
4790
|
+
page.style.width = `${dims.width}px`;
|
|
4791
|
+
page.style.minHeight = `${dims.height}px`;
|
|
4792
|
+
page.style.padding = `${dims.marginTop}px ${dims.marginRight}px ${dims.marginBottom}px ${dims.marginLeft}px`;
|
|
4793
|
+
page.style.margin = "0 auto";
|
|
4794
|
+
page.style.backgroundColor = "#ffffff";
|
|
4795
|
+
page.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
|
|
4796
|
+
page.style.borderRadius = "4px";
|
|
4797
|
+
page.style.boxSizing = "border-box";
|
|
4798
|
+
page.style.display = idx === 0 ? "block" : "none";
|
|
4799
|
+
page.style.position = "absolute";
|
|
4800
|
+
page.style.top = "0";
|
|
4801
|
+
page.style.left = "50%";
|
|
4802
|
+
page.style.transform = "translateX(-50%)";
|
|
4803
|
+
elements.forEach((el) => page.appendChild(el));
|
|
4804
|
+
wrapper.appendChild(page);
|
|
4805
|
+
slides.push(page);
|
|
4806
|
+
});
|
|
4807
|
+
const pageIndicator = document.createElement("div");
|
|
4808
|
+
pageIndicator.className = "fp-odt-page-indicator";
|
|
4809
|
+
pageIndicator.style.position = "sticky";
|
|
4810
|
+
pageIndicator.style.bottom = "16px";
|
|
4811
|
+
pageIndicator.style.left = "50%";
|
|
4812
|
+
pageIndicator.style.transform = "translateX(-50%)";
|
|
4813
|
+
pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
|
4814
|
+
pageIndicator.style.color = "#fff";
|
|
4815
|
+
pageIndicator.style.padding = "6px 12px";
|
|
4816
|
+
pageIndicator.style.borderRadius = "16px";
|
|
4817
|
+
pageIndicator.style.fontSize = "12px";
|
|
4818
|
+
pageIndicator.style.zIndex = "100";
|
|
4819
|
+
pageIndicator.style.display = "inline-block";
|
|
4820
|
+
pageIndicator.style.width = "fit-content";
|
|
4821
|
+
pageIndicator.textContent = `Page 1 of ${totalPages}`;
|
|
4822
|
+
container.appendChild(pageIndicator);
|
|
4486
4823
|
}
|
|
4487
4824
|
const cleanup = () => {
|
|
4488
4825
|
imageUrls.forEach((url) => URL.revokeObjectURL(url));
|
|
@@ -4491,11 +4828,15 @@ var OpenDocumentPlugin = class {
|
|
|
4491
4828
|
};
|
|
4492
4829
|
ctx.signal.addEventListener("abort", cleanup);
|
|
4493
4830
|
const goToPage = (page) => {
|
|
4494
|
-
if (
|
|
4831
|
+
if (page < 1 || page > totalPages) return;
|
|
4495
4832
|
currentPage = page;
|
|
4496
4833
|
slides.forEach((s, idx) => {
|
|
4497
4834
|
s.style.display = idx === page - 1 ? "block" : "none";
|
|
4498
4835
|
});
|
|
4836
|
+
const indicator = container.querySelector(".fp-odt-page-indicator");
|
|
4837
|
+
if (indicator) {
|
|
4838
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4839
|
+
}
|
|
4499
4840
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4500
4841
|
};
|
|
4501
4842
|
return {
|
|
@@ -4515,7 +4856,8 @@ var OpenDocumentPlugin = class {
|
|
|
4515
4856
|
applyTransform();
|
|
4516
4857
|
},
|
|
4517
4858
|
fitToPage: () => {
|
|
4518
|
-
|
|
4859
|
+
fitMode = fitMode === "width" ? "page" : "width";
|
|
4860
|
+
scale = calculateFitScale(fitMode);
|
|
4519
4861
|
rotation = 0;
|
|
4520
4862
|
applyTransform();
|
|
4521
4863
|
},
|
|
@@ -4564,6 +4906,43 @@ var OpenDocumentPlugin = class {
|
|
|
4564
4906
|
}
|
|
4565
4907
|
};
|
|
4566
4908
|
}
|
|
4909
|
+
getPageDimensions(stylesDoc, contentDoc) {
|
|
4910
|
+
let width = 850;
|
|
4911
|
+
let height = 1123;
|
|
4912
|
+
let marginTop = 48;
|
|
4913
|
+
let marginBottom = 48;
|
|
4914
|
+
let marginLeft = 48;
|
|
4915
|
+
let marginRight = 48;
|
|
4916
|
+
const parseUnit = (val) => {
|
|
4917
|
+
if (!val) return null;
|
|
4918
|
+
if (val.endsWith("cm")) return parseFloat(val) * 37.8;
|
|
4919
|
+
if (val.endsWith("mm")) return parseFloat(val) * 3.78;
|
|
4920
|
+
if (val.endsWith("in")) return parseFloat(val) * 96;
|
|
4921
|
+
if (val.endsWith("pt")) return parseFloat(val) * 1.33;
|
|
4922
|
+
if (val.endsWith("px")) return parseFloat(val);
|
|
4923
|
+
return parseFloat(val);
|
|
4924
|
+
};
|
|
4925
|
+
const docs = [stylesDoc, contentDoc].filter(Boolean);
|
|
4926
|
+
for (const doc of docs) {
|
|
4927
|
+
const pageLayout = doc.querySelector("page-layout-properties, [page-width]");
|
|
4928
|
+
if (pageLayout) {
|
|
4929
|
+
const w = parseUnit(pageLayout.getAttribute("fo:page-width") || pageLayout.getAttribute("page-width"));
|
|
4930
|
+
const h = parseUnit(pageLayout.getAttribute("fo:page-height") || pageLayout.getAttribute("page-height"));
|
|
4931
|
+
const mt = parseUnit(pageLayout.getAttribute("fo:margin-top") || pageLayout.getAttribute("margin-top"));
|
|
4932
|
+
const mb = parseUnit(pageLayout.getAttribute("fo:margin-bottom") || pageLayout.getAttribute("margin-bottom"));
|
|
4933
|
+
const ml = parseUnit(pageLayout.getAttribute("fo:margin-left") || pageLayout.getAttribute("margin-left"));
|
|
4934
|
+
const mr = parseUnit(pageLayout.getAttribute("fo:margin-right") || pageLayout.getAttribute("margin-right"));
|
|
4935
|
+
if (w !== null) width = w;
|
|
4936
|
+
if (h !== null) height = h;
|
|
4937
|
+
if (mt !== null) marginTop = mt;
|
|
4938
|
+
if (mb !== null) marginBottom = mb;
|
|
4939
|
+
if (ml !== null) marginLeft = ml;
|
|
4940
|
+
if (mr !== null) marginRight = mr;
|
|
4941
|
+
break;
|
|
4942
|
+
}
|
|
4943
|
+
}
|
|
4944
|
+
return { width, height, marginTop, marginBottom, marginLeft, marginRight };
|
|
4945
|
+
}
|
|
4567
4946
|
extractStyles(stylesDoc, contentDoc) {
|
|
4568
4947
|
const map = /* @__PURE__ */ new Map();
|
|
4569
4948
|
const styleNodes = [];
|
|
@@ -4586,14 +4965,21 @@ var OpenDocumentPlugin = class {
|
|
|
4586
4965
|
if (color) css += `color: ${color}; `;
|
|
4587
4966
|
if (size) css += `font-size: ${size}; `;
|
|
4588
4967
|
}
|
|
4589
|
-
|
|
4968
|
+
let paraProp = node.querySelector("paragraph-properties, [text-align]");
|
|
4969
|
+
if (!paraProp) {
|
|
4970
|
+
paraProp = Array.from(node.children).find((c) => c.tagName.includes("paragraph-properties")) || null;
|
|
4971
|
+
}
|
|
4590
4972
|
if (paraProp) {
|
|
4591
4973
|
const align = paraProp.getAttribute("fo:text-align") || paraProp.getAttribute("text-align");
|
|
4592
4974
|
const mt = paraProp.getAttribute("fo:margin-top") || paraProp.getAttribute("margin-top");
|
|
4593
4975
|
const mb = paraProp.getAttribute("fo:margin-bottom") || paraProp.getAttribute("margin-bottom");
|
|
4976
|
+
const breakBefore = paraProp.getAttribute("fo:break-before") || paraProp.getAttribute("break-before");
|
|
4977
|
+
const breakAfter = paraProp.getAttribute("fo:break-after") || paraProp.getAttribute("break-after");
|
|
4594
4978
|
if (align) css += `text-align: ${align}; `;
|
|
4595
4979
|
if (mt) css += `margin-top: ${mt}; `;
|
|
4596
4980
|
if (mb) css += `margin-bottom: ${mb}; `;
|
|
4981
|
+
if (breakBefore === "page") css += "page-break-before: always; ";
|
|
4982
|
+
if (breakAfter === "page") css += "page-break-after: always; ";
|
|
4597
4983
|
}
|
|
4598
4984
|
if (css) map.set(name, css);
|
|
4599
4985
|
}
|
|
@@ -4678,6 +5064,8 @@ var OpenDocumentPlugin = class {
|
|
|
4678
5064
|
result += " ";
|
|
4679
5065
|
} else if (tag === "line-break") {
|
|
4680
5066
|
result += "<br/>";
|
|
5067
|
+
} else if (tag === "soft-page-break") {
|
|
5068
|
+
result += '<hr class="odf-page-break" style="page-break-after: always; border: none; margin: 0; padding: 0; height: 0;" />';
|
|
4681
5069
|
} else {
|
|
4682
5070
|
result += el.textContent || "";
|
|
4683
5071
|
}
|
|
@@ -4838,20 +5226,9 @@ var DocPlugin = class {
|
|
|
4838
5226
|
container.style.overflow = "auto";
|
|
4839
5227
|
container.style.padding = "32px 16px";
|
|
4840
5228
|
container.style.backgroundColor = "#f1f5f9";
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
wrapper.style.margin = "0 auto";
|
|
4845
|
-
wrapper.style.backgroundColor = "#ffffff";
|
|
4846
|
-
wrapper.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4847
|
-
wrapper.style.borderRadius = "4px";
|
|
4848
|
-
wrapper.style.padding = "56px 48px";
|
|
4849
|
-
wrapper.style.minHeight = "100%";
|
|
4850
|
-
wrapper.style.transformOrigin = "top center";
|
|
4851
|
-
wrapper.style.transition = "transform 0.2s ease";
|
|
4852
|
-
wrapper.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4853
|
-
wrapper.style.color = "#1e293b";
|
|
4854
|
-
container.appendChild(wrapper);
|
|
5229
|
+
container.style.display = "flex";
|
|
5230
|
+
container.style.justifyContent = "center";
|
|
5231
|
+
container.style.alignItems = "flex-start";
|
|
4855
5232
|
ctx.container.appendChild(container);
|
|
4856
5233
|
let scale = 1;
|
|
4857
5234
|
let extractedRawText = "";
|
|
@@ -4878,21 +5255,27 @@ var DocPlugin = class {
|
|
|
4878
5255
|
const rawPages = this.splitIntoPages(extractedRawText);
|
|
4879
5256
|
const totalPages = Math.max(1, rawPages.length);
|
|
4880
5257
|
let currentPage = 1;
|
|
4881
|
-
wrapper.innerHTML = "";
|
|
4882
5258
|
const pageCards = [];
|
|
4883
5259
|
for (let i = 0; i < totalPages; i++) {
|
|
4884
5260
|
const pageCard = document.createElement("div");
|
|
4885
5261
|
pageCard.className = "fp-doc-page-card";
|
|
5262
|
+
pageCard.style.width = "816px";
|
|
5263
|
+
pageCard.style.height = "1056px";
|
|
4886
5264
|
pageCard.style.backgroundColor = "#ffffff";
|
|
4887
5265
|
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4888
5266
|
pageCard.style.borderRadius = "4px";
|
|
4889
|
-
pageCard.style.padding = "
|
|
4890
|
-
pageCard.style.
|
|
5267
|
+
pageCard.style.padding = "96px 72px";
|
|
5268
|
+
pageCard.style.boxSizing = "border-box";
|
|
5269
|
+
pageCard.style.overflow = "hidden";
|
|
4891
5270
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
5271
|
+
pageCard.style.transformOrigin = "top center";
|
|
5272
|
+
pageCard.style.transition = "transform 0.2s ease";
|
|
5273
|
+
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
5274
|
+
pageCard.style.color = "#1e293b";
|
|
4892
5275
|
if (isFallback && i === 0) {
|
|
4893
5276
|
pageCard.innerHTML = `
|
|
4894
5277
|
<div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
|
|
4895
|
-
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${
|
|
5278
|
+
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify6.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
|
|
4896
5279
|
<span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
|
|
4897
5280
|
</div>
|
|
4898
5281
|
${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
|
|
@@ -4900,15 +5283,17 @@ var DocPlugin = class {
|
|
|
4900
5283
|
} else {
|
|
4901
5284
|
pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
|
|
4902
5285
|
}
|
|
4903
|
-
|
|
5286
|
+
container.appendChild(pageCard);
|
|
4904
5287
|
pageCards.push(pageCard);
|
|
4905
5288
|
}
|
|
4906
5289
|
let indicator = null;
|
|
4907
5290
|
if (totalPages > 1) {
|
|
4908
5291
|
indicator = document.createElement("div");
|
|
4909
5292
|
indicator.className = "fp-doc-page-indicator";
|
|
4910
|
-
indicator.style.position = "
|
|
5293
|
+
indicator.style.position = "fixed";
|
|
4911
5294
|
indicator.style.bottom = "16px";
|
|
5295
|
+
indicator.style.left = "50%";
|
|
5296
|
+
indicator.style.transform = "translateX(-50%)";
|
|
4912
5297
|
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4913
5298
|
indicator.style.backdropFilter = "blur(8px)";
|
|
4914
5299
|
indicator.style.color = "#f8fafc";
|
|
@@ -4922,17 +5307,25 @@ var DocPlugin = class {
|
|
|
4922
5307
|
indicator.style.userSelect = "none";
|
|
4923
5308
|
indicator.style.pointerEvents = "none";
|
|
4924
5309
|
indicator.style.textAlign = "center";
|
|
4925
|
-
indicator.style.width = "fit-content";
|
|
4926
|
-
indicator.style.margin = "16px auto 0";
|
|
4927
5310
|
container.appendChild(indicator);
|
|
4928
5311
|
}
|
|
5312
|
+
let rotation = 0;
|
|
5313
|
+
const applyTransform = () => {
|
|
5314
|
+
const activeCard = pageCards[currentPage - 1];
|
|
5315
|
+
if (activeCard) {
|
|
5316
|
+
activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5317
|
+
}
|
|
5318
|
+
};
|
|
4929
5319
|
const showPage = (pageNum) => {
|
|
4930
5320
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
card.style.display =
|
|
4934
|
-
|
|
4935
|
-
|
|
5321
|
+
pageCards.forEach((card, idx) => {
|
|
5322
|
+
if (idx + 1 === currentPage) {
|
|
5323
|
+
card.style.display = "block";
|
|
5324
|
+
card.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5325
|
+
} else {
|
|
5326
|
+
card.style.display = "none";
|
|
5327
|
+
}
|
|
5328
|
+
});
|
|
4936
5329
|
if (indicator) {
|
|
4937
5330
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4938
5331
|
}
|
|
@@ -4941,21 +5334,22 @@ var DocPlugin = class {
|
|
|
4941
5334
|
if (totalPages > 1) {
|
|
4942
5335
|
showPage(1);
|
|
4943
5336
|
}
|
|
4944
|
-
let
|
|
4945
|
-
const calculateFitScale = () => {
|
|
4946
|
-
const
|
|
4947
|
-
const
|
|
4948
|
-
const
|
|
4949
|
-
const
|
|
4950
|
-
const
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
5337
|
+
let fitMode = "width";
|
|
5338
|
+
const calculateFitScale = (mode = fitMode) => {
|
|
5339
|
+
const elW = 816;
|
|
5340
|
+
const elH = 1056;
|
|
5341
|
+
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
5342
|
+
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
5343
|
+
const sW = availW / elW;
|
|
5344
|
+
const sH = availH / elH;
|
|
5345
|
+
if (mode === "page") {
|
|
5346
|
+
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
5347
|
+
}
|
|
5348
|
+
return Math.max(0.65, Math.min(1.05, sW));
|
|
4956
5349
|
};
|
|
4957
5350
|
setTimeout(() => {
|
|
4958
|
-
|
|
5351
|
+
fitMode = "width";
|
|
5352
|
+
scale = calculateFitScale("width");
|
|
4959
5353
|
applyTransform();
|
|
4960
5354
|
}, 60);
|
|
4961
5355
|
const cleanup = () => {
|
|
@@ -4983,7 +5377,8 @@ var DocPlugin = class {
|
|
|
4983
5377
|
applyTransform();
|
|
4984
5378
|
},
|
|
4985
5379
|
fitToPage: () => {
|
|
4986
|
-
|
|
5380
|
+
fitMode = fitMode === "width" ? "page" : "width";
|
|
5381
|
+
scale = calculateFitScale(fitMode);
|
|
4987
5382
|
rotation = 0;
|
|
4988
5383
|
applyTransform();
|
|
4989
5384
|
},
|
|
@@ -5111,8 +5506,28 @@ var DocPlugin = class {
|
|
|
5111
5506
|
}
|
|
5112
5507
|
splitIntoPages(text) {
|
|
5113
5508
|
if (!text) return [""];
|
|
5114
|
-
const
|
|
5115
|
-
|
|
5509
|
+
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);
|
|
5510
|
+
if (explicitParts.length === 0) explicitParts.push(text);
|
|
5511
|
+
const maxLinesPerPage = 48;
|
|
5512
|
+
const finalPages = [];
|
|
5513
|
+
for (const part of explicitParts) {
|
|
5514
|
+
const lines = part.split(/\r?\n/);
|
|
5515
|
+
let currentLines = [];
|
|
5516
|
+
let count = 0;
|
|
5517
|
+
for (const line of lines) {
|
|
5518
|
+
currentLines.push(line);
|
|
5519
|
+
count++;
|
|
5520
|
+
if (count >= maxLinesPerPage) {
|
|
5521
|
+
finalPages.push(currentLines.join("\n"));
|
|
5522
|
+
currentLines = [];
|
|
5523
|
+
count = 0;
|
|
5524
|
+
}
|
|
5525
|
+
}
|
|
5526
|
+
if (currentLines.length > 0) {
|
|
5527
|
+
finalPages.push(currentLines.join("\n"));
|
|
5528
|
+
}
|
|
5529
|
+
}
|
|
5530
|
+
return finalPages.length > 0 ? finalPages : [text];
|
|
5116
5531
|
}
|
|
5117
5532
|
/**
|
|
5118
5533
|
* Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
|
|
@@ -5121,17 +5536,65 @@ var DocPlugin = class {
|
|
|
5121
5536
|
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
|
|
5122
5537
|
let html = "";
|
|
5123
5538
|
let inList = false;
|
|
5124
|
-
|
|
5125
|
-
|
|
5539
|
+
let tableLines = [];
|
|
5540
|
+
const flushTable = () => {
|
|
5541
|
+
if (tableLines.length > 0) {
|
|
5542
|
+
html += '<table style="width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 12px;">';
|
|
5543
|
+
for (const tLine of tableLines) {
|
|
5544
|
+
html += "<tr>";
|
|
5545
|
+
const cols = tLine.split(" ");
|
|
5546
|
+
for (const col of cols) {
|
|
5547
|
+
html += `<td style="border: 1px solid #cbd5e1; padding: 6px 8px;">${DOMPurify6.sanitize(col.trim())}</td>`;
|
|
5548
|
+
}
|
|
5549
|
+
html += "</tr>";
|
|
5550
|
+
}
|
|
5551
|
+
html += "</table>";
|
|
5552
|
+
tableLines = [];
|
|
5553
|
+
}
|
|
5554
|
+
};
|
|
5555
|
+
let i = 0;
|
|
5556
|
+
while (i < lines.length) {
|
|
5557
|
+
let line = lines[i];
|
|
5558
|
+
let tabCount = (line.match(/\t/g) || []).length;
|
|
5559
|
+
if (tabCount > 0) {
|
|
5560
|
+
let consecutiveTableLines = 1;
|
|
5561
|
+
let j = i + 1;
|
|
5562
|
+
while (j < lines.length) {
|
|
5563
|
+
const nextTabCount = (lines[j].match(/\t/g) || []).length;
|
|
5564
|
+
if (nextTabCount === tabCount) {
|
|
5565
|
+
consecutiveTableLines++;
|
|
5566
|
+
j++;
|
|
5567
|
+
} else {
|
|
5568
|
+
break;
|
|
5569
|
+
}
|
|
5570
|
+
}
|
|
5571
|
+
if (consecutiveTableLines >= 3) {
|
|
5572
|
+
if (inList) {
|
|
5573
|
+
html += "</ul>";
|
|
5574
|
+
inList = false;
|
|
5575
|
+
}
|
|
5576
|
+
tableLines = lines.slice(i, j);
|
|
5577
|
+
flushTable();
|
|
5578
|
+
i = j;
|
|
5579
|
+
continue;
|
|
5580
|
+
}
|
|
5581
|
+
}
|
|
5582
|
+
line = line.trim();
|
|
5126
5583
|
if (!line) {
|
|
5127
5584
|
if (inList) {
|
|
5128
5585
|
html += "</ul>";
|
|
5129
5586
|
inList = false;
|
|
5130
5587
|
}
|
|
5588
|
+
html += '<div style="height: 1.15em;"></div>';
|
|
5589
|
+
i++;
|
|
5590
|
+
continue;
|
|
5591
|
+
}
|
|
5592
|
+
if (/^[\x00-\x1F\x7F-\x9F]+$/.test(line)) {
|
|
5593
|
+
i++;
|
|
5131
5594
|
continue;
|
|
5132
5595
|
}
|
|
5133
|
-
if (
|
|
5134
|
-
|
|
5596
|
+
if ((line.includes("Normal.dot") || line.includes("Microsoft Word") || line.includes("Times New Roman")) && line.length < 30) {
|
|
5597
|
+
i++;
|
|
5135
5598
|
continue;
|
|
5136
5599
|
}
|
|
5137
5600
|
if (line.length < 60 && !line.endsWith(".") && (/^[A-Z0-9\s:_-]+$/.test(line) || line.startsWith("#"))) {
|
|
@@ -5139,24 +5602,26 @@ var DocPlugin = class {
|
|
|
5139
5602
|
html += "</ul>";
|
|
5140
5603
|
inList = false;
|
|
5141
5604
|
}
|
|
5142
|
-
html += `<h2 style="font-size:
|
|
5605
|
+
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>`;
|
|
5143
5606
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
5144
5607
|
if (!inList) {
|
|
5145
5608
|
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
5146
5609
|
inList = true;
|
|
5147
5610
|
}
|
|
5148
5611
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
5149
|
-
html += `<li style="margin: 4px 0; line-height: 1.
|
|
5612
|
+
html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6.sanitize(bulletText)}</li>`;
|
|
5150
5613
|
} else {
|
|
5151
5614
|
if (inList) {
|
|
5152
5615
|
html += "</ul>";
|
|
5153
5616
|
inList = false;
|
|
5154
5617
|
}
|
|
5155
|
-
html += `<p style="line-height: 1.
|
|
5618
|
+
html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6.sanitize(line)}</p>`;
|
|
5156
5619
|
}
|
|
5620
|
+
i++;
|
|
5157
5621
|
}
|
|
5158
5622
|
if (inList) html += "</ul>";
|
|
5159
|
-
|
|
5623
|
+
flushTable();
|
|
5624
|
+
return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify6.sanitize(filename)})</p>`;
|
|
5160
5625
|
}
|
|
5161
5626
|
};
|
|
5162
5627
|
function docPlugin() {
|
|
@@ -5334,7 +5799,7 @@ var PptPlugin = class {
|
|
|
5334
5799
|
if (s.pictureUrl) {
|
|
5335
5800
|
contentHtml = `
|
|
5336
5801
|
<div style="flex: 1; display: flex; justify-content: center; align-items: center; padding: 12px; overflow: hidden;">
|
|
5337
|
-
<img src="${s.pictureUrl}" alt="${
|
|
5802
|
+
<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;" />
|
|
5338
5803
|
</div>
|
|
5339
5804
|
`;
|
|
5340
5805
|
} else if (s.tableColumns.length > 0) {
|
|
@@ -5344,7 +5809,7 @@ var PptPlugin = class {
|
|
|
5344
5809
|
<table style="width: 100%; border-collapse: collapse; border: 1px solid #cbd5e1; border-radius: 6px; overflow: hidden; background: #ffffff;">
|
|
5345
5810
|
<thead>
|
|
5346
5811
|
<tr style="background: #e2e8f0; color: #1e293b; font-weight: 600; font-size: 14px;">
|
|
5347
|
-
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${
|
|
5812
|
+
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify6.sanitize(c)}</th>`).join("")}
|
|
5348
5813
|
</tr>
|
|
5349
5814
|
</thead>
|
|
5350
5815
|
<tbody>
|
|
@@ -5360,7 +5825,7 @@ var PptPlugin = class {
|
|
|
5360
5825
|
} else {
|
|
5361
5826
|
const pTags = s.paragraphs.map((p) => {
|
|
5362
5827
|
const lines = p.split(/[\r\n]+/).map((l) => l.trim()).filter(Boolean);
|
|
5363
|
-
return lines.map((l) => `<p style="margin: 0 0 14px; font-size: 14px; line-height: 1.65; color: #334155; text-align: justify;">${
|
|
5828
|
+
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("");
|
|
5364
5829
|
}).join("");
|
|
5365
5830
|
contentHtml = `
|
|
5366
5831
|
<div style="flex: 1; overflow: auto; padding: 4px 8px; display: flex; flex-direction: column; justify-content: flex-start;">
|
|
@@ -5373,11 +5838,11 @@ var PptPlugin = class {
|
|
|
5373
5838
|
<!-- Header Banner matching PowerPoint design -->
|
|
5374
5839
|
<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;">
|
|
5375
5840
|
<h1 style="margin: 0; font-size: 26px; font-weight: 700; color: #1e293b; letter-spacing: -0.3px;">
|
|
5376
|
-
${
|
|
5841
|
+
${DOMPurify6.sanitize(s.title)}
|
|
5377
5842
|
</h1>
|
|
5378
5843
|
${s.subtitle ? `
|
|
5379
5844
|
<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);">
|
|
5380
|
-
${
|
|
5845
|
+
${DOMPurify6.sanitize(s.subtitle)}
|
|
5381
5846
|
</span>
|
|
5382
5847
|
` : `
|
|
5383
5848
|
<span style="font-size: 12px; color: #365314; font-weight: 600;">
|