@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/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import DOMPurify6 from 'dompurify';
|
|
2
2
|
import * as pdfjsLib from 'pdfjs-dist';
|
|
3
3
|
import * as docx from 'docx-preview';
|
|
4
4
|
import { unzipSync, strFromU8, unzip } from 'fflate';
|
|
@@ -356,7 +356,7 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
356
356
|
if (magicMime === "application/zip") {
|
|
357
357
|
const ooxmlMime = detectOoxmlType(buffer);
|
|
358
358
|
if (ooxmlMime && ooxmlMime !== "application/zip") {
|
|
359
|
-
metadata.mimeType = ooxmlMime;
|
|
359
|
+
metadata.mimeType = metadata.mimeType ?? ooxmlMime;
|
|
360
360
|
if (ooxmlMime.includes("wordprocessing")) metadata.extension = metadata.extension ?? ".docx";
|
|
361
361
|
else if (ooxmlMime.includes("spreadsheet")) metadata.extension = metadata.extension ?? ".xlsx";
|
|
362
362
|
else if (ooxmlMime.includes("presentation")) metadata.extension = metadata.extension ?? ".pptx";
|
|
@@ -385,12 +385,12 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
385
385
|
return { buffer, metadata };
|
|
386
386
|
}
|
|
387
387
|
function sanitizeHTML(html) {
|
|
388
|
-
return
|
|
388
|
+
return DOMPurify6.sanitize(html, {
|
|
389
389
|
USE_PROFILES: { html: true }
|
|
390
390
|
});
|
|
391
391
|
}
|
|
392
392
|
function sanitizeSVG(svg) {
|
|
393
|
-
return
|
|
393
|
+
return DOMPurify6.sanitize(svg, {
|
|
394
394
|
USE_PROFILES: { svg: true, svgFilters: true }
|
|
395
395
|
});
|
|
396
396
|
}
|
|
@@ -476,7 +476,8 @@ function createElement(tag, attrs, ...children) {
|
|
|
476
476
|
}
|
|
477
477
|
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>`;
|
|
478
478
|
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>`;
|
|
479
|
-
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"><
|
|
479
|
+
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>`;
|
|
480
|
+
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>`;
|
|
480
481
|
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>`;
|
|
481
482
|
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>`;
|
|
482
483
|
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>`;
|
|
@@ -496,6 +497,7 @@ var ICON_MAP = {
|
|
|
496
497
|
"zoom-in": ICON_ZOOM_IN,
|
|
497
498
|
"zoom-out": ICON_ZOOM_OUT,
|
|
498
499
|
"fit-page": ICON_FIT_PAGE,
|
|
500
|
+
"fit-width": ICON_FIT_WIDTH,
|
|
499
501
|
"fit-slide": ICON_FIT_PAGE,
|
|
500
502
|
"rotate-cw": ICON_ROTATE_CW,
|
|
501
503
|
"rotate-ccw": ICON_ROTATE_CCW,
|
|
@@ -1442,6 +1444,7 @@ var PdfPlugin = class {
|
|
|
1442
1444
|
let currentPage = 1;
|
|
1443
1445
|
let zoomScale = 1;
|
|
1444
1446
|
let rotation = 0;
|
|
1447
|
+
let fitMode = "width";
|
|
1445
1448
|
let currentRenderTask = null;
|
|
1446
1449
|
const renderPage = async (pageNum) => {
|
|
1447
1450
|
if (currentRenderTask) {
|
|
@@ -1461,11 +1464,16 @@ var PdfPlugin = class {
|
|
|
1461
1464
|
const containerWidth = container.clientWidth || 900;
|
|
1462
1465
|
const containerHeight = container.clientHeight || 700;
|
|
1463
1466
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1464
|
-
const availWidth = Math.max(
|
|
1465
|
-
const availHeight = Math.max(
|
|
1467
|
+
const availWidth = Math.max(280, containerWidth - 48);
|
|
1468
|
+
const availHeight = Math.max(280, containerHeight - 88);
|
|
1466
1469
|
const scaleW = availWidth / unscaledVp.width;
|
|
1467
1470
|
const scaleH = availHeight / unscaledVp.height;
|
|
1468
|
-
|
|
1471
|
+
let fitScale;
|
|
1472
|
+
if (fitMode === "page") {
|
|
1473
|
+
fitScale = Math.max(0.5, Math.min(scaleW, scaleH));
|
|
1474
|
+
} else {
|
|
1475
|
+
fitScale = Math.max(0.65, Math.min(1.15, scaleW));
|
|
1476
|
+
}
|
|
1469
1477
|
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1470
1478
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
1471
1479
|
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
@@ -1491,7 +1499,19 @@ var PdfPlugin = class {
|
|
|
1491
1499
|
}
|
|
1492
1500
|
};
|
|
1493
1501
|
await renderPage(1);
|
|
1502
|
+
let resizeTimer = null;
|
|
1503
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
1504
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1505
|
+
resizeTimer = setTimeout(() => {
|
|
1506
|
+
if (Math.abs(zoomScale - 1) < 0.05) {
|
|
1507
|
+
renderPage(currentPage);
|
|
1508
|
+
}
|
|
1509
|
+
}, 150);
|
|
1510
|
+
});
|
|
1511
|
+
resizeObserver.observe(container);
|
|
1494
1512
|
const cleanup = () => {
|
|
1513
|
+
resizeObserver.disconnect();
|
|
1514
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1495
1515
|
if (currentRenderTask) {
|
|
1496
1516
|
try {
|
|
1497
1517
|
currentRenderTask.cancel();
|
|
@@ -1522,6 +1542,7 @@ var PdfPlugin = class {
|
|
|
1522
1542
|
renderPage(currentPage);
|
|
1523
1543
|
},
|
|
1524
1544
|
fitToPage: () => {
|
|
1545
|
+
fitMode = fitMode === "width" ? "page" : "width";
|
|
1525
1546
|
zoomScale = 1;
|
|
1526
1547
|
rotation = 0;
|
|
1527
1548
|
renderPage(currentPage);
|
|
@@ -2075,8 +2096,53 @@ var DocxPlugin = class {
|
|
|
2075
2096
|
}
|
|
2076
2097
|
}
|
|
2077
2098
|
}
|
|
2078
|
-
|
|
2079
|
-
const cards = wrapper.querySelectorAll(".fp-docx-page-card");
|
|
2099
|
+
let sections = Array.from(wrapper.querySelectorAll("section.docx"));
|
|
2100
|
+
const cards = Array.from(wrapper.querySelectorAll(".fp-docx-page-card"));
|
|
2101
|
+
if (sections.length === 1 && cards.length === 0) {
|
|
2102
|
+
const singleSec = sections[0];
|
|
2103
|
+
const pageH = 1056;
|
|
2104
|
+
const secH = singleSec.offsetHeight || singleSec.scrollHeight;
|
|
2105
|
+
if (secH > pageH * 1.25) {
|
|
2106
|
+
const children = Array.from(singleSec.children);
|
|
2107
|
+
if (children.length > 1) {
|
|
2108
|
+
const parent = singleSec.parentElement || wrapper;
|
|
2109
|
+
const newSections = [singleSec];
|
|
2110
|
+
singleSec.innerHTML = "";
|
|
2111
|
+
singleSec.style.minHeight = `${pageH}px`;
|
|
2112
|
+
singleSec.style.maxHeight = `${pageH}px`;
|
|
2113
|
+
singleSec.style.overflow = "hidden";
|
|
2114
|
+
singleSec.style.boxSizing = "border-box";
|
|
2115
|
+
let curSec = singleSec;
|
|
2116
|
+
let curH = 0;
|
|
2117
|
+
const maxH = pageH - 96;
|
|
2118
|
+
for (let i = 0; i < children.length; i++) {
|
|
2119
|
+
const child = children[i];
|
|
2120
|
+
curSec.appendChild(child);
|
|
2121
|
+
const chH = child.offsetHeight || 28;
|
|
2122
|
+
curH += chH;
|
|
2123
|
+
if (curH >= maxH && i < children.length - 1) {
|
|
2124
|
+
const nextSec = document.createElement("section");
|
|
2125
|
+
nextSec.className = singleSec.className;
|
|
2126
|
+
nextSec.style.cssText = singleSec.style.cssText;
|
|
2127
|
+
nextSec.style.width = singleSec.style.width || "816px";
|
|
2128
|
+
nextSec.style.minHeight = `${pageH}px`;
|
|
2129
|
+
nextSec.style.maxHeight = `${pageH}px`;
|
|
2130
|
+
nextSec.style.overflow = "hidden";
|
|
2131
|
+
nextSec.style.boxSizing = "border-box";
|
|
2132
|
+
nextSec.style.backgroundColor = "#ffffff";
|
|
2133
|
+
nextSec.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
|
|
2134
|
+
nextSec.style.borderRadius = "4px";
|
|
2135
|
+
nextSec.style.marginBottom = "24px";
|
|
2136
|
+
parent.appendChild(nextSec);
|
|
2137
|
+
newSections.push(nextSec);
|
|
2138
|
+
curSec = nextSec;
|
|
2139
|
+
curH = 0;
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
sections = newSections;
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2080
2146
|
const pageElements = sections.length > 0 ? sections : cards;
|
|
2081
2147
|
const totalPages = Math.max(1, pageElements.length);
|
|
2082
2148
|
let currentPage = 1;
|
|
@@ -2120,22 +2186,27 @@ var DocxPlugin = class {
|
|
|
2120
2186
|
}
|
|
2121
2187
|
scale = 1;
|
|
2122
2188
|
let rotation = 0;
|
|
2123
|
-
|
|
2189
|
+
let fitMode = "width";
|
|
2190
|
+
const calculateFitScale = (mode = fitMode) => {
|
|
2124
2191
|
const activeEl = pageElements[currentPage - 1] || wrapper.firstElementChild || wrapper;
|
|
2125
2192
|
const elW = activeEl.offsetWidth || 816;
|
|
2126
|
-
const
|
|
2127
|
-
const availW = Math.max(
|
|
2128
|
-
const availH = Math.max(
|
|
2193
|
+
const singlePageH = Math.min(activeEl.offsetHeight || 1056, Math.round(elW * 1.32));
|
|
2194
|
+
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
2195
|
+
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
2129
2196
|
const sW = availW / elW;
|
|
2130
|
-
const sH = availH /
|
|
2131
|
-
|
|
2197
|
+
const sH = availH / singlePageH;
|
|
2198
|
+
if (mode === "page") {
|
|
2199
|
+
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
2200
|
+
}
|
|
2201
|
+
return Math.max(0.65, Math.min(1.05, sW));
|
|
2132
2202
|
};
|
|
2133
2203
|
const applyTransform = () => {
|
|
2134
2204
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2135
2205
|
wrapper.style.transformOrigin = "top center";
|
|
2136
2206
|
};
|
|
2137
2207
|
setTimeout(() => {
|
|
2138
|
-
|
|
2208
|
+
fitMode = "width";
|
|
2209
|
+
scale = calculateFitScale("width");
|
|
2139
2210
|
applyTransform();
|
|
2140
2211
|
}, 60);
|
|
2141
2212
|
const cleanup = () => {
|
|
@@ -2169,7 +2240,8 @@ var DocxPlugin = class {
|
|
|
2169
2240
|
applyTransform();
|
|
2170
2241
|
},
|
|
2171
2242
|
fitToPage: () => {
|
|
2172
|
-
|
|
2243
|
+
fitMode = fitMode === "width" ? "page" : "width";
|
|
2244
|
+
scale = calculateFitScale(fitMode);
|
|
2173
2245
|
rotation = 0;
|
|
2174
2246
|
applyTransform();
|
|
2175
2247
|
},
|
|
@@ -2239,90 +2311,149 @@ var DocxPlugin = class {
|
|
|
2239
2311
|
console.warn("[DocxPlugin] Error parsing relationships:", relsErr);
|
|
2240
2312
|
}
|
|
2241
2313
|
}
|
|
2242
|
-
const
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2314
|
+
const sectPrs = Array.from(doc.getElementsByTagNameNS("*", "sectPr"));
|
|
2315
|
+
const lastSectPr = sectPrs[sectPrs.length - 1];
|
|
2316
|
+
let defaultW = 12240;
|
|
2317
|
+
let defaultH = 15840;
|
|
2318
|
+
let margins = { top: 1440, right: 1440, bottom: 1440, left: 1440 };
|
|
2319
|
+
if (lastSectPr) {
|
|
2320
|
+
const pgSz = lastSectPr.getElementsByTagNameNS("*", "pgSz")[0];
|
|
2321
|
+
if (pgSz) {
|
|
2322
|
+
defaultW = parseInt(pgSz.getAttribute("w:w") || pgSz.getAttribute("w") || "12240", 10);
|
|
2323
|
+
defaultH = parseInt(pgSz.getAttribute("w:h") || pgSz.getAttribute("h") || "15840", 10);
|
|
2324
|
+
}
|
|
2325
|
+
const pgMar = lastSectPr.getElementsByTagNameNS("*", "pgMar")[0];
|
|
2326
|
+
if (pgMar) {
|
|
2327
|
+
margins.top = parseInt(pgMar.getAttribute("w:top") || pgMar.getAttribute("top") || "1440", 10);
|
|
2328
|
+
margins.bottom = parseInt(pgMar.getAttribute("w:bottom") || pgMar.getAttribute("bottom") || "1440", 10);
|
|
2329
|
+
margins.left = parseInt(pgMar.getAttribute("w:left") || pgMar.getAttribute("left") || "1440", 10);
|
|
2330
|
+
margins.right = parseInt(pgMar.getAttribute("w:right") || pgMar.getAttribute("right") || "1440", 10);
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
const createPageCard = () => {
|
|
2334
|
+
const card = document.createElement("div");
|
|
2335
|
+
card.className = "fp-docx-page-card";
|
|
2336
|
+
card.style.backgroundColor = "#ffffff";
|
|
2337
|
+
card.style.borderRadius = "4px";
|
|
2338
|
+
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
2339
|
+
card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
2340
|
+
card.style.color = "#1e293b";
|
|
2341
|
+
card.style.lineHeight = "1.6";
|
|
2342
|
+
card.style.boxSizing = "border-box";
|
|
2343
|
+
card.style.overflow = "hidden";
|
|
2344
|
+
card.style.position = "relative";
|
|
2345
|
+
card.style.marginBottom = "24px";
|
|
2346
|
+
card.style.width = `${defaultW / 15}px`;
|
|
2347
|
+
card.style.height = `${defaultH / 15}px`;
|
|
2348
|
+
card.style.padding = `${margins.top / 15}px ${margins.right / 15}px ${margins.bottom / 15}px ${margins.left / 15}px`;
|
|
2349
|
+
return card;
|
|
2350
|
+
};
|
|
2351
|
+
let currentCard = createPageCard();
|
|
2352
|
+
let currentHtml = "";
|
|
2353
|
+
const pages = [{ card: currentCard, html: "" }];
|
|
2354
|
+
const flushHtml = () => {
|
|
2355
|
+
pages[pages.length - 1].html += currentHtml;
|
|
2356
|
+
currentHtml = "";
|
|
2357
|
+
};
|
|
2358
|
+
const newPage = () => {
|
|
2359
|
+
flushHtml();
|
|
2360
|
+
currentCard = createPageCard();
|
|
2361
|
+
pages.push({ card: currentCard, html: "" });
|
|
2362
|
+
};
|
|
2251
2363
|
const body = doc.getElementsByTagNameNS("*", "body")[0] || doc.documentElement;
|
|
2252
|
-
let html = "";
|
|
2253
2364
|
for (const child of Array.from(body.children)) {
|
|
2254
2365
|
const tag = child.localName || child.nodeName.split(":").pop();
|
|
2255
2366
|
if (tag === "p") {
|
|
2256
2367
|
const pStyle = child.getElementsByTagNameNS("*", "pStyle")[0];
|
|
2257
2368
|
const styleVal = pStyle?.getAttribute("w:val") || pStyle?.getAttribute("val") || "";
|
|
2258
2369
|
const numPr = child.getElementsByTagNameNS("*", "numPr")[0];
|
|
2259
|
-
const
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2370
|
+
const chunks = this.extractParagraphChunks(child, imageMap);
|
|
2371
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
2372
|
+
if (i > 0) {
|
|
2373
|
+
newPage();
|
|
2374
|
+
}
|
|
2375
|
+
const textContent = chunks[i];
|
|
2376
|
+
if (!textContent.trim() && !textContent.includes("<img")) {
|
|
2377
|
+
currentHtml += '<div style="height: 10px;"></div>';
|
|
2378
|
+
continue;
|
|
2379
|
+
}
|
|
2380
|
+
const lowerStyle = styleVal.toLowerCase();
|
|
2381
|
+
if (lowerStyle.includes("title")) {
|
|
2382
|
+
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>`;
|
|
2383
|
+
} else if (lowerStyle.includes("heading1") || styleVal === "1") {
|
|
2384
|
+
currentHtml += `<h2 style="font-size: 22px; font-weight: 700; color: #1e40af; margin: 20px 0 10px;">${textContent}</h2>`;
|
|
2385
|
+
} else if (lowerStyle.includes("heading2") || styleVal === "2") {
|
|
2386
|
+
currentHtml += `<h3 style="font-size: 18px; font-weight: 600; color: #2563eb; margin: 16px 0 8px;">${textContent}</h3>`;
|
|
2387
|
+
} else if (lowerStyle.includes("heading3") || styleVal === "3") {
|
|
2388
|
+
currentHtml += `<h4 style="font-size: 15px; font-weight: 600; color: #334155; margin: 12px 0 6px;">${textContent}</h4>`;
|
|
2389
|
+
} else if (numPr) {
|
|
2390
|
+
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>`;
|
|
2391
|
+
} else {
|
|
2392
|
+
currentHtml += `<p style="margin: 8px 0; font-size: 14px;">${textContent}</p>`;
|
|
2393
|
+
}
|
|
2277
2394
|
}
|
|
2278
2395
|
} else if (tag === "tbl") {
|
|
2279
|
-
|
|
2396
|
+
currentHtml += '<table style="width: 100%; border-collapse: collapse; margin: 20px 0; border: 1px solid #cbd5e1;">';
|
|
2280
2397
|
const rows = Array.from(child.getElementsByTagNameNS("*", "tr"));
|
|
2281
2398
|
rows.forEach((tr, rIdx) => {
|
|
2282
|
-
|
|
2399
|
+
currentHtml += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
|
|
2283
2400
|
const cells = Array.from(tr.getElementsByTagNameNS("*", "tc"));
|
|
2284
2401
|
cells.forEach((tc) => {
|
|
2285
2402
|
const cellText = this.extractParagraphHtml(tc, imageMap);
|
|
2286
|
-
|
|
2403
|
+
currentHtml += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || " "}</td>`;
|
|
2287
2404
|
});
|
|
2288
|
-
|
|
2405
|
+
currentHtml += "</tr>";
|
|
2289
2406
|
});
|
|
2290
|
-
|
|
2407
|
+
currentHtml += "</table>";
|
|
2291
2408
|
}
|
|
2292
2409
|
}
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2410
|
+
flushHtml();
|
|
2411
|
+
for (const page of pages) {
|
|
2412
|
+
page.card.innerHTML = DOMPurify6.sanitize(page.html, {
|
|
2413
|
+
ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "s", "strike", "img", "div", "br"],
|
|
2414
|
+
ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
|
|
2415
|
+
});
|
|
2416
|
+
wrapper.appendChild(page.card);
|
|
2417
|
+
}
|
|
2298
2418
|
}
|
|
2299
2419
|
extractParagraphHtml(pElement, imageMap = {}) {
|
|
2300
|
-
|
|
2420
|
+
return this.extractParagraphChunks(pElement, imageMap).join("<br/>");
|
|
2421
|
+
}
|
|
2422
|
+
extractParagraphChunks(pElement, imageMap = {}) {
|
|
2423
|
+
const chunks = [""];
|
|
2424
|
+
let currentChunkIndex = 0;
|
|
2301
2425
|
const drawings = Array.from(pElement.getElementsByTagNameNS("*", "drawing"));
|
|
2302
2426
|
for (const drawing of drawings) {
|
|
2303
2427
|
const blip = drawing.getElementsByTagNameNS("*", "blip")[0];
|
|
2304
2428
|
const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
|
|
2305
2429
|
if (rId && imageMap[rId]) {
|
|
2306
|
-
|
|
2430
|
+
chunks[currentChunkIndex] += `<div style="text-align:center; margin: 12px 0;"><img src="${imageMap[rId]}" style="max-width: 100%; height: auto; border-radius: 4px;" /></div>`;
|
|
2307
2431
|
}
|
|
2308
2432
|
}
|
|
2309
2433
|
const runs = Array.from(pElement.getElementsByTagNameNS("*", "r"));
|
|
2310
|
-
if (runs.length === 0 && !
|
|
2311
|
-
|
|
2434
|
+
if (runs.length === 0 && !chunks[currentChunkIndex]) {
|
|
2435
|
+
chunks[currentChunkIndex] = DOMPurify6.sanitize(pElement.textContent || "");
|
|
2436
|
+
return chunks;
|
|
2312
2437
|
}
|
|
2313
2438
|
for (const r of runs) {
|
|
2314
2439
|
const blip = r.getElementsByTagNameNS("*", "blip")[0] || r.getElementsByTagNameNS("*", "imagedata")[0];
|
|
2315
2440
|
const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
|
|
2316
2441
|
if (rId && imageMap[rId]) {
|
|
2317
|
-
|
|
2442
|
+
chunks[currentChunkIndex] += `<img src="${imageMap[rId]}" style="max-width: 100%; height: auto; display: inline-block; margin: 4px;" />`;
|
|
2318
2443
|
}
|
|
2319
|
-
const brs = r.getElementsByTagNameNS("*", "br");
|
|
2320
|
-
for (
|
|
2321
|
-
|
|
2444
|
+
const brs = Array.from(r.getElementsByTagNameNS("*", "br"));
|
|
2445
|
+
for (const br of brs) {
|
|
2446
|
+
const type = br.getAttribute("w:type") || br.getAttribute("type");
|
|
2447
|
+
if (type === "page") {
|
|
2448
|
+
chunks.push("");
|
|
2449
|
+
currentChunkIndex++;
|
|
2450
|
+
} else {
|
|
2451
|
+
chunks[currentChunkIndex] += "<br/>";
|
|
2452
|
+
}
|
|
2322
2453
|
}
|
|
2323
2454
|
const tabs = r.getElementsByTagNameNS("*", "tab");
|
|
2324
2455
|
if (tabs.length > 0) {
|
|
2325
|
-
|
|
2456
|
+
chunks[currentChunkIndex] += " ";
|
|
2326
2457
|
}
|
|
2327
2458
|
const rPr = r.getElementsByTagNameNS("*", "rPr")[0];
|
|
2328
2459
|
const isBold = !!rPr?.getElementsByTagNameNS("*", "b")[0];
|
|
@@ -2336,7 +2467,7 @@ var DocxPlugin = class {
|
|
|
2336
2467
|
const texts = Array.from(r.getElementsByTagNameNS("*", "t"));
|
|
2337
2468
|
let text = texts.map((t) => t.textContent || "").join("");
|
|
2338
2469
|
if (!text) continue;
|
|
2339
|
-
text =
|
|
2470
|
+
text = DOMPurify6.sanitize(text);
|
|
2340
2471
|
let styles = "";
|
|
2341
2472
|
if (isBold) styles += "font-weight: bold; ";
|
|
2342
2473
|
if (isItalic) styles += "font-style: italic; ";
|
|
@@ -2348,12 +2479,12 @@ var DocxPlugin = class {
|
|
|
2348
2479
|
if (!isNaN(pt) && pt > 0) styles += `font-size: ${pt}pt; `;
|
|
2349
2480
|
}
|
|
2350
2481
|
if (styles) {
|
|
2351
|
-
|
|
2482
|
+
chunks[currentChunkIndex] += `<span style="${styles}">${text}</span>`;
|
|
2352
2483
|
} else {
|
|
2353
|
-
|
|
2484
|
+
chunks[currentChunkIndex] += text;
|
|
2354
2485
|
}
|
|
2355
2486
|
}
|
|
2356
|
-
return
|
|
2487
|
+
return chunks;
|
|
2357
2488
|
}
|
|
2358
2489
|
renderBinaryDocFallback(ctx, wrapper) {
|
|
2359
2490
|
const card = document.createElement("div");
|
|
@@ -2370,14 +2501,14 @@ var DocxPlugin = class {
|
|
|
2370
2501
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
2371
2502
|
if (wordDocStream && wordDocStream.length >= 512) {
|
|
2372
2503
|
const text2 = this.extractReadableStrings(wordDocStream);
|
|
2373
|
-
card.innerHTML = `<div style="white-space: pre-wrap;">${
|
|
2504
|
+
card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6.sanitize(text2)}</div>`;
|
|
2374
2505
|
wrapper.appendChild(card);
|
|
2375
2506
|
return;
|
|
2376
2507
|
}
|
|
2377
2508
|
} catch {
|
|
2378
2509
|
}
|
|
2379
2510
|
const text = this.extractReadableStrings(new Uint8Array(ctx.buffer));
|
|
2380
|
-
card.innerHTML = `<div style="white-space: pre-wrap;">${
|
|
2511
|
+
card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6.sanitize(text)}</div>`;
|
|
2381
2512
|
wrapper.appendChild(card);
|
|
2382
2513
|
}
|
|
2383
2514
|
extractReadableStrings(bytes) {
|
|
@@ -2554,11 +2685,9 @@ var ExcelPlugin = class {
|
|
|
2554
2685
|
const calculateFitScale = () => {
|
|
2555
2686
|
const table = contentArea.querySelector("table");
|
|
2556
2687
|
if (!table) return 1;
|
|
2557
|
-
const availW = Math.max(
|
|
2558
|
-
const availH = Math.max(200, container.clientHeight - 80);
|
|
2688
|
+
const availW = Math.max(280, container.clientWidth - 48);
|
|
2559
2689
|
const tW = table.offsetWidth || 800;
|
|
2560
|
-
|
|
2561
|
-
return Math.min(1, Math.min(availW / tW, availH / tH));
|
|
2690
|
+
return Math.max(0.65, Math.min(1, availW / tW));
|
|
2562
2691
|
};
|
|
2563
2692
|
try {
|
|
2564
2693
|
wb = XLSX.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
|
|
@@ -2976,41 +3105,94 @@ var CodePlugin = class {
|
|
|
2976
3105
|
async render(ctx) {
|
|
2977
3106
|
const decoder = new TextDecoder("utf-8");
|
|
2978
3107
|
const fullText = decoder.decode(ctx.buffer);
|
|
2979
|
-
const
|
|
2980
|
-
const
|
|
3108
|
+
const extRaw = ctx.metadata.extension?.toLowerCase();
|
|
3109
|
+
const mimeRaw = ctx.metadata.mimeType?.toLowerCase();
|
|
3110
|
+
const isTxt = extRaw === ".txt" || mimeRaw === "text/plain" && (!extRaw || !this.extensions.filter((e) => e !== ".txt").includes(extRaw));
|
|
3111
|
+
let rawPages = [];
|
|
3112
|
+
if (isTxt) {
|
|
3113
|
+
const explicitPages = fullText.split(/(?:\f|\x0C)/);
|
|
3114
|
+
for (const ep of explicitPages) {
|
|
3115
|
+
const lines = ep.split(/\r?\n/);
|
|
3116
|
+
let currentChunk = [];
|
|
3117
|
+
for (let i = 0; i < lines.length; i++) {
|
|
3118
|
+
currentChunk.push(lines[i]);
|
|
3119
|
+
if (currentChunk.length >= 46) {
|
|
3120
|
+
rawPages.push(currentChunk.join("\n"));
|
|
3121
|
+
currentChunk = [];
|
|
3122
|
+
}
|
|
3123
|
+
}
|
|
3124
|
+
if (currentChunk.length > 0 || lines.length === 0) {
|
|
3125
|
+
rawPages.push(currentChunk.join("\n"));
|
|
3126
|
+
}
|
|
3127
|
+
}
|
|
3128
|
+
if (rawPages.length === 0) rawPages = [""];
|
|
3129
|
+
} else {
|
|
3130
|
+
const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
|
|
3131
|
+
rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
3132
|
+
}
|
|
2981
3133
|
const totalPages = Math.max(1, rawPages.length);
|
|
2982
3134
|
let currentPage = 1;
|
|
2983
3135
|
const container = document.createElement("div");
|
|
2984
3136
|
container.style.width = "100%";
|
|
2985
3137
|
container.style.height = "100%";
|
|
2986
3138
|
container.style.overflow = "auto";
|
|
2987
|
-
container.style.backgroundColor = "#1e1e1e";
|
|
2988
|
-
container.style.color = "#d4d4d4";
|
|
2989
|
-
container.style.padding = "16px";
|
|
2990
|
-
container.style.boxSizing = "border-box";
|
|
2991
3139
|
let fontSize = 13;
|
|
2992
3140
|
let rotation = 0;
|
|
3141
|
+
let zoomLevel = 1;
|
|
2993
3142
|
const pre = document.createElement("pre");
|
|
2994
|
-
pre.style.margin = "0";
|
|
2995
|
-
pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
|
|
2996
|
-
pre.style.fontSize = `${fontSize}px`;
|
|
2997
|
-
pre.style.lineHeight = "1.5";
|
|
2998
|
-
pre.style.whiteSpace = "pre-wrap";
|
|
2999
|
-
pre.style.wordBreak = "break-all";
|
|
3000
3143
|
const code = document.createElement("code");
|
|
3144
|
+
if (isTxt) {
|
|
3145
|
+
container.style.backgroundColor = "#f1f5f9";
|
|
3146
|
+
container.style.padding = "32px";
|
|
3147
|
+
container.style.boxSizing = "border-box";
|
|
3148
|
+
container.style.display = "flex";
|
|
3149
|
+
container.style.flexDirection = "column";
|
|
3150
|
+
container.style.alignItems = "center";
|
|
3151
|
+
pre.style.margin = "0";
|
|
3152
|
+
pre.style.fontFamily = "Consolas, 'Courier New', monospace";
|
|
3153
|
+
pre.style.fontSize = "13px";
|
|
3154
|
+
pre.style.color = "#1e293b";
|
|
3155
|
+
pre.style.lineHeight = "1.5";
|
|
3156
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3157
|
+
pre.style.wordBreak = "break-word";
|
|
3158
|
+
pre.style.backgroundColor = "#ffffff";
|
|
3159
|
+
pre.style.width = "816px";
|
|
3160
|
+
pre.style.minHeight = "1056px";
|
|
3161
|
+
pre.style.padding = "72px 56px";
|
|
3162
|
+
pre.style.boxSizing = "border-box";
|
|
3163
|
+
pre.style.boxShadow = "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)";
|
|
3164
|
+
pre.style.borderRadius = "4px";
|
|
3165
|
+
pre.style.transformOrigin = "top center";
|
|
3166
|
+
} else {
|
|
3167
|
+
container.style.backgroundColor = "#1e1e1e";
|
|
3168
|
+
container.style.color = "#d4d4d4";
|
|
3169
|
+
container.style.padding = "16px";
|
|
3170
|
+
container.style.boxSizing = "border-box";
|
|
3171
|
+
pre.style.margin = "0";
|
|
3172
|
+
pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
|
|
3173
|
+
pre.style.fontSize = `${fontSize}px`;
|
|
3174
|
+
pre.style.lineHeight = "1.5";
|
|
3175
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3176
|
+
pre.style.wordBreak = "break-all";
|
|
3177
|
+
pre.style.transformOrigin = "top left";
|
|
3178
|
+
}
|
|
3001
3179
|
const ext = (ctx.metadata.extension || "").replace(".", "");
|
|
3002
3180
|
const renderCodePage = (text) => {
|
|
3003
|
-
|
|
3004
|
-
if (ext && hljs.getLanguage(ext)) {
|
|
3005
|
-
code.innerHTML = hljs.highlight(text, { language: ext }).value;
|
|
3006
|
-
} else {
|
|
3007
|
-
code.innerHTML = hljs.highlightAuto(text).value;
|
|
3008
|
-
}
|
|
3009
|
-
} catch {
|
|
3181
|
+
if (isTxt) {
|
|
3010
3182
|
code.textContent = text;
|
|
3183
|
+
} else {
|
|
3184
|
+
try {
|
|
3185
|
+
if (ext && hljs.getLanguage(ext)) {
|
|
3186
|
+
code.innerHTML = hljs.highlight(text, { language: ext }).value;
|
|
3187
|
+
} else {
|
|
3188
|
+
code.innerHTML = hljs.highlightAuto(text).value;
|
|
3189
|
+
}
|
|
3190
|
+
} catch {
|
|
3191
|
+
code.textContent = text;
|
|
3192
|
+
}
|
|
3011
3193
|
}
|
|
3012
3194
|
};
|
|
3013
|
-
renderCodePage(rawPages[0] || fullText);
|
|
3195
|
+
renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
|
|
3014
3196
|
pre.appendChild(code);
|
|
3015
3197
|
container.appendChild(pre);
|
|
3016
3198
|
let indicator = null;
|
|
@@ -3019,15 +3201,22 @@ var CodePlugin = class {
|
|
|
3019
3201
|
indicator.className = "fp-code-page-indicator";
|
|
3020
3202
|
indicator.style.position = "sticky";
|
|
3021
3203
|
indicator.style.bottom = "16px";
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3204
|
+
if (isTxt) {
|
|
3205
|
+
indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
|
|
3206
|
+
indicator.style.color = "#334155";
|
|
3207
|
+
indicator.style.border = "1px solid #e2e8f0";
|
|
3208
|
+
indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
|
|
3209
|
+
} else {
|
|
3210
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3211
|
+
indicator.style.color = "#f8fafc";
|
|
3212
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3213
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3214
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
3215
|
+
}
|
|
3025
3216
|
indicator.style.fontSize = "12px";
|
|
3026
3217
|
indicator.style.fontWeight = "600";
|
|
3027
3218
|
indicator.style.padding = "5px 14px";
|
|
3028
3219
|
indicator.style.borderRadius = "20px";
|
|
3029
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3030
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3031
3220
|
indicator.style.zIndex = "10";
|
|
3032
3221
|
indicator.style.userSelect = "none";
|
|
3033
3222
|
indicator.style.pointerEvents = "none";
|
|
@@ -3038,7 +3227,7 @@ var CodePlugin = class {
|
|
|
3038
3227
|
}
|
|
3039
3228
|
const showPage = (pageNum) => {
|
|
3040
3229
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3041
|
-
renderCodePage(rawPages[currentPage - 1] || fullText);
|
|
3230
|
+
renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
|
|
3042
3231
|
if (indicator) {
|
|
3043
3232
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3044
3233
|
}
|
|
@@ -3054,39 +3243,57 @@ var CodePlugin = class {
|
|
|
3054
3243
|
ctx.container.innerHTML = "";
|
|
3055
3244
|
};
|
|
3056
3245
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3246
|
+
const updateTransform = () => {
|
|
3247
|
+
if (isTxt) {
|
|
3248
|
+
pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
|
|
3249
|
+
} else {
|
|
3250
|
+
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3251
|
+
pre.style.fontSize = `${fontSize}px`;
|
|
3252
|
+
}
|
|
3253
|
+
};
|
|
3057
3254
|
return {
|
|
3058
3255
|
destroy: cleanup,
|
|
3059
3256
|
getPageCount: () => totalPages,
|
|
3060
3257
|
getCurrentPage: () => currentPage,
|
|
3061
3258
|
goToPage: (page) => showPage(page),
|
|
3062
3259
|
zoomIn: () => {
|
|
3063
|
-
|
|
3064
|
-
|
|
3260
|
+
if (isTxt) {
|
|
3261
|
+
zoomLevel = Math.min(3, zoomLevel + 0.1);
|
|
3262
|
+
} else {
|
|
3263
|
+
fontSize = Math.min(32, fontSize + 2);
|
|
3264
|
+
}
|
|
3265
|
+
updateTransform();
|
|
3065
3266
|
},
|
|
3066
3267
|
zoomOut: () => {
|
|
3067
|
-
|
|
3068
|
-
|
|
3268
|
+
if (isTxt) {
|
|
3269
|
+
zoomLevel = Math.max(0.1, zoomLevel - 0.1);
|
|
3270
|
+
} else {
|
|
3271
|
+
fontSize = Math.max(8, fontSize - 2);
|
|
3272
|
+
}
|
|
3273
|
+
updateTransform();
|
|
3069
3274
|
},
|
|
3070
|
-
getZoom: () => fontSize / 13,
|
|
3275
|
+
getZoom: () => isTxt ? zoomLevel : fontSize / 13,
|
|
3071
3276
|
setZoom: (level) => {
|
|
3072
|
-
|
|
3073
|
-
|
|
3277
|
+
if (isTxt) {
|
|
3278
|
+
zoomLevel = level;
|
|
3279
|
+
} else {
|
|
3280
|
+
fontSize = Math.round(13 * level);
|
|
3281
|
+
}
|
|
3282
|
+
updateTransform();
|
|
3074
3283
|
},
|
|
3075
3284
|
fitToPage: () => {
|
|
3076
3285
|
fontSize = 13;
|
|
3077
3286
|
rotation = 0;
|
|
3078
|
-
|
|
3079
|
-
|
|
3287
|
+
zoomLevel = isTxt ? Math.max(0.65, Math.min(1.05, (container.clientWidth - 48) / 816)) : 1;
|
|
3288
|
+
updateTransform();
|
|
3080
3289
|
},
|
|
3081
3290
|
rotateCW: () => {
|
|
3082
3291
|
rotation = (rotation + 90) % 360;
|
|
3083
|
-
|
|
3084
|
-
pre.style.transformOrigin = "top left";
|
|
3292
|
+
updateTransform();
|
|
3085
3293
|
},
|
|
3086
3294
|
rotateCCW: () => {
|
|
3087
3295
|
rotation = (rotation - 90 + 360) % 360;
|
|
3088
|
-
|
|
3089
|
-
pre.style.transformOrigin = "top left";
|
|
3296
|
+
updateTransform();
|
|
3090
3297
|
},
|
|
3091
3298
|
download: () => {
|
|
3092
3299
|
const mimeType = ctx.metadata.mimeType || "text/plain";
|
|
@@ -3385,7 +3592,7 @@ var MarkdownPlugin = class {
|
|
|
3385
3592
|
gfm: true,
|
|
3386
3593
|
breaks: true
|
|
3387
3594
|
});
|
|
3388
|
-
const cleanHtml =
|
|
3595
|
+
const cleanHtml = DOMPurify6.sanitize(rawHtml, {
|
|
3389
3596
|
USE_PROFILES: { html: true }
|
|
3390
3597
|
});
|
|
3391
3598
|
const wrapper = document.createElement("div");
|
|
@@ -4021,6 +4228,14 @@ var RtfPlugin = class {
|
|
|
4021
4228
|
group: "actions",
|
|
4022
4229
|
execute: () => instance.download?.()
|
|
4023
4230
|
},
|
|
4231
|
+
{
|
|
4232
|
+
id: "copy",
|
|
4233
|
+
icon: "copy",
|
|
4234
|
+
label: "Copy Text",
|
|
4235
|
+
type: "button",
|
|
4236
|
+
group: "actions",
|
|
4237
|
+
execute: () => instance.copy?.()
|
|
4238
|
+
},
|
|
4024
4239
|
{
|
|
4025
4240
|
id: "print",
|
|
4026
4241
|
icon: "print",
|
|
@@ -4051,20 +4266,27 @@ var RtfPlugin = class {
|
|
|
4051
4266
|
let scale = 1;
|
|
4052
4267
|
let rotation = 0;
|
|
4053
4268
|
let pageElements = [];
|
|
4054
|
-
|
|
4269
|
+
let fitMode = "width";
|
|
4270
|
+
const calculateFitScale = (mode = fitMode) => {
|
|
4055
4271
|
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4056
4272
|
const elW = activeEl.offsetWidth || 850;
|
|
4057
|
-
const
|
|
4058
|
-
const availW = Math.max(
|
|
4059
|
-
const availH = Math.max(
|
|
4060
|
-
|
|
4273
|
+
const singlePageH = Math.min(activeEl.offsetHeight || 1056, Math.round(elW * 1.32));
|
|
4274
|
+
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
4275
|
+
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
4276
|
+
const sW = availW / elW;
|
|
4277
|
+
const sH = availH / singlePageH;
|
|
4278
|
+
if (mode === "page") {
|
|
4279
|
+
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
4280
|
+
}
|
|
4281
|
+
return Math.max(0.65, Math.min(1.05, sW));
|
|
4061
4282
|
};
|
|
4062
4283
|
const applyTransform = () => {
|
|
4063
4284
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4064
4285
|
wrapper.style.transformOrigin = "top center";
|
|
4065
4286
|
};
|
|
4066
4287
|
setTimeout(() => {
|
|
4067
|
-
|
|
4288
|
+
fitMode = "width";
|
|
4289
|
+
scale = calculateFitScale("width");
|
|
4068
4290
|
applyTransform();
|
|
4069
4291
|
}, 60);
|
|
4070
4292
|
try {
|
|
@@ -4082,14 +4304,31 @@ var RtfPlugin = class {
|
|
|
4082
4304
|
} catch (err) {
|
|
4083
4305
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
4084
4306
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
4085
|
-
const
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4307
|
+
const rawPages = text.split(/\\page\b/).map((segment) => {
|
|
4308
|
+
return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
|
|
4309
|
+
}).filter((p) => p.length > 0);
|
|
4310
|
+
const pages = rawPages.length > 0 ? rawPages : [text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim()];
|
|
4311
|
+
for (let i = 0; i < pages.length; i++) {
|
|
4312
|
+
const pageCard = document.createElement("div");
|
|
4313
|
+
pageCard.className = "fp-rtf-page-card";
|
|
4314
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
4315
|
+
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4316
|
+
pageCard.style.borderRadius = "4px";
|
|
4317
|
+
pageCard.style.padding = "72px 56px";
|
|
4318
|
+
pageCard.style.width = "816px";
|
|
4319
|
+
pageCard.style.minHeight = "1056px";
|
|
4320
|
+
pageCard.style.maxWidth = "100%";
|
|
4321
|
+
pageCard.style.boxSizing = "border-box";
|
|
4322
|
+
pageCard.style.fontFamily = "serif";
|
|
4323
|
+
pageCard.style.fontSize = "12pt";
|
|
4324
|
+
pageCard.style.lineHeight = "1.6";
|
|
4325
|
+
pageCard.style.color = "#1e293b";
|
|
4326
|
+
pageCard.style.whiteSpace = "pre-wrap";
|
|
4327
|
+
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4328
|
+
pageCard.textContent = pages[i];
|
|
4329
|
+
wrapper.appendChild(pageCard);
|
|
4330
|
+
pageElements.push(pageCard);
|
|
4331
|
+
}
|
|
4093
4332
|
}
|
|
4094
4333
|
const totalPages = Math.max(1, pageElements.length);
|
|
4095
4334
|
let currentPage = 1;
|
|
@@ -4156,7 +4395,8 @@ var RtfPlugin = class {
|
|
|
4156
4395
|
applyTransform();
|
|
4157
4396
|
},
|
|
4158
4397
|
fitToPage: () => {
|
|
4159
|
-
|
|
4398
|
+
fitMode = fitMode === "width" ? "page" : "width";
|
|
4399
|
+
scale = calculateFitScale(fitMode);
|
|
4160
4400
|
rotation = 0;
|
|
4161
4401
|
applyTransform();
|
|
4162
4402
|
},
|
|
@@ -4177,6 +4417,10 @@ var RtfPlugin = class {
|
|
|
4177
4417
|
a.click();
|
|
4178
4418
|
URL.revokeObjectURL(url);
|
|
4179
4419
|
},
|
|
4420
|
+
copy: () => {
|
|
4421
|
+
const text = wrapper.textContent || "";
|
|
4422
|
+
navigator.clipboard?.writeText(text);
|
|
4423
|
+
},
|
|
4180
4424
|
print: () => {
|
|
4181
4425
|
window.print();
|
|
4182
4426
|
}
|
|
@@ -4251,7 +4495,7 @@ var HtmlPreviewPlugin = class {
|
|
|
4251
4495
|
}
|
|
4252
4496
|
async render(ctx) {
|
|
4253
4497
|
const rawHtml = new TextDecoder("utf-8").decode(ctx.buffer);
|
|
4254
|
-
const sanitized =
|
|
4498
|
+
const sanitized = DOMPurify6.sanitize(rawHtml, {
|
|
4255
4499
|
WHOLE_DOCUMENT: true,
|
|
4256
4500
|
ADD_TAGS: ["style", "link"],
|
|
4257
4501
|
ADD_ATTR: ["target", "rel"]
|
|
@@ -4471,19 +4715,29 @@ var OpenDocumentPlugin = class {
|
|
|
4471
4715
|
ctx.container.appendChild(container);
|
|
4472
4716
|
let scale = 1;
|
|
4473
4717
|
let rotation = 0;
|
|
4474
|
-
|
|
4718
|
+
let fitMode = "width";
|
|
4719
|
+
const calculateFitScale = (mode = fitMode) => {
|
|
4475
4720
|
const elW = wrapper.offsetWidth || 850;
|
|
4476
|
-
const
|
|
4477
|
-
const availW = Math.max(
|
|
4478
|
-
const availH = Math.max(
|
|
4479
|
-
|
|
4721
|
+
const singlePageH = Math.min(wrapper.offsetHeight || 1056, Math.round(elW * 1.32));
|
|
4722
|
+
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
4723
|
+
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
4724
|
+
const sW = availW / elW;
|
|
4725
|
+
const sH = availH / (isPresentation ? 540 : singlePageH);
|
|
4726
|
+
if (isPresentation) {
|
|
4727
|
+
return Math.min(1, Math.min(sW, sH));
|
|
4728
|
+
}
|
|
4729
|
+
if (mode === "page") {
|
|
4730
|
+
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
4731
|
+
}
|
|
4732
|
+
return Math.max(0.65, Math.min(1.05, sW));
|
|
4480
4733
|
};
|
|
4481
4734
|
const applyTransform = () => {
|
|
4482
4735
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4483
4736
|
wrapper.style.transformOrigin = "top center";
|
|
4484
4737
|
};
|
|
4485
4738
|
setTimeout(() => {
|
|
4486
|
-
|
|
4739
|
+
fitMode = "width";
|
|
4740
|
+
scale = calculateFitScale("width");
|
|
4487
4741
|
applyTransform();
|
|
4488
4742
|
}, 60);
|
|
4489
4743
|
let currentPage = 1;
|
|
@@ -4517,14 +4771,97 @@ var OpenDocumentPlugin = class {
|
|
|
4517
4771
|
wrapper.textContent = contentDoc.documentElement.textContent || "Formula content";
|
|
4518
4772
|
}
|
|
4519
4773
|
} else {
|
|
4520
|
-
wrapper.style.maxWidth = "
|
|
4521
|
-
wrapper.style.padding = "
|
|
4774
|
+
wrapper.style.maxWidth = "none";
|
|
4775
|
+
wrapper.style.padding = "0";
|
|
4522
4776
|
wrapper.style.minHeight = "100%";
|
|
4777
|
+
wrapper.style.backgroundColor = "transparent";
|
|
4778
|
+
wrapper.style.boxShadow = "none";
|
|
4779
|
+
wrapper.style.position = "relative";
|
|
4780
|
+
const dims = this.getPageDimensions(stylesDoc, contentDoc);
|
|
4523
4781
|
const bodyHtml = this.renderOdfBody(contentDoc, styleMap, imageUrls);
|
|
4524
|
-
|
|
4525
|
-
|
|
4782
|
+
const tempDiv = document.createElement("div");
|
|
4783
|
+
tempDiv.style.width = `${dims.width - dims.marginLeft - dims.marginRight}px`;
|
|
4784
|
+
tempDiv.style.position = "absolute";
|
|
4785
|
+
tempDiv.style.visibility = "hidden";
|
|
4786
|
+
tempDiv.innerHTML = DOMPurify6.sanitize(bodyHtml, {
|
|
4787
|
+
ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub", "hr"],
|
|
4526
4788
|
ADD_ATTR: ["style", "colspan", "rowspan"]
|
|
4527
4789
|
});
|
|
4790
|
+
document.body.appendChild(tempDiv);
|
|
4791
|
+
const contentHeight = dims.height - dims.marginTop - dims.marginBottom;
|
|
4792
|
+
const pageElements = [[]];
|
|
4793
|
+
let currentHeight = 0;
|
|
4794
|
+
let currentPageIdx = 0;
|
|
4795
|
+
Array.from(tempDiv.children).forEach((child) => {
|
|
4796
|
+
const el = child;
|
|
4797
|
+
const style = el.getAttribute("style") || "";
|
|
4798
|
+
const isBreakBefore = style.includes("page-break-before: always");
|
|
4799
|
+
const isBreakAfter = style.includes("page-break-after: always");
|
|
4800
|
+
const isSoftBreak = el.classList.contains("odf-page-break");
|
|
4801
|
+
if (isBreakBefore) {
|
|
4802
|
+
if (pageElements[currentPageIdx].length > 0) {
|
|
4803
|
+
currentPageIdx++;
|
|
4804
|
+
pageElements.push([]);
|
|
4805
|
+
currentHeight = 0;
|
|
4806
|
+
}
|
|
4807
|
+
}
|
|
4808
|
+
const h = el.offsetHeight || 0;
|
|
4809
|
+
if (currentHeight + h > contentHeight && pageElements[currentPageIdx].length > 0 && !isSoftBreak) {
|
|
4810
|
+
currentPageIdx++;
|
|
4811
|
+
pageElements.push([]);
|
|
4812
|
+
currentHeight = 0;
|
|
4813
|
+
}
|
|
4814
|
+
if (!isSoftBreak) {
|
|
4815
|
+
pageElements[currentPageIdx].push(el.cloneNode(true));
|
|
4816
|
+
currentHeight += h;
|
|
4817
|
+
}
|
|
4818
|
+
if (isBreakAfter || isSoftBreak) {
|
|
4819
|
+
currentPageIdx++;
|
|
4820
|
+
pageElements.push([]);
|
|
4821
|
+
currentHeight = 0;
|
|
4822
|
+
}
|
|
4823
|
+
});
|
|
4824
|
+
document.body.removeChild(tempDiv);
|
|
4825
|
+
if (pageElements.length > 1 && pageElements[pageElements.length - 1].length === 0) {
|
|
4826
|
+
pageElements.pop();
|
|
4827
|
+
}
|
|
4828
|
+
totalPages = Math.max(1, pageElements.length);
|
|
4829
|
+
pageElements.forEach((elements, idx) => {
|
|
4830
|
+
const page = document.createElement("div");
|
|
4831
|
+
page.className = `fp-odt-page fp-odt-page-${idx + 1}`;
|
|
4832
|
+
page.style.width = `${dims.width}px`;
|
|
4833
|
+
page.style.minHeight = `${dims.height}px`;
|
|
4834
|
+
page.style.padding = `${dims.marginTop}px ${dims.marginRight}px ${dims.marginBottom}px ${dims.marginLeft}px`;
|
|
4835
|
+
page.style.margin = "0 auto";
|
|
4836
|
+
page.style.backgroundColor = "#ffffff";
|
|
4837
|
+
page.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
|
|
4838
|
+
page.style.borderRadius = "4px";
|
|
4839
|
+
page.style.boxSizing = "border-box";
|
|
4840
|
+
page.style.display = idx === 0 ? "block" : "none";
|
|
4841
|
+
page.style.position = "absolute";
|
|
4842
|
+
page.style.top = "0";
|
|
4843
|
+
page.style.left = "50%";
|
|
4844
|
+
page.style.transform = "translateX(-50%)";
|
|
4845
|
+
elements.forEach((el) => page.appendChild(el));
|
|
4846
|
+
wrapper.appendChild(page);
|
|
4847
|
+
slides.push(page);
|
|
4848
|
+
});
|
|
4849
|
+
const pageIndicator = document.createElement("div");
|
|
4850
|
+
pageIndicator.className = "fp-odt-page-indicator";
|
|
4851
|
+
pageIndicator.style.position = "sticky";
|
|
4852
|
+
pageIndicator.style.bottom = "16px";
|
|
4853
|
+
pageIndicator.style.left = "50%";
|
|
4854
|
+
pageIndicator.style.transform = "translateX(-50%)";
|
|
4855
|
+
pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
|
4856
|
+
pageIndicator.style.color = "#fff";
|
|
4857
|
+
pageIndicator.style.padding = "6px 12px";
|
|
4858
|
+
pageIndicator.style.borderRadius = "16px";
|
|
4859
|
+
pageIndicator.style.fontSize = "12px";
|
|
4860
|
+
pageIndicator.style.zIndex = "100";
|
|
4861
|
+
pageIndicator.style.display = "inline-block";
|
|
4862
|
+
pageIndicator.style.width = "fit-content";
|
|
4863
|
+
pageIndicator.textContent = `Page 1 of ${totalPages}`;
|
|
4864
|
+
container.appendChild(pageIndicator);
|
|
4528
4865
|
}
|
|
4529
4866
|
const cleanup = () => {
|
|
4530
4867
|
imageUrls.forEach((url) => URL.revokeObjectURL(url));
|
|
@@ -4533,11 +4870,15 @@ var OpenDocumentPlugin = class {
|
|
|
4533
4870
|
};
|
|
4534
4871
|
ctx.signal.addEventListener("abort", cleanup);
|
|
4535
4872
|
const goToPage = (page) => {
|
|
4536
|
-
if (
|
|
4873
|
+
if (page < 1 || page > totalPages) return;
|
|
4537
4874
|
currentPage = page;
|
|
4538
4875
|
slides.forEach((s, idx) => {
|
|
4539
4876
|
s.style.display = idx === page - 1 ? "block" : "none";
|
|
4540
4877
|
});
|
|
4878
|
+
const indicator = container.querySelector(".fp-odt-page-indicator");
|
|
4879
|
+
if (indicator) {
|
|
4880
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4881
|
+
}
|
|
4541
4882
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4542
4883
|
};
|
|
4543
4884
|
return {
|
|
@@ -4557,7 +4898,8 @@ var OpenDocumentPlugin = class {
|
|
|
4557
4898
|
applyTransform();
|
|
4558
4899
|
},
|
|
4559
4900
|
fitToPage: () => {
|
|
4560
|
-
|
|
4901
|
+
fitMode = fitMode === "width" ? "page" : "width";
|
|
4902
|
+
scale = calculateFitScale(fitMode);
|
|
4561
4903
|
rotation = 0;
|
|
4562
4904
|
applyTransform();
|
|
4563
4905
|
},
|
|
@@ -4606,6 +4948,43 @@ var OpenDocumentPlugin = class {
|
|
|
4606
4948
|
}
|
|
4607
4949
|
};
|
|
4608
4950
|
}
|
|
4951
|
+
getPageDimensions(stylesDoc, contentDoc) {
|
|
4952
|
+
let width = 850;
|
|
4953
|
+
let height = 1123;
|
|
4954
|
+
let marginTop = 48;
|
|
4955
|
+
let marginBottom = 48;
|
|
4956
|
+
let marginLeft = 48;
|
|
4957
|
+
let marginRight = 48;
|
|
4958
|
+
const parseUnit = (val) => {
|
|
4959
|
+
if (!val) return null;
|
|
4960
|
+
if (val.endsWith("cm")) return parseFloat(val) * 37.8;
|
|
4961
|
+
if (val.endsWith("mm")) return parseFloat(val) * 3.78;
|
|
4962
|
+
if (val.endsWith("in")) return parseFloat(val) * 96;
|
|
4963
|
+
if (val.endsWith("pt")) return parseFloat(val) * 1.33;
|
|
4964
|
+
if (val.endsWith("px")) return parseFloat(val);
|
|
4965
|
+
return parseFloat(val);
|
|
4966
|
+
};
|
|
4967
|
+
const docs = [stylesDoc, contentDoc].filter(Boolean);
|
|
4968
|
+
for (const doc of docs) {
|
|
4969
|
+
const pageLayout = doc.querySelector("page-layout-properties, [page-width]");
|
|
4970
|
+
if (pageLayout) {
|
|
4971
|
+
const w = parseUnit(pageLayout.getAttribute("fo:page-width") || pageLayout.getAttribute("page-width"));
|
|
4972
|
+
const h = parseUnit(pageLayout.getAttribute("fo:page-height") || pageLayout.getAttribute("page-height"));
|
|
4973
|
+
const mt = parseUnit(pageLayout.getAttribute("fo:margin-top") || pageLayout.getAttribute("margin-top"));
|
|
4974
|
+
const mb = parseUnit(pageLayout.getAttribute("fo:margin-bottom") || pageLayout.getAttribute("margin-bottom"));
|
|
4975
|
+
const ml = parseUnit(pageLayout.getAttribute("fo:margin-left") || pageLayout.getAttribute("margin-left"));
|
|
4976
|
+
const mr = parseUnit(pageLayout.getAttribute("fo:margin-right") || pageLayout.getAttribute("margin-right"));
|
|
4977
|
+
if (w !== null) width = w;
|
|
4978
|
+
if (h !== null) height = h;
|
|
4979
|
+
if (mt !== null) marginTop = mt;
|
|
4980
|
+
if (mb !== null) marginBottom = mb;
|
|
4981
|
+
if (ml !== null) marginLeft = ml;
|
|
4982
|
+
if (mr !== null) marginRight = mr;
|
|
4983
|
+
break;
|
|
4984
|
+
}
|
|
4985
|
+
}
|
|
4986
|
+
return { width, height, marginTop, marginBottom, marginLeft, marginRight };
|
|
4987
|
+
}
|
|
4609
4988
|
extractStyles(stylesDoc, contentDoc) {
|
|
4610
4989
|
const map = /* @__PURE__ */ new Map();
|
|
4611
4990
|
const styleNodes = [];
|
|
@@ -4628,14 +5007,21 @@ var OpenDocumentPlugin = class {
|
|
|
4628
5007
|
if (color) css += `color: ${color}; `;
|
|
4629
5008
|
if (size) css += `font-size: ${size}; `;
|
|
4630
5009
|
}
|
|
4631
|
-
|
|
5010
|
+
let paraProp = node.querySelector("paragraph-properties, [text-align]");
|
|
5011
|
+
if (!paraProp) {
|
|
5012
|
+
paraProp = Array.from(node.children).find((c) => c.tagName.includes("paragraph-properties")) || null;
|
|
5013
|
+
}
|
|
4632
5014
|
if (paraProp) {
|
|
4633
5015
|
const align = paraProp.getAttribute("fo:text-align") || paraProp.getAttribute("text-align");
|
|
4634
5016
|
const mt = paraProp.getAttribute("fo:margin-top") || paraProp.getAttribute("margin-top");
|
|
4635
5017
|
const mb = paraProp.getAttribute("fo:margin-bottom") || paraProp.getAttribute("margin-bottom");
|
|
5018
|
+
const breakBefore = paraProp.getAttribute("fo:break-before") || paraProp.getAttribute("break-before");
|
|
5019
|
+
const breakAfter = paraProp.getAttribute("fo:break-after") || paraProp.getAttribute("break-after");
|
|
4636
5020
|
if (align) css += `text-align: ${align}; `;
|
|
4637
5021
|
if (mt) css += `margin-top: ${mt}; `;
|
|
4638
5022
|
if (mb) css += `margin-bottom: ${mb}; `;
|
|
5023
|
+
if (breakBefore === "page") css += "page-break-before: always; ";
|
|
5024
|
+
if (breakAfter === "page") css += "page-break-after: always; ";
|
|
4639
5025
|
}
|
|
4640
5026
|
if (css) map.set(name, css);
|
|
4641
5027
|
}
|
|
@@ -4720,6 +5106,8 @@ var OpenDocumentPlugin = class {
|
|
|
4720
5106
|
result += " ";
|
|
4721
5107
|
} else if (tag === "line-break") {
|
|
4722
5108
|
result += "<br/>";
|
|
5109
|
+
} else if (tag === "soft-page-break") {
|
|
5110
|
+
result += '<hr class="odf-page-break" style="page-break-after: always; border: none; margin: 0; padding: 0; height: 0;" />';
|
|
4723
5111
|
} else {
|
|
4724
5112
|
result += el.textContent || "";
|
|
4725
5113
|
}
|
|
@@ -4880,20 +5268,9 @@ var DocPlugin = class {
|
|
|
4880
5268
|
container.style.overflow = "auto";
|
|
4881
5269
|
container.style.padding = "32px 16px";
|
|
4882
5270
|
container.style.backgroundColor = "#f1f5f9";
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
wrapper.style.margin = "0 auto";
|
|
4887
|
-
wrapper.style.backgroundColor = "#ffffff";
|
|
4888
|
-
wrapper.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4889
|
-
wrapper.style.borderRadius = "4px";
|
|
4890
|
-
wrapper.style.padding = "56px 48px";
|
|
4891
|
-
wrapper.style.minHeight = "100%";
|
|
4892
|
-
wrapper.style.transformOrigin = "top center";
|
|
4893
|
-
wrapper.style.transition = "transform 0.2s ease";
|
|
4894
|
-
wrapper.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4895
|
-
wrapper.style.color = "#1e293b";
|
|
4896
|
-
container.appendChild(wrapper);
|
|
5271
|
+
container.style.display = "flex";
|
|
5272
|
+
container.style.justifyContent = "center";
|
|
5273
|
+
container.style.alignItems = "flex-start";
|
|
4897
5274
|
ctx.container.appendChild(container);
|
|
4898
5275
|
let scale = 1;
|
|
4899
5276
|
let extractedRawText = "";
|
|
@@ -4920,21 +5297,27 @@ var DocPlugin = class {
|
|
|
4920
5297
|
const rawPages = this.splitIntoPages(extractedRawText);
|
|
4921
5298
|
const totalPages = Math.max(1, rawPages.length);
|
|
4922
5299
|
let currentPage = 1;
|
|
4923
|
-
wrapper.innerHTML = "";
|
|
4924
5300
|
const pageCards = [];
|
|
4925
5301
|
for (let i = 0; i < totalPages; i++) {
|
|
4926
5302
|
const pageCard = document.createElement("div");
|
|
4927
5303
|
pageCard.className = "fp-doc-page-card";
|
|
5304
|
+
pageCard.style.width = "816px";
|
|
5305
|
+
pageCard.style.height = "1056px";
|
|
4928
5306
|
pageCard.style.backgroundColor = "#ffffff";
|
|
4929
5307
|
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4930
5308
|
pageCard.style.borderRadius = "4px";
|
|
4931
|
-
pageCard.style.padding = "
|
|
4932
|
-
pageCard.style.
|
|
5309
|
+
pageCard.style.padding = "96px 72px";
|
|
5310
|
+
pageCard.style.boxSizing = "border-box";
|
|
5311
|
+
pageCard.style.overflow = "hidden";
|
|
4933
5312
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
5313
|
+
pageCard.style.transformOrigin = "top center";
|
|
5314
|
+
pageCard.style.transition = "transform 0.2s ease";
|
|
5315
|
+
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
5316
|
+
pageCard.style.color = "#1e293b";
|
|
4934
5317
|
if (isFallback && i === 0) {
|
|
4935
5318
|
pageCard.innerHTML = `
|
|
4936
5319
|
<div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
|
|
4937
|
-
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${
|
|
5320
|
+
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify6.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
|
|
4938
5321
|
<span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
|
|
4939
5322
|
</div>
|
|
4940
5323
|
${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
|
|
@@ -4942,15 +5325,17 @@ var DocPlugin = class {
|
|
|
4942
5325
|
} else {
|
|
4943
5326
|
pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
|
|
4944
5327
|
}
|
|
4945
|
-
|
|
5328
|
+
container.appendChild(pageCard);
|
|
4946
5329
|
pageCards.push(pageCard);
|
|
4947
5330
|
}
|
|
4948
5331
|
let indicator = null;
|
|
4949
5332
|
if (totalPages > 1) {
|
|
4950
5333
|
indicator = document.createElement("div");
|
|
4951
5334
|
indicator.className = "fp-doc-page-indicator";
|
|
4952
|
-
indicator.style.position = "
|
|
5335
|
+
indicator.style.position = "fixed";
|
|
4953
5336
|
indicator.style.bottom = "16px";
|
|
5337
|
+
indicator.style.left = "50%";
|
|
5338
|
+
indicator.style.transform = "translateX(-50%)";
|
|
4954
5339
|
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4955
5340
|
indicator.style.backdropFilter = "blur(8px)";
|
|
4956
5341
|
indicator.style.color = "#f8fafc";
|
|
@@ -4964,17 +5349,25 @@ var DocPlugin = class {
|
|
|
4964
5349
|
indicator.style.userSelect = "none";
|
|
4965
5350
|
indicator.style.pointerEvents = "none";
|
|
4966
5351
|
indicator.style.textAlign = "center";
|
|
4967
|
-
indicator.style.width = "fit-content";
|
|
4968
|
-
indicator.style.margin = "16px auto 0";
|
|
4969
5352
|
container.appendChild(indicator);
|
|
4970
5353
|
}
|
|
5354
|
+
let rotation = 0;
|
|
5355
|
+
const applyTransform = () => {
|
|
5356
|
+
const activeCard = pageCards[currentPage - 1];
|
|
5357
|
+
if (activeCard) {
|
|
5358
|
+
activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5359
|
+
}
|
|
5360
|
+
};
|
|
4971
5361
|
const showPage = (pageNum) => {
|
|
4972
5362
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
card.style.display =
|
|
4976
|
-
|
|
4977
|
-
|
|
5363
|
+
pageCards.forEach((card, idx) => {
|
|
5364
|
+
if (idx + 1 === currentPage) {
|
|
5365
|
+
card.style.display = "block";
|
|
5366
|
+
card.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5367
|
+
} else {
|
|
5368
|
+
card.style.display = "none";
|
|
5369
|
+
}
|
|
5370
|
+
});
|
|
4978
5371
|
if (indicator) {
|
|
4979
5372
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4980
5373
|
}
|
|
@@ -4983,21 +5376,22 @@ var DocPlugin = class {
|
|
|
4983
5376
|
if (totalPages > 1) {
|
|
4984
5377
|
showPage(1);
|
|
4985
5378
|
}
|
|
4986
|
-
let
|
|
4987
|
-
const calculateFitScale = () => {
|
|
4988
|
-
const
|
|
4989
|
-
const
|
|
4990
|
-
const
|
|
4991
|
-
const
|
|
4992
|
-
const
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
5379
|
+
let fitMode = "width";
|
|
5380
|
+
const calculateFitScale = (mode = fitMode) => {
|
|
5381
|
+
const elW = 816;
|
|
5382
|
+
const elH = 1056;
|
|
5383
|
+
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
5384
|
+
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
5385
|
+
const sW = availW / elW;
|
|
5386
|
+
const sH = availH / elH;
|
|
5387
|
+
if (mode === "page") {
|
|
5388
|
+
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
5389
|
+
}
|
|
5390
|
+
return Math.max(0.65, Math.min(1.05, sW));
|
|
4998
5391
|
};
|
|
4999
5392
|
setTimeout(() => {
|
|
5000
|
-
|
|
5393
|
+
fitMode = "width";
|
|
5394
|
+
scale = calculateFitScale("width");
|
|
5001
5395
|
applyTransform();
|
|
5002
5396
|
}, 60);
|
|
5003
5397
|
const cleanup = () => {
|
|
@@ -5025,7 +5419,8 @@ var DocPlugin = class {
|
|
|
5025
5419
|
applyTransform();
|
|
5026
5420
|
},
|
|
5027
5421
|
fitToPage: () => {
|
|
5028
|
-
|
|
5422
|
+
fitMode = fitMode === "width" ? "page" : "width";
|
|
5423
|
+
scale = calculateFitScale(fitMode);
|
|
5029
5424
|
rotation = 0;
|
|
5030
5425
|
applyTransform();
|
|
5031
5426
|
},
|
|
@@ -5153,8 +5548,28 @@ var DocPlugin = class {
|
|
|
5153
5548
|
}
|
|
5154
5549
|
splitIntoPages(text) {
|
|
5155
5550
|
if (!text) return [""];
|
|
5156
|
-
const
|
|
5157
|
-
|
|
5551
|
+
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);
|
|
5552
|
+
if (explicitParts.length === 0) explicitParts.push(text);
|
|
5553
|
+
const maxLinesPerPage = 48;
|
|
5554
|
+
const finalPages = [];
|
|
5555
|
+
for (const part of explicitParts) {
|
|
5556
|
+
const lines = part.split(/\r?\n/);
|
|
5557
|
+
let currentLines = [];
|
|
5558
|
+
let count = 0;
|
|
5559
|
+
for (const line of lines) {
|
|
5560
|
+
currentLines.push(line);
|
|
5561
|
+
count++;
|
|
5562
|
+
if (count >= maxLinesPerPage) {
|
|
5563
|
+
finalPages.push(currentLines.join("\n"));
|
|
5564
|
+
currentLines = [];
|
|
5565
|
+
count = 0;
|
|
5566
|
+
}
|
|
5567
|
+
}
|
|
5568
|
+
if (currentLines.length > 0) {
|
|
5569
|
+
finalPages.push(currentLines.join("\n"));
|
|
5570
|
+
}
|
|
5571
|
+
}
|
|
5572
|
+
return finalPages.length > 0 ? finalPages : [text];
|
|
5158
5573
|
}
|
|
5159
5574
|
/**
|
|
5160
5575
|
* Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
|
|
@@ -5163,17 +5578,65 @@ var DocPlugin = class {
|
|
|
5163
5578
|
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
|
|
5164
5579
|
let html = "";
|
|
5165
5580
|
let inList = false;
|
|
5166
|
-
|
|
5167
|
-
|
|
5581
|
+
let tableLines = [];
|
|
5582
|
+
const flushTable = () => {
|
|
5583
|
+
if (tableLines.length > 0) {
|
|
5584
|
+
html += '<table style="width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 12px;">';
|
|
5585
|
+
for (const tLine of tableLines) {
|
|
5586
|
+
html += "<tr>";
|
|
5587
|
+
const cols = tLine.split(" ");
|
|
5588
|
+
for (const col of cols) {
|
|
5589
|
+
html += `<td style="border: 1px solid #cbd5e1; padding: 6px 8px;">${DOMPurify6.sanitize(col.trim())}</td>`;
|
|
5590
|
+
}
|
|
5591
|
+
html += "</tr>";
|
|
5592
|
+
}
|
|
5593
|
+
html += "</table>";
|
|
5594
|
+
tableLines = [];
|
|
5595
|
+
}
|
|
5596
|
+
};
|
|
5597
|
+
let i = 0;
|
|
5598
|
+
while (i < lines.length) {
|
|
5599
|
+
let line = lines[i];
|
|
5600
|
+
let tabCount = (line.match(/\t/g) || []).length;
|
|
5601
|
+
if (tabCount > 0) {
|
|
5602
|
+
let consecutiveTableLines = 1;
|
|
5603
|
+
let j = i + 1;
|
|
5604
|
+
while (j < lines.length) {
|
|
5605
|
+
const nextTabCount = (lines[j].match(/\t/g) || []).length;
|
|
5606
|
+
if (nextTabCount === tabCount) {
|
|
5607
|
+
consecutiveTableLines++;
|
|
5608
|
+
j++;
|
|
5609
|
+
} else {
|
|
5610
|
+
break;
|
|
5611
|
+
}
|
|
5612
|
+
}
|
|
5613
|
+
if (consecutiveTableLines >= 3) {
|
|
5614
|
+
if (inList) {
|
|
5615
|
+
html += "</ul>";
|
|
5616
|
+
inList = false;
|
|
5617
|
+
}
|
|
5618
|
+
tableLines = lines.slice(i, j);
|
|
5619
|
+
flushTable();
|
|
5620
|
+
i = j;
|
|
5621
|
+
continue;
|
|
5622
|
+
}
|
|
5623
|
+
}
|
|
5624
|
+
line = line.trim();
|
|
5168
5625
|
if (!line) {
|
|
5169
5626
|
if (inList) {
|
|
5170
5627
|
html += "</ul>";
|
|
5171
5628
|
inList = false;
|
|
5172
5629
|
}
|
|
5630
|
+
html += '<div style="height: 1.15em;"></div>';
|
|
5631
|
+
i++;
|
|
5632
|
+
continue;
|
|
5633
|
+
}
|
|
5634
|
+
if (/^[\x00-\x1F\x7F-\x9F]+$/.test(line)) {
|
|
5635
|
+
i++;
|
|
5173
5636
|
continue;
|
|
5174
5637
|
}
|
|
5175
|
-
if (
|
|
5176
|
-
|
|
5638
|
+
if ((line.includes("Normal.dot") || line.includes("Microsoft Word") || line.includes("Times New Roman")) && line.length < 30) {
|
|
5639
|
+
i++;
|
|
5177
5640
|
continue;
|
|
5178
5641
|
}
|
|
5179
5642
|
if (line.length < 60 && !line.endsWith(".") && (/^[A-Z0-9\s:_-]+$/.test(line) || line.startsWith("#"))) {
|
|
@@ -5181,24 +5644,26 @@ var DocPlugin = class {
|
|
|
5181
5644
|
html += "</ul>";
|
|
5182
5645
|
inList = false;
|
|
5183
5646
|
}
|
|
5184
|
-
html += `<h2 style="font-size:
|
|
5647
|
+
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>`;
|
|
5185
5648
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
5186
5649
|
if (!inList) {
|
|
5187
5650
|
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
5188
5651
|
inList = true;
|
|
5189
5652
|
}
|
|
5190
5653
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
5191
|
-
html += `<li style="margin: 4px 0; line-height: 1.
|
|
5654
|
+
html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6.sanitize(bulletText)}</li>`;
|
|
5192
5655
|
} else {
|
|
5193
5656
|
if (inList) {
|
|
5194
5657
|
html += "</ul>";
|
|
5195
5658
|
inList = false;
|
|
5196
5659
|
}
|
|
5197
|
-
html += `<p style="line-height: 1.
|
|
5660
|
+
html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6.sanitize(line)}</p>`;
|
|
5198
5661
|
}
|
|
5662
|
+
i++;
|
|
5199
5663
|
}
|
|
5200
5664
|
if (inList) html += "</ul>";
|
|
5201
|
-
|
|
5665
|
+
flushTable();
|
|
5666
|
+
return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify6.sanitize(filename)})</p>`;
|
|
5202
5667
|
}
|
|
5203
5668
|
};
|
|
5204
5669
|
function docPlugin() {
|
|
@@ -5376,7 +5841,7 @@ var PptPlugin = class {
|
|
|
5376
5841
|
if (s.pictureUrl) {
|
|
5377
5842
|
contentHtml = `
|
|
5378
5843
|
<div style="flex: 1; display: flex; justify-content: center; align-items: center; padding: 12px; overflow: hidden;">
|
|
5379
|
-
<img src="${s.pictureUrl}" alt="${
|
|
5844
|
+
<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;" />
|
|
5380
5845
|
</div>
|
|
5381
5846
|
`;
|
|
5382
5847
|
} else if (s.tableColumns.length > 0) {
|
|
@@ -5386,7 +5851,7 @@ var PptPlugin = class {
|
|
|
5386
5851
|
<table style="width: 100%; border-collapse: collapse; border: 1px solid #cbd5e1; border-radius: 6px; overflow: hidden; background: #ffffff;">
|
|
5387
5852
|
<thead>
|
|
5388
5853
|
<tr style="background: #e2e8f0; color: #1e293b; font-weight: 600; font-size: 14px;">
|
|
5389
|
-
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${
|
|
5854
|
+
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify6.sanitize(c)}</th>`).join("")}
|
|
5390
5855
|
</tr>
|
|
5391
5856
|
</thead>
|
|
5392
5857
|
<tbody>
|
|
@@ -5402,7 +5867,7 @@ var PptPlugin = class {
|
|
|
5402
5867
|
} else {
|
|
5403
5868
|
const pTags = s.paragraphs.map((p) => {
|
|
5404
5869
|
const lines = p.split(/[\r\n]+/).map((l) => l.trim()).filter(Boolean);
|
|
5405
|
-
return lines.map((l) => `<p style="margin: 0 0 14px; font-size: 14px; line-height: 1.65; color: #334155; text-align: justify;">${
|
|
5870
|
+
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("");
|
|
5406
5871
|
}).join("");
|
|
5407
5872
|
contentHtml = `
|
|
5408
5873
|
<div style="flex: 1; overflow: auto; padding: 4px 8px; display: flex; flex-direction: column; justify-content: flex-start;">
|
|
@@ -5415,11 +5880,11 @@ var PptPlugin = class {
|
|
|
5415
5880
|
<!-- Header Banner matching PowerPoint design -->
|
|
5416
5881
|
<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;">
|
|
5417
5882
|
<h1 style="margin: 0; font-size: 26px; font-weight: 700; color: #1e293b; letter-spacing: -0.3px;">
|
|
5418
|
-
${
|
|
5883
|
+
${DOMPurify6.sanitize(s.title)}
|
|
5419
5884
|
</h1>
|
|
5420
5885
|
${s.subtitle ? `
|
|
5421
5886
|
<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);">
|
|
5422
|
-
${
|
|
5887
|
+
${DOMPurify6.sanitize(s.subtitle)}
|
|
5423
5888
|
</span>
|
|
5424
5889
|
` : `
|
|
5425
5890
|
<span style="font-size: 12px; color: #365314; font-weight: 600;">
|