@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/angular.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Component, ChangeDetectionStrategy, Input, Output, ViewChild, EventEmitter as EventEmitter$1 } from '@angular/core';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
|
-
import
|
|
3
|
+
import DOMPurify6 from 'dompurify';
|
|
4
4
|
import * as pdfjsLib from 'pdfjs-dist';
|
|
5
5
|
import * as docx from 'docx-preview';
|
|
6
6
|
import { unzipSync, strFromU8, unzip } from 'fflate';
|
|
@@ -405,7 +405,7 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
405
405
|
if (magicMime === "application/zip") {
|
|
406
406
|
const ooxmlMime = detectOoxmlType(buffer);
|
|
407
407
|
if (ooxmlMime && ooxmlMime !== "application/zip") {
|
|
408
|
-
metadata.mimeType = ooxmlMime;
|
|
408
|
+
metadata.mimeType = metadata.mimeType ?? ooxmlMime;
|
|
409
409
|
if (ooxmlMime.includes("wordprocessing")) metadata.extension = metadata.extension ?? ".docx";
|
|
410
410
|
else if (ooxmlMime.includes("spreadsheet")) metadata.extension = metadata.extension ?? ".xlsx";
|
|
411
411
|
else if (ooxmlMime.includes("presentation")) metadata.extension = metadata.extension ?? ".pptx";
|
|
@@ -434,7 +434,7 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
434
434
|
return { buffer, metadata };
|
|
435
435
|
}
|
|
436
436
|
function sanitizeSVG(svg) {
|
|
437
|
-
return
|
|
437
|
+
return DOMPurify6.sanitize(svg, {
|
|
438
438
|
USE_PROFILES: { svg: true, svgFilters: true }
|
|
439
439
|
});
|
|
440
440
|
}
|
|
@@ -481,7 +481,8 @@ function createElement(tag, attrs, ...children) {
|
|
|
481
481
|
}
|
|
482
482
|
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>`;
|
|
483
483
|
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>`;
|
|
484
|
-
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"><
|
|
484
|
+
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>`;
|
|
485
|
+
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>`;
|
|
485
486
|
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>`;
|
|
486
487
|
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>`;
|
|
487
488
|
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>`;
|
|
@@ -501,6 +502,7 @@ var ICON_MAP = {
|
|
|
501
502
|
"zoom-in": ICON_ZOOM_IN,
|
|
502
503
|
"zoom-out": ICON_ZOOM_OUT,
|
|
503
504
|
"fit-page": ICON_FIT_PAGE,
|
|
505
|
+
"fit-width": ICON_FIT_WIDTH,
|
|
504
506
|
"fit-slide": ICON_FIT_PAGE,
|
|
505
507
|
"rotate-cw": ICON_ROTATE_CW,
|
|
506
508
|
"rotate-ccw": ICON_ROTATE_CCW,
|
|
@@ -1447,6 +1449,7 @@ var PdfPlugin = class {
|
|
|
1447
1449
|
let currentPage = 1;
|
|
1448
1450
|
let zoomScale = 1;
|
|
1449
1451
|
let rotation = 0;
|
|
1452
|
+
let fitMode = "width";
|
|
1450
1453
|
let currentRenderTask = null;
|
|
1451
1454
|
const renderPage = async (pageNum) => {
|
|
1452
1455
|
if (currentRenderTask) {
|
|
@@ -1466,11 +1469,16 @@ var PdfPlugin = class {
|
|
|
1466
1469
|
const containerWidth = container.clientWidth || 900;
|
|
1467
1470
|
const containerHeight = container.clientHeight || 700;
|
|
1468
1471
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1469
|
-
const availWidth = Math.max(
|
|
1470
|
-
const availHeight = Math.max(
|
|
1472
|
+
const availWidth = Math.max(280, containerWidth - 48);
|
|
1473
|
+
const availHeight = Math.max(280, containerHeight - 88);
|
|
1471
1474
|
const scaleW = availWidth / unscaledVp.width;
|
|
1472
1475
|
const scaleH = availHeight / unscaledVp.height;
|
|
1473
|
-
|
|
1476
|
+
let fitScale;
|
|
1477
|
+
if (fitMode === "page") {
|
|
1478
|
+
fitScale = Math.max(0.5, Math.min(scaleW, scaleH));
|
|
1479
|
+
} else {
|
|
1480
|
+
fitScale = Math.max(0.65, Math.min(1.15, scaleW));
|
|
1481
|
+
}
|
|
1474
1482
|
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1475
1483
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
1476
1484
|
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
@@ -1496,7 +1504,19 @@ var PdfPlugin = class {
|
|
|
1496
1504
|
}
|
|
1497
1505
|
};
|
|
1498
1506
|
await renderPage(1);
|
|
1507
|
+
let resizeTimer = null;
|
|
1508
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
1509
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1510
|
+
resizeTimer = setTimeout(() => {
|
|
1511
|
+
if (Math.abs(zoomScale - 1) < 0.05) {
|
|
1512
|
+
renderPage(currentPage);
|
|
1513
|
+
}
|
|
1514
|
+
}, 150);
|
|
1515
|
+
});
|
|
1516
|
+
resizeObserver.observe(container);
|
|
1499
1517
|
const cleanup = () => {
|
|
1518
|
+
resizeObserver.disconnect();
|
|
1519
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1500
1520
|
if (currentRenderTask) {
|
|
1501
1521
|
try {
|
|
1502
1522
|
currentRenderTask.cancel();
|
|
@@ -1527,6 +1547,7 @@ var PdfPlugin = class {
|
|
|
1527
1547
|
renderPage(currentPage);
|
|
1528
1548
|
},
|
|
1529
1549
|
fitToPage: () => {
|
|
1550
|
+
fitMode = fitMode === "width" ? "page" : "width";
|
|
1530
1551
|
zoomScale = 1;
|
|
1531
1552
|
rotation = 0;
|
|
1532
1553
|
renderPage(currentPage);
|
|
@@ -2080,8 +2101,53 @@ var DocxPlugin = class {
|
|
|
2080
2101
|
}
|
|
2081
2102
|
}
|
|
2082
2103
|
}
|
|
2083
|
-
|
|
2084
|
-
const cards = wrapper.querySelectorAll(".fp-docx-page-card");
|
|
2104
|
+
let sections = Array.from(wrapper.querySelectorAll("section.docx"));
|
|
2105
|
+
const cards = Array.from(wrapper.querySelectorAll(".fp-docx-page-card"));
|
|
2106
|
+
if (sections.length === 1 && cards.length === 0) {
|
|
2107
|
+
const singleSec = sections[0];
|
|
2108
|
+
const pageH = 1056;
|
|
2109
|
+
const secH = singleSec.offsetHeight || singleSec.scrollHeight;
|
|
2110
|
+
if (secH > pageH * 1.25) {
|
|
2111
|
+
const children = Array.from(singleSec.children);
|
|
2112
|
+
if (children.length > 1) {
|
|
2113
|
+
const parent = singleSec.parentElement || wrapper;
|
|
2114
|
+
const newSections = [singleSec];
|
|
2115
|
+
singleSec.innerHTML = "";
|
|
2116
|
+
singleSec.style.minHeight = `${pageH}px`;
|
|
2117
|
+
singleSec.style.maxHeight = `${pageH}px`;
|
|
2118
|
+
singleSec.style.overflow = "hidden";
|
|
2119
|
+
singleSec.style.boxSizing = "border-box";
|
|
2120
|
+
let curSec = singleSec;
|
|
2121
|
+
let curH = 0;
|
|
2122
|
+
const maxH = pageH - 96;
|
|
2123
|
+
for (let i = 0; i < children.length; i++) {
|
|
2124
|
+
const child = children[i];
|
|
2125
|
+
curSec.appendChild(child);
|
|
2126
|
+
const chH = child.offsetHeight || 28;
|
|
2127
|
+
curH += chH;
|
|
2128
|
+
if (curH >= maxH && i < children.length - 1) {
|
|
2129
|
+
const nextSec = document.createElement("section");
|
|
2130
|
+
nextSec.className = singleSec.className;
|
|
2131
|
+
nextSec.style.cssText = singleSec.style.cssText;
|
|
2132
|
+
nextSec.style.width = singleSec.style.width || "816px";
|
|
2133
|
+
nextSec.style.minHeight = `${pageH}px`;
|
|
2134
|
+
nextSec.style.maxHeight = `${pageH}px`;
|
|
2135
|
+
nextSec.style.overflow = "hidden";
|
|
2136
|
+
nextSec.style.boxSizing = "border-box";
|
|
2137
|
+
nextSec.style.backgroundColor = "#ffffff";
|
|
2138
|
+
nextSec.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
|
|
2139
|
+
nextSec.style.borderRadius = "4px";
|
|
2140
|
+
nextSec.style.marginBottom = "24px";
|
|
2141
|
+
parent.appendChild(nextSec);
|
|
2142
|
+
newSections.push(nextSec);
|
|
2143
|
+
curSec = nextSec;
|
|
2144
|
+
curH = 0;
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
sections = newSections;
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2085
2151
|
const pageElements = sections.length > 0 ? sections : cards;
|
|
2086
2152
|
const totalPages = Math.max(1, pageElements.length);
|
|
2087
2153
|
let currentPage = 1;
|
|
@@ -2125,22 +2191,27 @@ var DocxPlugin = class {
|
|
|
2125
2191
|
}
|
|
2126
2192
|
scale = 1;
|
|
2127
2193
|
let rotation = 0;
|
|
2128
|
-
|
|
2194
|
+
let fitMode = "width";
|
|
2195
|
+
const calculateFitScale = (mode = fitMode) => {
|
|
2129
2196
|
const activeEl = pageElements[currentPage - 1] || wrapper.firstElementChild || wrapper;
|
|
2130
2197
|
const elW = activeEl.offsetWidth || 816;
|
|
2131
|
-
const
|
|
2132
|
-
const availW = Math.max(
|
|
2133
|
-
const availH = Math.max(
|
|
2198
|
+
const singlePageH = Math.min(activeEl.offsetHeight || 1056, Math.round(elW * 1.32));
|
|
2199
|
+
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
2200
|
+
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
2134
2201
|
const sW = availW / elW;
|
|
2135
|
-
const sH = availH /
|
|
2136
|
-
|
|
2202
|
+
const sH = availH / singlePageH;
|
|
2203
|
+
if (mode === "page") {
|
|
2204
|
+
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
2205
|
+
}
|
|
2206
|
+
return Math.max(0.65, Math.min(1.05, sW));
|
|
2137
2207
|
};
|
|
2138
2208
|
const applyTransform = () => {
|
|
2139
2209
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2140
2210
|
wrapper.style.transformOrigin = "top center";
|
|
2141
2211
|
};
|
|
2142
2212
|
setTimeout(() => {
|
|
2143
|
-
|
|
2213
|
+
fitMode = "width";
|
|
2214
|
+
scale = calculateFitScale("width");
|
|
2144
2215
|
applyTransform();
|
|
2145
2216
|
}, 60);
|
|
2146
2217
|
const cleanup = () => {
|
|
@@ -2174,7 +2245,8 @@ var DocxPlugin = class {
|
|
|
2174
2245
|
applyTransform();
|
|
2175
2246
|
},
|
|
2176
2247
|
fitToPage: () => {
|
|
2177
|
-
|
|
2248
|
+
fitMode = fitMode === "width" ? "page" : "width";
|
|
2249
|
+
scale = calculateFitScale(fitMode);
|
|
2178
2250
|
rotation = 0;
|
|
2179
2251
|
applyTransform();
|
|
2180
2252
|
},
|
|
@@ -2244,90 +2316,149 @@ var DocxPlugin = class {
|
|
|
2244
2316
|
console.warn("[DocxPlugin] Error parsing relationships:", relsErr);
|
|
2245
2317
|
}
|
|
2246
2318
|
}
|
|
2247
|
-
const
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2319
|
+
const sectPrs = Array.from(doc.getElementsByTagNameNS("*", "sectPr"));
|
|
2320
|
+
const lastSectPr = sectPrs[sectPrs.length - 1];
|
|
2321
|
+
let defaultW = 12240;
|
|
2322
|
+
let defaultH = 15840;
|
|
2323
|
+
let margins = { top: 1440, right: 1440, bottom: 1440, left: 1440 };
|
|
2324
|
+
if (lastSectPr) {
|
|
2325
|
+
const pgSz = lastSectPr.getElementsByTagNameNS("*", "pgSz")[0];
|
|
2326
|
+
if (pgSz) {
|
|
2327
|
+
defaultW = parseInt(pgSz.getAttribute("w:w") || pgSz.getAttribute("w") || "12240", 10);
|
|
2328
|
+
defaultH = parseInt(pgSz.getAttribute("w:h") || pgSz.getAttribute("h") || "15840", 10);
|
|
2329
|
+
}
|
|
2330
|
+
const pgMar = lastSectPr.getElementsByTagNameNS("*", "pgMar")[0];
|
|
2331
|
+
if (pgMar) {
|
|
2332
|
+
margins.top = parseInt(pgMar.getAttribute("w:top") || pgMar.getAttribute("top") || "1440", 10);
|
|
2333
|
+
margins.bottom = parseInt(pgMar.getAttribute("w:bottom") || pgMar.getAttribute("bottom") || "1440", 10);
|
|
2334
|
+
margins.left = parseInt(pgMar.getAttribute("w:left") || pgMar.getAttribute("left") || "1440", 10);
|
|
2335
|
+
margins.right = parseInt(pgMar.getAttribute("w:right") || pgMar.getAttribute("right") || "1440", 10);
|
|
2336
|
+
}
|
|
2337
|
+
}
|
|
2338
|
+
const createPageCard = () => {
|
|
2339
|
+
const card = document.createElement("div");
|
|
2340
|
+
card.className = "fp-docx-page-card";
|
|
2341
|
+
card.style.backgroundColor = "#ffffff";
|
|
2342
|
+
card.style.borderRadius = "4px";
|
|
2343
|
+
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
2344
|
+
card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
2345
|
+
card.style.color = "#1e293b";
|
|
2346
|
+
card.style.lineHeight = "1.6";
|
|
2347
|
+
card.style.boxSizing = "border-box";
|
|
2348
|
+
card.style.overflow = "hidden";
|
|
2349
|
+
card.style.position = "relative";
|
|
2350
|
+
card.style.marginBottom = "24px";
|
|
2351
|
+
card.style.width = `${defaultW / 15}px`;
|
|
2352
|
+
card.style.height = `${defaultH / 15}px`;
|
|
2353
|
+
card.style.padding = `${margins.top / 15}px ${margins.right / 15}px ${margins.bottom / 15}px ${margins.left / 15}px`;
|
|
2354
|
+
return card;
|
|
2355
|
+
};
|
|
2356
|
+
let currentCard = createPageCard();
|
|
2357
|
+
let currentHtml = "";
|
|
2358
|
+
const pages = [{ card: currentCard, html: "" }];
|
|
2359
|
+
const flushHtml = () => {
|
|
2360
|
+
pages[pages.length - 1].html += currentHtml;
|
|
2361
|
+
currentHtml = "";
|
|
2362
|
+
};
|
|
2363
|
+
const newPage = () => {
|
|
2364
|
+
flushHtml();
|
|
2365
|
+
currentCard = createPageCard();
|
|
2366
|
+
pages.push({ card: currentCard, html: "" });
|
|
2367
|
+
};
|
|
2256
2368
|
const body = doc.getElementsByTagNameNS("*", "body")[0] || doc.documentElement;
|
|
2257
|
-
let html = "";
|
|
2258
2369
|
for (const child of Array.from(body.children)) {
|
|
2259
2370
|
const tag = child.localName || child.nodeName.split(":").pop();
|
|
2260
2371
|
if (tag === "p") {
|
|
2261
2372
|
const pStyle = child.getElementsByTagNameNS("*", "pStyle")[0];
|
|
2262
2373
|
const styleVal = pStyle?.getAttribute("w:val") || pStyle?.getAttribute("val") || "";
|
|
2263
2374
|
const numPr = child.getElementsByTagNameNS("*", "numPr")[0];
|
|
2264
|
-
const
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2375
|
+
const chunks = this.extractParagraphChunks(child, imageMap);
|
|
2376
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
2377
|
+
if (i > 0) {
|
|
2378
|
+
newPage();
|
|
2379
|
+
}
|
|
2380
|
+
const textContent = chunks[i];
|
|
2381
|
+
if (!textContent.trim() && !textContent.includes("<img")) {
|
|
2382
|
+
currentHtml += '<div style="height: 10px;"></div>';
|
|
2383
|
+
continue;
|
|
2384
|
+
}
|
|
2385
|
+
const lowerStyle = styleVal.toLowerCase();
|
|
2386
|
+
if (lowerStyle.includes("title")) {
|
|
2387
|
+
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>`;
|
|
2388
|
+
} else if (lowerStyle.includes("heading1") || styleVal === "1") {
|
|
2389
|
+
currentHtml += `<h2 style="font-size: 22px; font-weight: 700; color: #1e40af; margin: 20px 0 10px;">${textContent}</h2>`;
|
|
2390
|
+
} else if (lowerStyle.includes("heading2") || styleVal === "2") {
|
|
2391
|
+
currentHtml += `<h3 style="font-size: 18px; font-weight: 600; color: #2563eb; margin: 16px 0 8px;">${textContent}</h3>`;
|
|
2392
|
+
} else if (lowerStyle.includes("heading3") || styleVal === "3") {
|
|
2393
|
+
currentHtml += `<h4 style="font-size: 15px; font-weight: 600; color: #334155; margin: 12px 0 6px;">${textContent}</h4>`;
|
|
2394
|
+
} else if (numPr) {
|
|
2395
|
+
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>`;
|
|
2396
|
+
} else {
|
|
2397
|
+
currentHtml += `<p style="margin: 8px 0; font-size: 14px;">${textContent}</p>`;
|
|
2398
|
+
}
|
|
2282
2399
|
}
|
|
2283
2400
|
} else if (tag === "tbl") {
|
|
2284
|
-
|
|
2401
|
+
currentHtml += '<table style="width: 100%; border-collapse: collapse; margin: 20px 0; border: 1px solid #cbd5e1;">';
|
|
2285
2402
|
const rows = Array.from(child.getElementsByTagNameNS("*", "tr"));
|
|
2286
2403
|
rows.forEach((tr, rIdx) => {
|
|
2287
|
-
|
|
2404
|
+
currentHtml += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
|
|
2288
2405
|
const cells = Array.from(tr.getElementsByTagNameNS("*", "tc"));
|
|
2289
2406
|
cells.forEach((tc) => {
|
|
2290
2407
|
const cellText = this.extractParagraphHtml(tc, imageMap);
|
|
2291
|
-
|
|
2408
|
+
currentHtml += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || " "}</td>`;
|
|
2292
2409
|
});
|
|
2293
|
-
|
|
2410
|
+
currentHtml += "</tr>";
|
|
2294
2411
|
});
|
|
2295
|
-
|
|
2412
|
+
currentHtml += "</table>";
|
|
2296
2413
|
}
|
|
2297
2414
|
}
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2415
|
+
flushHtml();
|
|
2416
|
+
for (const page of pages) {
|
|
2417
|
+
page.card.innerHTML = DOMPurify6.sanitize(page.html, {
|
|
2418
|
+
ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "s", "strike", "img", "div", "br"],
|
|
2419
|
+
ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
|
|
2420
|
+
});
|
|
2421
|
+
wrapper.appendChild(page.card);
|
|
2422
|
+
}
|
|
2303
2423
|
}
|
|
2304
2424
|
extractParagraphHtml(pElement, imageMap = {}) {
|
|
2305
|
-
|
|
2425
|
+
return this.extractParagraphChunks(pElement, imageMap).join("<br/>");
|
|
2426
|
+
}
|
|
2427
|
+
extractParagraphChunks(pElement, imageMap = {}) {
|
|
2428
|
+
const chunks = [""];
|
|
2429
|
+
let currentChunkIndex = 0;
|
|
2306
2430
|
const drawings = Array.from(pElement.getElementsByTagNameNS("*", "drawing"));
|
|
2307
2431
|
for (const drawing of drawings) {
|
|
2308
2432
|
const blip = drawing.getElementsByTagNameNS("*", "blip")[0];
|
|
2309
2433
|
const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
|
|
2310
2434
|
if (rId && imageMap[rId]) {
|
|
2311
|
-
|
|
2435
|
+
chunks[currentChunkIndex] += `<div style="text-align:center; margin: 12px 0;"><img src="${imageMap[rId]}" style="max-width: 100%; height: auto; border-radius: 4px;" /></div>`;
|
|
2312
2436
|
}
|
|
2313
2437
|
}
|
|
2314
2438
|
const runs = Array.from(pElement.getElementsByTagNameNS("*", "r"));
|
|
2315
|
-
if (runs.length === 0 && !
|
|
2316
|
-
|
|
2439
|
+
if (runs.length === 0 && !chunks[currentChunkIndex]) {
|
|
2440
|
+
chunks[currentChunkIndex] = DOMPurify6.sanitize(pElement.textContent || "");
|
|
2441
|
+
return chunks;
|
|
2317
2442
|
}
|
|
2318
2443
|
for (const r of runs) {
|
|
2319
2444
|
const blip = r.getElementsByTagNameNS("*", "blip")[0] || r.getElementsByTagNameNS("*", "imagedata")[0];
|
|
2320
2445
|
const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
|
|
2321
2446
|
if (rId && imageMap[rId]) {
|
|
2322
|
-
|
|
2447
|
+
chunks[currentChunkIndex] += `<img src="${imageMap[rId]}" style="max-width: 100%; height: auto; display: inline-block; margin: 4px;" />`;
|
|
2323
2448
|
}
|
|
2324
|
-
const brs = r.getElementsByTagNameNS("*", "br");
|
|
2325
|
-
for (
|
|
2326
|
-
|
|
2449
|
+
const brs = Array.from(r.getElementsByTagNameNS("*", "br"));
|
|
2450
|
+
for (const br of brs) {
|
|
2451
|
+
const type = br.getAttribute("w:type") || br.getAttribute("type");
|
|
2452
|
+
if (type === "page") {
|
|
2453
|
+
chunks.push("");
|
|
2454
|
+
currentChunkIndex++;
|
|
2455
|
+
} else {
|
|
2456
|
+
chunks[currentChunkIndex] += "<br/>";
|
|
2457
|
+
}
|
|
2327
2458
|
}
|
|
2328
2459
|
const tabs = r.getElementsByTagNameNS("*", "tab");
|
|
2329
2460
|
if (tabs.length > 0) {
|
|
2330
|
-
|
|
2461
|
+
chunks[currentChunkIndex] += " ";
|
|
2331
2462
|
}
|
|
2332
2463
|
const rPr = r.getElementsByTagNameNS("*", "rPr")[0];
|
|
2333
2464
|
const isBold = !!rPr?.getElementsByTagNameNS("*", "b")[0];
|
|
@@ -2341,7 +2472,7 @@ var DocxPlugin = class {
|
|
|
2341
2472
|
const texts = Array.from(r.getElementsByTagNameNS("*", "t"));
|
|
2342
2473
|
let text = texts.map((t) => t.textContent || "").join("");
|
|
2343
2474
|
if (!text) continue;
|
|
2344
|
-
text =
|
|
2475
|
+
text = DOMPurify6.sanitize(text);
|
|
2345
2476
|
let styles = "";
|
|
2346
2477
|
if (isBold) styles += "font-weight: bold; ";
|
|
2347
2478
|
if (isItalic) styles += "font-style: italic; ";
|
|
@@ -2353,12 +2484,12 @@ var DocxPlugin = class {
|
|
|
2353
2484
|
if (!isNaN(pt) && pt > 0) styles += `font-size: ${pt}pt; `;
|
|
2354
2485
|
}
|
|
2355
2486
|
if (styles) {
|
|
2356
|
-
|
|
2487
|
+
chunks[currentChunkIndex] += `<span style="${styles}">${text}</span>`;
|
|
2357
2488
|
} else {
|
|
2358
|
-
|
|
2489
|
+
chunks[currentChunkIndex] += text;
|
|
2359
2490
|
}
|
|
2360
2491
|
}
|
|
2361
|
-
return
|
|
2492
|
+
return chunks;
|
|
2362
2493
|
}
|
|
2363
2494
|
renderBinaryDocFallback(ctx, wrapper) {
|
|
2364
2495
|
const card = document.createElement("div");
|
|
@@ -2375,14 +2506,14 @@ var DocxPlugin = class {
|
|
|
2375
2506
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
2376
2507
|
if (wordDocStream && wordDocStream.length >= 512) {
|
|
2377
2508
|
const text2 = this.extractReadableStrings(wordDocStream);
|
|
2378
|
-
card.innerHTML = `<div style="white-space: pre-wrap;">${
|
|
2509
|
+
card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6.sanitize(text2)}</div>`;
|
|
2379
2510
|
wrapper.appendChild(card);
|
|
2380
2511
|
return;
|
|
2381
2512
|
}
|
|
2382
2513
|
} catch {
|
|
2383
2514
|
}
|
|
2384
2515
|
const text = this.extractReadableStrings(new Uint8Array(ctx.buffer));
|
|
2385
|
-
card.innerHTML = `<div style="white-space: pre-wrap;">${
|
|
2516
|
+
card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6.sanitize(text)}</div>`;
|
|
2386
2517
|
wrapper.appendChild(card);
|
|
2387
2518
|
}
|
|
2388
2519
|
extractReadableStrings(bytes) {
|
|
@@ -2559,11 +2690,9 @@ var ExcelPlugin = class {
|
|
|
2559
2690
|
const calculateFitScale = () => {
|
|
2560
2691
|
const table = contentArea.querySelector("table");
|
|
2561
2692
|
if (!table) return 1;
|
|
2562
|
-
const availW = Math.max(
|
|
2563
|
-
const availH = Math.max(200, container.clientHeight - 80);
|
|
2693
|
+
const availW = Math.max(280, container.clientWidth - 48);
|
|
2564
2694
|
const tW = table.offsetWidth || 800;
|
|
2565
|
-
|
|
2566
|
-
return Math.min(1, Math.min(availW / tW, availH / tH));
|
|
2695
|
+
return Math.max(0.65, Math.min(1, availW / tW));
|
|
2567
2696
|
};
|
|
2568
2697
|
try {
|
|
2569
2698
|
wb = XLSX.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
|
|
@@ -2981,41 +3110,94 @@ var CodePlugin = class {
|
|
|
2981
3110
|
async render(ctx) {
|
|
2982
3111
|
const decoder = new TextDecoder("utf-8");
|
|
2983
3112
|
const fullText = decoder.decode(ctx.buffer);
|
|
2984
|
-
const
|
|
2985
|
-
const
|
|
3113
|
+
const extRaw = ctx.metadata.extension?.toLowerCase();
|
|
3114
|
+
const mimeRaw = ctx.metadata.mimeType?.toLowerCase();
|
|
3115
|
+
const isTxt = extRaw === ".txt" || mimeRaw === "text/plain" && (!extRaw || !this.extensions.filter((e) => e !== ".txt").includes(extRaw));
|
|
3116
|
+
let rawPages = [];
|
|
3117
|
+
if (isTxt) {
|
|
3118
|
+
const explicitPages = fullText.split(/(?:\f|\x0C)/);
|
|
3119
|
+
for (const ep of explicitPages) {
|
|
3120
|
+
const lines = ep.split(/\r?\n/);
|
|
3121
|
+
let currentChunk = [];
|
|
3122
|
+
for (let i = 0; i < lines.length; i++) {
|
|
3123
|
+
currentChunk.push(lines[i]);
|
|
3124
|
+
if (currentChunk.length >= 46) {
|
|
3125
|
+
rawPages.push(currentChunk.join("\n"));
|
|
3126
|
+
currentChunk = [];
|
|
3127
|
+
}
|
|
3128
|
+
}
|
|
3129
|
+
if (currentChunk.length > 0 || lines.length === 0) {
|
|
3130
|
+
rawPages.push(currentChunk.join("\n"));
|
|
3131
|
+
}
|
|
3132
|
+
}
|
|
3133
|
+
if (rawPages.length === 0) rawPages = [""];
|
|
3134
|
+
} else {
|
|
3135
|
+
const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
|
|
3136
|
+
rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
3137
|
+
}
|
|
2986
3138
|
const totalPages = Math.max(1, rawPages.length);
|
|
2987
3139
|
let currentPage = 1;
|
|
2988
3140
|
const container = document.createElement("div");
|
|
2989
3141
|
container.style.width = "100%";
|
|
2990
3142
|
container.style.height = "100%";
|
|
2991
3143
|
container.style.overflow = "auto";
|
|
2992
|
-
container.style.backgroundColor = "#1e1e1e";
|
|
2993
|
-
container.style.color = "#d4d4d4";
|
|
2994
|
-
container.style.padding = "16px";
|
|
2995
|
-
container.style.boxSizing = "border-box";
|
|
2996
3144
|
let fontSize = 13;
|
|
2997
3145
|
let rotation = 0;
|
|
3146
|
+
let zoomLevel = 1;
|
|
2998
3147
|
const pre = document.createElement("pre");
|
|
2999
|
-
pre.style.margin = "0";
|
|
3000
|
-
pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
|
|
3001
|
-
pre.style.fontSize = `${fontSize}px`;
|
|
3002
|
-
pre.style.lineHeight = "1.5";
|
|
3003
|
-
pre.style.whiteSpace = "pre-wrap";
|
|
3004
|
-
pre.style.wordBreak = "break-all";
|
|
3005
3148
|
const code = document.createElement("code");
|
|
3149
|
+
if (isTxt) {
|
|
3150
|
+
container.style.backgroundColor = "#f1f5f9";
|
|
3151
|
+
container.style.padding = "32px";
|
|
3152
|
+
container.style.boxSizing = "border-box";
|
|
3153
|
+
container.style.display = "flex";
|
|
3154
|
+
container.style.flexDirection = "column";
|
|
3155
|
+
container.style.alignItems = "center";
|
|
3156
|
+
pre.style.margin = "0";
|
|
3157
|
+
pre.style.fontFamily = "Consolas, 'Courier New', monospace";
|
|
3158
|
+
pre.style.fontSize = "13px";
|
|
3159
|
+
pre.style.color = "#1e293b";
|
|
3160
|
+
pre.style.lineHeight = "1.5";
|
|
3161
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3162
|
+
pre.style.wordBreak = "break-word";
|
|
3163
|
+
pre.style.backgroundColor = "#ffffff";
|
|
3164
|
+
pre.style.width = "816px";
|
|
3165
|
+
pre.style.minHeight = "1056px";
|
|
3166
|
+
pre.style.padding = "72px 56px";
|
|
3167
|
+
pre.style.boxSizing = "border-box";
|
|
3168
|
+
pre.style.boxShadow = "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)";
|
|
3169
|
+
pre.style.borderRadius = "4px";
|
|
3170
|
+
pre.style.transformOrigin = "top center";
|
|
3171
|
+
} else {
|
|
3172
|
+
container.style.backgroundColor = "#1e1e1e";
|
|
3173
|
+
container.style.color = "#d4d4d4";
|
|
3174
|
+
container.style.padding = "16px";
|
|
3175
|
+
container.style.boxSizing = "border-box";
|
|
3176
|
+
pre.style.margin = "0";
|
|
3177
|
+
pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
|
|
3178
|
+
pre.style.fontSize = `${fontSize}px`;
|
|
3179
|
+
pre.style.lineHeight = "1.5";
|
|
3180
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3181
|
+
pre.style.wordBreak = "break-all";
|
|
3182
|
+
pre.style.transformOrigin = "top left";
|
|
3183
|
+
}
|
|
3006
3184
|
const ext = (ctx.metadata.extension || "").replace(".", "");
|
|
3007
3185
|
const renderCodePage = (text) => {
|
|
3008
|
-
|
|
3009
|
-
if (ext && hljs.getLanguage(ext)) {
|
|
3010
|
-
code.innerHTML = hljs.highlight(text, { language: ext }).value;
|
|
3011
|
-
} else {
|
|
3012
|
-
code.innerHTML = hljs.highlightAuto(text).value;
|
|
3013
|
-
}
|
|
3014
|
-
} catch {
|
|
3186
|
+
if (isTxt) {
|
|
3015
3187
|
code.textContent = text;
|
|
3188
|
+
} else {
|
|
3189
|
+
try {
|
|
3190
|
+
if (ext && hljs.getLanguage(ext)) {
|
|
3191
|
+
code.innerHTML = hljs.highlight(text, { language: ext }).value;
|
|
3192
|
+
} else {
|
|
3193
|
+
code.innerHTML = hljs.highlightAuto(text).value;
|
|
3194
|
+
}
|
|
3195
|
+
} catch {
|
|
3196
|
+
code.textContent = text;
|
|
3197
|
+
}
|
|
3016
3198
|
}
|
|
3017
3199
|
};
|
|
3018
|
-
renderCodePage(rawPages[0] || fullText);
|
|
3200
|
+
renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
|
|
3019
3201
|
pre.appendChild(code);
|
|
3020
3202
|
container.appendChild(pre);
|
|
3021
3203
|
let indicator = null;
|
|
@@ -3024,15 +3206,22 @@ var CodePlugin = class {
|
|
|
3024
3206
|
indicator.className = "fp-code-page-indicator";
|
|
3025
3207
|
indicator.style.position = "sticky";
|
|
3026
3208
|
indicator.style.bottom = "16px";
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3209
|
+
if (isTxt) {
|
|
3210
|
+
indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
|
|
3211
|
+
indicator.style.color = "#334155";
|
|
3212
|
+
indicator.style.border = "1px solid #e2e8f0";
|
|
3213
|
+
indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
|
|
3214
|
+
} else {
|
|
3215
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3216
|
+
indicator.style.color = "#f8fafc";
|
|
3217
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3218
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3219
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
3220
|
+
}
|
|
3030
3221
|
indicator.style.fontSize = "12px";
|
|
3031
3222
|
indicator.style.fontWeight = "600";
|
|
3032
3223
|
indicator.style.padding = "5px 14px";
|
|
3033
3224
|
indicator.style.borderRadius = "20px";
|
|
3034
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3035
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3036
3225
|
indicator.style.zIndex = "10";
|
|
3037
3226
|
indicator.style.userSelect = "none";
|
|
3038
3227
|
indicator.style.pointerEvents = "none";
|
|
@@ -3043,7 +3232,7 @@ var CodePlugin = class {
|
|
|
3043
3232
|
}
|
|
3044
3233
|
const showPage = (pageNum) => {
|
|
3045
3234
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3046
|
-
renderCodePage(rawPages[currentPage - 1] || fullText);
|
|
3235
|
+
renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
|
|
3047
3236
|
if (indicator) {
|
|
3048
3237
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3049
3238
|
}
|
|
@@ -3059,39 +3248,57 @@ var CodePlugin = class {
|
|
|
3059
3248
|
ctx.container.innerHTML = "";
|
|
3060
3249
|
};
|
|
3061
3250
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3251
|
+
const updateTransform = () => {
|
|
3252
|
+
if (isTxt) {
|
|
3253
|
+
pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
|
|
3254
|
+
} else {
|
|
3255
|
+
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3256
|
+
pre.style.fontSize = `${fontSize}px`;
|
|
3257
|
+
}
|
|
3258
|
+
};
|
|
3062
3259
|
return {
|
|
3063
3260
|
destroy: cleanup,
|
|
3064
3261
|
getPageCount: () => totalPages,
|
|
3065
3262
|
getCurrentPage: () => currentPage,
|
|
3066
3263
|
goToPage: (page) => showPage(page),
|
|
3067
3264
|
zoomIn: () => {
|
|
3068
|
-
|
|
3069
|
-
|
|
3265
|
+
if (isTxt) {
|
|
3266
|
+
zoomLevel = Math.min(3, zoomLevel + 0.1);
|
|
3267
|
+
} else {
|
|
3268
|
+
fontSize = Math.min(32, fontSize + 2);
|
|
3269
|
+
}
|
|
3270
|
+
updateTransform();
|
|
3070
3271
|
},
|
|
3071
3272
|
zoomOut: () => {
|
|
3072
|
-
|
|
3073
|
-
|
|
3273
|
+
if (isTxt) {
|
|
3274
|
+
zoomLevel = Math.max(0.1, zoomLevel - 0.1);
|
|
3275
|
+
} else {
|
|
3276
|
+
fontSize = Math.max(8, fontSize - 2);
|
|
3277
|
+
}
|
|
3278
|
+
updateTransform();
|
|
3074
3279
|
},
|
|
3075
|
-
getZoom: () => fontSize / 13,
|
|
3280
|
+
getZoom: () => isTxt ? zoomLevel : fontSize / 13,
|
|
3076
3281
|
setZoom: (level) => {
|
|
3077
|
-
|
|
3078
|
-
|
|
3282
|
+
if (isTxt) {
|
|
3283
|
+
zoomLevel = level;
|
|
3284
|
+
} else {
|
|
3285
|
+
fontSize = Math.round(13 * level);
|
|
3286
|
+
}
|
|
3287
|
+
updateTransform();
|
|
3079
3288
|
},
|
|
3080
3289
|
fitToPage: () => {
|
|
3081
3290
|
fontSize = 13;
|
|
3082
3291
|
rotation = 0;
|
|
3083
|
-
|
|
3084
|
-
|
|
3292
|
+
zoomLevel = isTxt ? Math.max(0.65, Math.min(1.05, (container.clientWidth - 48) / 816)) : 1;
|
|
3293
|
+
updateTransform();
|
|
3085
3294
|
},
|
|
3086
3295
|
rotateCW: () => {
|
|
3087
3296
|
rotation = (rotation + 90) % 360;
|
|
3088
|
-
|
|
3089
|
-
pre.style.transformOrigin = "top left";
|
|
3297
|
+
updateTransform();
|
|
3090
3298
|
},
|
|
3091
3299
|
rotateCCW: () => {
|
|
3092
3300
|
rotation = (rotation - 90 + 360) % 360;
|
|
3093
|
-
|
|
3094
|
-
pre.style.transformOrigin = "top left";
|
|
3301
|
+
updateTransform();
|
|
3095
3302
|
},
|
|
3096
3303
|
download: () => {
|
|
3097
3304
|
const mimeType = ctx.metadata.mimeType || "text/plain";
|
|
@@ -3390,7 +3597,7 @@ var MarkdownPlugin = class {
|
|
|
3390
3597
|
gfm: true,
|
|
3391
3598
|
breaks: true
|
|
3392
3599
|
});
|
|
3393
|
-
const cleanHtml =
|
|
3600
|
+
const cleanHtml = DOMPurify6.sanitize(rawHtml, {
|
|
3394
3601
|
USE_PROFILES: { html: true }
|
|
3395
3602
|
});
|
|
3396
3603
|
const wrapper = document.createElement("div");
|
|
@@ -4026,6 +4233,14 @@ var RtfPlugin = class {
|
|
|
4026
4233
|
group: "actions",
|
|
4027
4234
|
execute: () => instance.download?.()
|
|
4028
4235
|
},
|
|
4236
|
+
{
|
|
4237
|
+
id: "copy",
|
|
4238
|
+
icon: "copy",
|
|
4239
|
+
label: "Copy Text",
|
|
4240
|
+
type: "button",
|
|
4241
|
+
group: "actions",
|
|
4242
|
+
execute: () => instance.copy?.()
|
|
4243
|
+
},
|
|
4029
4244
|
{
|
|
4030
4245
|
id: "print",
|
|
4031
4246
|
icon: "print",
|
|
@@ -4056,20 +4271,27 @@ var RtfPlugin = class {
|
|
|
4056
4271
|
let scale = 1;
|
|
4057
4272
|
let rotation = 0;
|
|
4058
4273
|
let pageElements = [];
|
|
4059
|
-
|
|
4274
|
+
let fitMode = "width";
|
|
4275
|
+
const calculateFitScale = (mode = fitMode) => {
|
|
4060
4276
|
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4061
4277
|
const elW = activeEl.offsetWidth || 850;
|
|
4062
|
-
const
|
|
4063
|
-
const availW = Math.max(
|
|
4064
|
-
const availH = Math.max(
|
|
4065
|
-
|
|
4278
|
+
const singlePageH = Math.min(activeEl.offsetHeight || 1056, Math.round(elW * 1.32));
|
|
4279
|
+
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
4280
|
+
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
4281
|
+
const sW = availW / elW;
|
|
4282
|
+
const sH = availH / singlePageH;
|
|
4283
|
+
if (mode === "page") {
|
|
4284
|
+
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
4285
|
+
}
|
|
4286
|
+
return Math.max(0.65, Math.min(1.05, sW));
|
|
4066
4287
|
};
|
|
4067
4288
|
const applyTransform = () => {
|
|
4068
4289
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4069
4290
|
wrapper.style.transformOrigin = "top center";
|
|
4070
4291
|
};
|
|
4071
4292
|
setTimeout(() => {
|
|
4072
|
-
|
|
4293
|
+
fitMode = "width";
|
|
4294
|
+
scale = calculateFitScale("width");
|
|
4073
4295
|
applyTransform();
|
|
4074
4296
|
}, 60);
|
|
4075
4297
|
try {
|
|
@@ -4087,14 +4309,31 @@ var RtfPlugin = class {
|
|
|
4087
4309
|
} catch (err) {
|
|
4088
4310
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
4089
4311
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
4090
|
-
const
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4312
|
+
const rawPages = text.split(/\\page\b/).map((segment) => {
|
|
4313
|
+
return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
|
|
4314
|
+
}).filter((p) => p.length > 0);
|
|
4315
|
+
const pages = rawPages.length > 0 ? rawPages : [text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim()];
|
|
4316
|
+
for (let i = 0; i < pages.length; i++) {
|
|
4317
|
+
const pageCard = document.createElement("div");
|
|
4318
|
+
pageCard.className = "fp-rtf-page-card";
|
|
4319
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
4320
|
+
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4321
|
+
pageCard.style.borderRadius = "4px";
|
|
4322
|
+
pageCard.style.padding = "72px 56px";
|
|
4323
|
+
pageCard.style.width = "816px";
|
|
4324
|
+
pageCard.style.minHeight = "1056px";
|
|
4325
|
+
pageCard.style.maxWidth = "100%";
|
|
4326
|
+
pageCard.style.boxSizing = "border-box";
|
|
4327
|
+
pageCard.style.fontFamily = "serif";
|
|
4328
|
+
pageCard.style.fontSize = "12pt";
|
|
4329
|
+
pageCard.style.lineHeight = "1.6";
|
|
4330
|
+
pageCard.style.color = "#1e293b";
|
|
4331
|
+
pageCard.style.whiteSpace = "pre-wrap";
|
|
4332
|
+
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4333
|
+
pageCard.textContent = pages[i];
|
|
4334
|
+
wrapper.appendChild(pageCard);
|
|
4335
|
+
pageElements.push(pageCard);
|
|
4336
|
+
}
|
|
4098
4337
|
}
|
|
4099
4338
|
const totalPages = Math.max(1, pageElements.length);
|
|
4100
4339
|
let currentPage = 1;
|
|
@@ -4161,7 +4400,8 @@ var RtfPlugin = class {
|
|
|
4161
4400
|
applyTransform();
|
|
4162
4401
|
},
|
|
4163
4402
|
fitToPage: () => {
|
|
4164
|
-
|
|
4403
|
+
fitMode = fitMode === "width" ? "page" : "width";
|
|
4404
|
+
scale = calculateFitScale(fitMode);
|
|
4165
4405
|
rotation = 0;
|
|
4166
4406
|
applyTransform();
|
|
4167
4407
|
},
|
|
@@ -4182,6 +4422,10 @@ var RtfPlugin = class {
|
|
|
4182
4422
|
a.click();
|
|
4183
4423
|
URL.revokeObjectURL(url);
|
|
4184
4424
|
},
|
|
4425
|
+
copy: () => {
|
|
4426
|
+
const text = wrapper.textContent || "";
|
|
4427
|
+
navigator.clipboard?.writeText(text);
|
|
4428
|
+
},
|
|
4185
4429
|
print: () => {
|
|
4186
4430
|
window.print();
|
|
4187
4431
|
}
|
|
@@ -4256,7 +4500,7 @@ var HtmlPreviewPlugin = class {
|
|
|
4256
4500
|
}
|
|
4257
4501
|
async render(ctx) {
|
|
4258
4502
|
const rawHtml = new TextDecoder("utf-8").decode(ctx.buffer);
|
|
4259
|
-
const sanitized =
|
|
4503
|
+
const sanitized = DOMPurify6.sanitize(rawHtml, {
|
|
4260
4504
|
WHOLE_DOCUMENT: true,
|
|
4261
4505
|
ADD_TAGS: ["style", "link"],
|
|
4262
4506
|
ADD_ATTR: ["target", "rel"]
|
|
@@ -4476,19 +4720,29 @@ var OpenDocumentPlugin = class {
|
|
|
4476
4720
|
ctx.container.appendChild(container);
|
|
4477
4721
|
let scale = 1;
|
|
4478
4722
|
let rotation = 0;
|
|
4479
|
-
|
|
4723
|
+
let fitMode = "width";
|
|
4724
|
+
const calculateFitScale = (mode = fitMode) => {
|
|
4480
4725
|
const elW = wrapper.offsetWidth || 850;
|
|
4481
|
-
const
|
|
4482
|
-
const availW = Math.max(
|
|
4483
|
-
const availH = Math.max(
|
|
4484
|
-
|
|
4726
|
+
const singlePageH = Math.min(wrapper.offsetHeight || 1056, Math.round(elW * 1.32));
|
|
4727
|
+
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
4728
|
+
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
4729
|
+
const sW = availW / elW;
|
|
4730
|
+
const sH = availH / (isPresentation ? 540 : singlePageH);
|
|
4731
|
+
if (isPresentation) {
|
|
4732
|
+
return Math.min(1, Math.min(sW, sH));
|
|
4733
|
+
}
|
|
4734
|
+
if (mode === "page") {
|
|
4735
|
+
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
4736
|
+
}
|
|
4737
|
+
return Math.max(0.65, Math.min(1.05, sW));
|
|
4485
4738
|
};
|
|
4486
4739
|
const applyTransform = () => {
|
|
4487
4740
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4488
4741
|
wrapper.style.transformOrigin = "top center";
|
|
4489
4742
|
};
|
|
4490
4743
|
setTimeout(() => {
|
|
4491
|
-
|
|
4744
|
+
fitMode = "width";
|
|
4745
|
+
scale = calculateFitScale("width");
|
|
4492
4746
|
applyTransform();
|
|
4493
4747
|
}, 60);
|
|
4494
4748
|
let currentPage = 1;
|
|
@@ -4522,14 +4776,97 @@ var OpenDocumentPlugin = class {
|
|
|
4522
4776
|
wrapper.textContent = contentDoc.documentElement.textContent || "Formula content";
|
|
4523
4777
|
}
|
|
4524
4778
|
} else {
|
|
4525
|
-
wrapper.style.maxWidth = "
|
|
4526
|
-
wrapper.style.padding = "
|
|
4779
|
+
wrapper.style.maxWidth = "none";
|
|
4780
|
+
wrapper.style.padding = "0";
|
|
4527
4781
|
wrapper.style.minHeight = "100%";
|
|
4782
|
+
wrapper.style.backgroundColor = "transparent";
|
|
4783
|
+
wrapper.style.boxShadow = "none";
|
|
4784
|
+
wrapper.style.position = "relative";
|
|
4785
|
+
const dims = this.getPageDimensions(stylesDoc, contentDoc);
|
|
4528
4786
|
const bodyHtml = this.renderOdfBody(contentDoc, styleMap, imageUrls);
|
|
4529
|
-
|
|
4530
|
-
|
|
4787
|
+
const tempDiv = document.createElement("div");
|
|
4788
|
+
tempDiv.style.width = `${dims.width - dims.marginLeft - dims.marginRight}px`;
|
|
4789
|
+
tempDiv.style.position = "absolute";
|
|
4790
|
+
tempDiv.style.visibility = "hidden";
|
|
4791
|
+
tempDiv.innerHTML = DOMPurify6.sanitize(bodyHtml, {
|
|
4792
|
+
ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub", "hr"],
|
|
4531
4793
|
ADD_ATTR: ["style", "colspan", "rowspan"]
|
|
4532
4794
|
});
|
|
4795
|
+
document.body.appendChild(tempDiv);
|
|
4796
|
+
const contentHeight = dims.height - dims.marginTop - dims.marginBottom;
|
|
4797
|
+
const pageElements = [[]];
|
|
4798
|
+
let currentHeight = 0;
|
|
4799
|
+
let currentPageIdx = 0;
|
|
4800
|
+
Array.from(tempDiv.children).forEach((child) => {
|
|
4801
|
+
const el = child;
|
|
4802
|
+
const style = el.getAttribute("style") || "";
|
|
4803
|
+
const isBreakBefore = style.includes("page-break-before: always");
|
|
4804
|
+
const isBreakAfter = style.includes("page-break-after: always");
|
|
4805
|
+
const isSoftBreak = el.classList.contains("odf-page-break");
|
|
4806
|
+
if (isBreakBefore) {
|
|
4807
|
+
if (pageElements[currentPageIdx].length > 0) {
|
|
4808
|
+
currentPageIdx++;
|
|
4809
|
+
pageElements.push([]);
|
|
4810
|
+
currentHeight = 0;
|
|
4811
|
+
}
|
|
4812
|
+
}
|
|
4813
|
+
const h = el.offsetHeight || 0;
|
|
4814
|
+
if (currentHeight + h > contentHeight && pageElements[currentPageIdx].length > 0 && !isSoftBreak) {
|
|
4815
|
+
currentPageIdx++;
|
|
4816
|
+
pageElements.push([]);
|
|
4817
|
+
currentHeight = 0;
|
|
4818
|
+
}
|
|
4819
|
+
if (!isSoftBreak) {
|
|
4820
|
+
pageElements[currentPageIdx].push(el.cloneNode(true));
|
|
4821
|
+
currentHeight += h;
|
|
4822
|
+
}
|
|
4823
|
+
if (isBreakAfter || isSoftBreak) {
|
|
4824
|
+
currentPageIdx++;
|
|
4825
|
+
pageElements.push([]);
|
|
4826
|
+
currentHeight = 0;
|
|
4827
|
+
}
|
|
4828
|
+
});
|
|
4829
|
+
document.body.removeChild(tempDiv);
|
|
4830
|
+
if (pageElements.length > 1 && pageElements[pageElements.length - 1].length === 0) {
|
|
4831
|
+
pageElements.pop();
|
|
4832
|
+
}
|
|
4833
|
+
totalPages = Math.max(1, pageElements.length);
|
|
4834
|
+
pageElements.forEach((elements, idx) => {
|
|
4835
|
+
const page = document.createElement("div");
|
|
4836
|
+
page.className = `fp-odt-page fp-odt-page-${idx + 1}`;
|
|
4837
|
+
page.style.width = `${dims.width}px`;
|
|
4838
|
+
page.style.minHeight = `${dims.height}px`;
|
|
4839
|
+
page.style.padding = `${dims.marginTop}px ${dims.marginRight}px ${dims.marginBottom}px ${dims.marginLeft}px`;
|
|
4840
|
+
page.style.margin = "0 auto";
|
|
4841
|
+
page.style.backgroundColor = "#ffffff";
|
|
4842
|
+
page.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
|
|
4843
|
+
page.style.borderRadius = "4px";
|
|
4844
|
+
page.style.boxSizing = "border-box";
|
|
4845
|
+
page.style.display = idx === 0 ? "block" : "none";
|
|
4846
|
+
page.style.position = "absolute";
|
|
4847
|
+
page.style.top = "0";
|
|
4848
|
+
page.style.left = "50%";
|
|
4849
|
+
page.style.transform = "translateX(-50%)";
|
|
4850
|
+
elements.forEach((el) => page.appendChild(el));
|
|
4851
|
+
wrapper.appendChild(page);
|
|
4852
|
+
slides.push(page);
|
|
4853
|
+
});
|
|
4854
|
+
const pageIndicator = document.createElement("div");
|
|
4855
|
+
pageIndicator.className = "fp-odt-page-indicator";
|
|
4856
|
+
pageIndicator.style.position = "sticky";
|
|
4857
|
+
pageIndicator.style.bottom = "16px";
|
|
4858
|
+
pageIndicator.style.left = "50%";
|
|
4859
|
+
pageIndicator.style.transform = "translateX(-50%)";
|
|
4860
|
+
pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
|
4861
|
+
pageIndicator.style.color = "#fff";
|
|
4862
|
+
pageIndicator.style.padding = "6px 12px";
|
|
4863
|
+
pageIndicator.style.borderRadius = "16px";
|
|
4864
|
+
pageIndicator.style.fontSize = "12px";
|
|
4865
|
+
pageIndicator.style.zIndex = "100";
|
|
4866
|
+
pageIndicator.style.display = "inline-block";
|
|
4867
|
+
pageIndicator.style.width = "fit-content";
|
|
4868
|
+
pageIndicator.textContent = `Page 1 of ${totalPages}`;
|
|
4869
|
+
container.appendChild(pageIndicator);
|
|
4533
4870
|
}
|
|
4534
4871
|
const cleanup = () => {
|
|
4535
4872
|
imageUrls.forEach((url) => URL.revokeObjectURL(url));
|
|
@@ -4538,11 +4875,15 @@ var OpenDocumentPlugin = class {
|
|
|
4538
4875
|
};
|
|
4539
4876
|
ctx.signal.addEventListener("abort", cleanup);
|
|
4540
4877
|
const goToPage = (page) => {
|
|
4541
|
-
if (
|
|
4878
|
+
if (page < 1 || page > totalPages) return;
|
|
4542
4879
|
currentPage = page;
|
|
4543
4880
|
slides.forEach((s, idx) => {
|
|
4544
4881
|
s.style.display = idx === page - 1 ? "block" : "none";
|
|
4545
4882
|
});
|
|
4883
|
+
const indicator = container.querySelector(".fp-odt-page-indicator");
|
|
4884
|
+
if (indicator) {
|
|
4885
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4886
|
+
}
|
|
4546
4887
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4547
4888
|
};
|
|
4548
4889
|
return {
|
|
@@ -4562,7 +4903,8 @@ var OpenDocumentPlugin = class {
|
|
|
4562
4903
|
applyTransform();
|
|
4563
4904
|
},
|
|
4564
4905
|
fitToPage: () => {
|
|
4565
|
-
|
|
4906
|
+
fitMode = fitMode === "width" ? "page" : "width";
|
|
4907
|
+
scale = calculateFitScale(fitMode);
|
|
4566
4908
|
rotation = 0;
|
|
4567
4909
|
applyTransform();
|
|
4568
4910
|
},
|
|
@@ -4611,6 +4953,43 @@ var OpenDocumentPlugin = class {
|
|
|
4611
4953
|
}
|
|
4612
4954
|
};
|
|
4613
4955
|
}
|
|
4956
|
+
getPageDimensions(stylesDoc, contentDoc) {
|
|
4957
|
+
let width = 850;
|
|
4958
|
+
let height = 1123;
|
|
4959
|
+
let marginTop = 48;
|
|
4960
|
+
let marginBottom = 48;
|
|
4961
|
+
let marginLeft = 48;
|
|
4962
|
+
let marginRight = 48;
|
|
4963
|
+
const parseUnit = (val) => {
|
|
4964
|
+
if (!val) return null;
|
|
4965
|
+
if (val.endsWith("cm")) return parseFloat(val) * 37.8;
|
|
4966
|
+
if (val.endsWith("mm")) return parseFloat(val) * 3.78;
|
|
4967
|
+
if (val.endsWith("in")) return parseFloat(val) * 96;
|
|
4968
|
+
if (val.endsWith("pt")) return parseFloat(val) * 1.33;
|
|
4969
|
+
if (val.endsWith("px")) return parseFloat(val);
|
|
4970
|
+
return parseFloat(val);
|
|
4971
|
+
};
|
|
4972
|
+
const docs = [stylesDoc, contentDoc].filter(Boolean);
|
|
4973
|
+
for (const doc of docs) {
|
|
4974
|
+
const pageLayout = doc.querySelector("page-layout-properties, [page-width]");
|
|
4975
|
+
if (pageLayout) {
|
|
4976
|
+
const w = parseUnit(pageLayout.getAttribute("fo:page-width") || pageLayout.getAttribute("page-width"));
|
|
4977
|
+
const h = parseUnit(pageLayout.getAttribute("fo:page-height") || pageLayout.getAttribute("page-height"));
|
|
4978
|
+
const mt = parseUnit(pageLayout.getAttribute("fo:margin-top") || pageLayout.getAttribute("margin-top"));
|
|
4979
|
+
const mb = parseUnit(pageLayout.getAttribute("fo:margin-bottom") || pageLayout.getAttribute("margin-bottom"));
|
|
4980
|
+
const ml = parseUnit(pageLayout.getAttribute("fo:margin-left") || pageLayout.getAttribute("margin-left"));
|
|
4981
|
+
const mr = parseUnit(pageLayout.getAttribute("fo:margin-right") || pageLayout.getAttribute("margin-right"));
|
|
4982
|
+
if (w !== null) width = w;
|
|
4983
|
+
if (h !== null) height = h;
|
|
4984
|
+
if (mt !== null) marginTop = mt;
|
|
4985
|
+
if (mb !== null) marginBottom = mb;
|
|
4986
|
+
if (ml !== null) marginLeft = ml;
|
|
4987
|
+
if (mr !== null) marginRight = mr;
|
|
4988
|
+
break;
|
|
4989
|
+
}
|
|
4990
|
+
}
|
|
4991
|
+
return { width, height, marginTop, marginBottom, marginLeft, marginRight };
|
|
4992
|
+
}
|
|
4614
4993
|
extractStyles(stylesDoc, contentDoc) {
|
|
4615
4994
|
const map = /* @__PURE__ */ new Map();
|
|
4616
4995
|
const styleNodes = [];
|
|
@@ -4633,14 +5012,21 @@ var OpenDocumentPlugin = class {
|
|
|
4633
5012
|
if (color) css += `color: ${color}; `;
|
|
4634
5013
|
if (size) css += `font-size: ${size}; `;
|
|
4635
5014
|
}
|
|
4636
|
-
|
|
5015
|
+
let paraProp = node.querySelector("paragraph-properties, [text-align]");
|
|
5016
|
+
if (!paraProp) {
|
|
5017
|
+
paraProp = Array.from(node.children).find((c) => c.tagName.includes("paragraph-properties")) || null;
|
|
5018
|
+
}
|
|
4637
5019
|
if (paraProp) {
|
|
4638
5020
|
const align = paraProp.getAttribute("fo:text-align") || paraProp.getAttribute("text-align");
|
|
4639
5021
|
const mt = paraProp.getAttribute("fo:margin-top") || paraProp.getAttribute("margin-top");
|
|
4640
5022
|
const mb = paraProp.getAttribute("fo:margin-bottom") || paraProp.getAttribute("margin-bottom");
|
|
5023
|
+
const breakBefore = paraProp.getAttribute("fo:break-before") || paraProp.getAttribute("break-before");
|
|
5024
|
+
const breakAfter = paraProp.getAttribute("fo:break-after") || paraProp.getAttribute("break-after");
|
|
4641
5025
|
if (align) css += `text-align: ${align}; `;
|
|
4642
5026
|
if (mt) css += `margin-top: ${mt}; `;
|
|
4643
5027
|
if (mb) css += `margin-bottom: ${mb}; `;
|
|
5028
|
+
if (breakBefore === "page") css += "page-break-before: always; ";
|
|
5029
|
+
if (breakAfter === "page") css += "page-break-after: always; ";
|
|
4644
5030
|
}
|
|
4645
5031
|
if (css) map.set(name, css);
|
|
4646
5032
|
}
|
|
@@ -4725,6 +5111,8 @@ var OpenDocumentPlugin = class {
|
|
|
4725
5111
|
result += " ";
|
|
4726
5112
|
} else if (tag === "line-break") {
|
|
4727
5113
|
result += "<br/>";
|
|
5114
|
+
} else if (tag === "soft-page-break") {
|
|
5115
|
+
result += '<hr class="odf-page-break" style="page-break-after: always; border: none; margin: 0; padding: 0; height: 0;" />';
|
|
4728
5116
|
} else {
|
|
4729
5117
|
result += el.textContent || "";
|
|
4730
5118
|
}
|
|
@@ -4885,20 +5273,9 @@ var DocPlugin = class {
|
|
|
4885
5273
|
container.style.overflow = "auto";
|
|
4886
5274
|
container.style.padding = "32px 16px";
|
|
4887
5275
|
container.style.backgroundColor = "#f1f5f9";
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
wrapper.style.margin = "0 auto";
|
|
4892
|
-
wrapper.style.backgroundColor = "#ffffff";
|
|
4893
|
-
wrapper.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4894
|
-
wrapper.style.borderRadius = "4px";
|
|
4895
|
-
wrapper.style.padding = "56px 48px";
|
|
4896
|
-
wrapper.style.minHeight = "100%";
|
|
4897
|
-
wrapper.style.transformOrigin = "top center";
|
|
4898
|
-
wrapper.style.transition = "transform 0.2s ease";
|
|
4899
|
-
wrapper.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4900
|
-
wrapper.style.color = "#1e293b";
|
|
4901
|
-
container.appendChild(wrapper);
|
|
5276
|
+
container.style.display = "flex";
|
|
5277
|
+
container.style.justifyContent = "center";
|
|
5278
|
+
container.style.alignItems = "flex-start";
|
|
4902
5279
|
ctx.container.appendChild(container);
|
|
4903
5280
|
let scale = 1;
|
|
4904
5281
|
let extractedRawText = "";
|
|
@@ -4925,21 +5302,27 @@ var DocPlugin = class {
|
|
|
4925
5302
|
const rawPages = this.splitIntoPages(extractedRawText);
|
|
4926
5303
|
const totalPages = Math.max(1, rawPages.length);
|
|
4927
5304
|
let currentPage = 1;
|
|
4928
|
-
wrapper.innerHTML = "";
|
|
4929
5305
|
const pageCards = [];
|
|
4930
5306
|
for (let i = 0; i < totalPages; i++) {
|
|
4931
5307
|
const pageCard = document.createElement("div");
|
|
4932
5308
|
pageCard.className = "fp-doc-page-card";
|
|
5309
|
+
pageCard.style.width = "816px";
|
|
5310
|
+
pageCard.style.height = "1056px";
|
|
4933
5311
|
pageCard.style.backgroundColor = "#ffffff";
|
|
4934
5312
|
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4935
5313
|
pageCard.style.borderRadius = "4px";
|
|
4936
|
-
pageCard.style.padding = "
|
|
4937
|
-
pageCard.style.
|
|
5314
|
+
pageCard.style.padding = "96px 72px";
|
|
5315
|
+
pageCard.style.boxSizing = "border-box";
|
|
5316
|
+
pageCard.style.overflow = "hidden";
|
|
4938
5317
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
5318
|
+
pageCard.style.transformOrigin = "top center";
|
|
5319
|
+
pageCard.style.transition = "transform 0.2s ease";
|
|
5320
|
+
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
5321
|
+
pageCard.style.color = "#1e293b";
|
|
4939
5322
|
if (isFallback && i === 0) {
|
|
4940
5323
|
pageCard.innerHTML = `
|
|
4941
5324
|
<div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
|
|
4942
|
-
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${
|
|
5325
|
+
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify6.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
|
|
4943
5326
|
<span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
|
|
4944
5327
|
</div>
|
|
4945
5328
|
${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
|
|
@@ -4947,15 +5330,17 @@ var DocPlugin = class {
|
|
|
4947
5330
|
} else {
|
|
4948
5331
|
pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
|
|
4949
5332
|
}
|
|
4950
|
-
|
|
5333
|
+
container.appendChild(pageCard);
|
|
4951
5334
|
pageCards.push(pageCard);
|
|
4952
5335
|
}
|
|
4953
5336
|
let indicator = null;
|
|
4954
5337
|
if (totalPages > 1) {
|
|
4955
5338
|
indicator = document.createElement("div");
|
|
4956
5339
|
indicator.className = "fp-doc-page-indicator";
|
|
4957
|
-
indicator.style.position = "
|
|
5340
|
+
indicator.style.position = "fixed";
|
|
4958
5341
|
indicator.style.bottom = "16px";
|
|
5342
|
+
indicator.style.left = "50%";
|
|
5343
|
+
indicator.style.transform = "translateX(-50%)";
|
|
4959
5344
|
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4960
5345
|
indicator.style.backdropFilter = "blur(8px)";
|
|
4961
5346
|
indicator.style.color = "#f8fafc";
|
|
@@ -4969,17 +5354,25 @@ var DocPlugin = class {
|
|
|
4969
5354
|
indicator.style.userSelect = "none";
|
|
4970
5355
|
indicator.style.pointerEvents = "none";
|
|
4971
5356
|
indicator.style.textAlign = "center";
|
|
4972
|
-
indicator.style.width = "fit-content";
|
|
4973
|
-
indicator.style.margin = "16px auto 0";
|
|
4974
5357
|
container.appendChild(indicator);
|
|
4975
5358
|
}
|
|
5359
|
+
let rotation = 0;
|
|
5360
|
+
const applyTransform = () => {
|
|
5361
|
+
const activeCard = pageCards[currentPage - 1];
|
|
5362
|
+
if (activeCard) {
|
|
5363
|
+
activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5364
|
+
}
|
|
5365
|
+
};
|
|
4976
5366
|
const showPage = (pageNum) => {
|
|
4977
5367
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
card.style.display =
|
|
4981
|
-
|
|
4982
|
-
|
|
5368
|
+
pageCards.forEach((card, idx) => {
|
|
5369
|
+
if (idx + 1 === currentPage) {
|
|
5370
|
+
card.style.display = "block";
|
|
5371
|
+
card.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5372
|
+
} else {
|
|
5373
|
+
card.style.display = "none";
|
|
5374
|
+
}
|
|
5375
|
+
});
|
|
4983
5376
|
if (indicator) {
|
|
4984
5377
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4985
5378
|
}
|
|
@@ -4988,21 +5381,22 @@ var DocPlugin = class {
|
|
|
4988
5381
|
if (totalPages > 1) {
|
|
4989
5382
|
showPage(1);
|
|
4990
5383
|
}
|
|
4991
|
-
let
|
|
4992
|
-
const calculateFitScale = () => {
|
|
4993
|
-
const
|
|
4994
|
-
const
|
|
4995
|
-
const
|
|
4996
|
-
const
|
|
4997
|
-
const
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5384
|
+
let fitMode = "width";
|
|
5385
|
+
const calculateFitScale = (mode = fitMode) => {
|
|
5386
|
+
const elW = 816;
|
|
5387
|
+
const elH = 1056;
|
|
5388
|
+
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
5389
|
+
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
5390
|
+
const sW = availW / elW;
|
|
5391
|
+
const sH = availH / elH;
|
|
5392
|
+
if (mode === "page") {
|
|
5393
|
+
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
5394
|
+
}
|
|
5395
|
+
return Math.max(0.65, Math.min(1.05, sW));
|
|
5003
5396
|
};
|
|
5004
5397
|
setTimeout(() => {
|
|
5005
|
-
|
|
5398
|
+
fitMode = "width";
|
|
5399
|
+
scale = calculateFitScale("width");
|
|
5006
5400
|
applyTransform();
|
|
5007
5401
|
}, 60);
|
|
5008
5402
|
const cleanup = () => {
|
|
@@ -5030,7 +5424,8 @@ var DocPlugin = class {
|
|
|
5030
5424
|
applyTransform();
|
|
5031
5425
|
},
|
|
5032
5426
|
fitToPage: () => {
|
|
5033
|
-
|
|
5427
|
+
fitMode = fitMode === "width" ? "page" : "width";
|
|
5428
|
+
scale = calculateFitScale(fitMode);
|
|
5034
5429
|
rotation = 0;
|
|
5035
5430
|
applyTransform();
|
|
5036
5431
|
},
|
|
@@ -5158,8 +5553,28 @@ var DocPlugin = class {
|
|
|
5158
5553
|
}
|
|
5159
5554
|
splitIntoPages(text) {
|
|
5160
5555
|
if (!text) return [""];
|
|
5161
|
-
const
|
|
5162
|
-
|
|
5556
|
+
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);
|
|
5557
|
+
if (explicitParts.length === 0) explicitParts.push(text);
|
|
5558
|
+
const maxLinesPerPage = 48;
|
|
5559
|
+
const finalPages = [];
|
|
5560
|
+
for (const part of explicitParts) {
|
|
5561
|
+
const lines = part.split(/\r?\n/);
|
|
5562
|
+
let currentLines = [];
|
|
5563
|
+
let count = 0;
|
|
5564
|
+
for (const line of lines) {
|
|
5565
|
+
currentLines.push(line);
|
|
5566
|
+
count++;
|
|
5567
|
+
if (count >= maxLinesPerPage) {
|
|
5568
|
+
finalPages.push(currentLines.join("\n"));
|
|
5569
|
+
currentLines = [];
|
|
5570
|
+
count = 0;
|
|
5571
|
+
}
|
|
5572
|
+
}
|
|
5573
|
+
if (currentLines.length > 0) {
|
|
5574
|
+
finalPages.push(currentLines.join("\n"));
|
|
5575
|
+
}
|
|
5576
|
+
}
|
|
5577
|
+
return finalPages.length > 0 ? finalPages : [text];
|
|
5163
5578
|
}
|
|
5164
5579
|
/**
|
|
5165
5580
|
* Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
|
|
@@ -5168,17 +5583,65 @@ var DocPlugin = class {
|
|
|
5168
5583
|
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
|
|
5169
5584
|
let html = "";
|
|
5170
5585
|
let inList = false;
|
|
5171
|
-
|
|
5172
|
-
|
|
5586
|
+
let tableLines = [];
|
|
5587
|
+
const flushTable = () => {
|
|
5588
|
+
if (tableLines.length > 0) {
|
|
5589
|
+
html += '<table style="width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 12px;">';
|
|
5590
|
+
for (const tLine of tableLines) {
|
|
5591
|
+
html += "<tr>";
|
|
5592
|
+
const cols = tLine.split(" ");
|
|
5593
|
+
for (const col of cols) {
|
|
5594
|
+
html += `<td style="border: 1px solid #cbd5e1; padding: 6px 8px;">${DOMPurify6.sanitize(col.trim())}</td>`;
|
|
5595
|
+
}
|
|
5596
|
+
html += "</tr>";
|
|
5597
|
+
}
|
|
5598
|
+
html += "</table>";
|
|
5599
|
+
tableLines = [];
|
|
5600
|
+
}
|
|
5601
|
+
};
|
|
5602
|
+
let i = 0;
|
|
5603
|
+
while (i < lines.length) {
|
|
5604
|
+
let line = lines[i];
|
|
5605
|
+
let tabCount = (line.match(/\t/g) || []).length;
|
|
5606
|
+
if (tabCount > 0) {
|
|
5607
|
+
let consecutiveTableLines = 1;
|
|
5608
|
+
let j = i + 1;
|
|
5609
|
+
while (j < lines.length) {
|
|
5610
|
+
const nextTabCount = (lines[j].match(/\t/g) || []).length;
|
|
5611
|
+
if (nextTabCount === tabCount) {
|
|
5612
|
+
consecutiveTableLines++;
|
|
5613
|
+
j++;
|
|
5614
|
+
} else {
|
|
5615
|
+
break;
|
|
5616
|
+
}
|
|
5617
|
+
}
|
|
5618
|
+
if (consecutiveTableLines >= 3) {
|
|
5619
|
+
if (inList) {
|
|
5620
|
+
html += "</ul>";
|
|
5621
|
+
inList = false;
|
|
5622
|
+
}
|
|
5623
|
+
tableLines = lines.slice(i, j);
|
|
5624
|
+
flushTable();
|
|
5625
|
+
i = j;
|
|
5626
|
+
continue;
|
|
5627
|
+
}
|
|
5628
|
+
}
|
|
5629
|
+
line = line.trim();
|
|
5173
5630
|
if (!line) {
|
|
5174
5631
|
if (inList) {
|
|
5175
5632
|
html += "</ul>";
|
|
5176
5633
|
inList = false;
|
|
5177
5634
|
}
|
|
5635
|
+
html += '<div style="height: 1.15em;"></div>';
|
|
5636
|
+
i++;
|
|
5637
|
+
continue;
|
|
5638
|
+
}
|
|
5639
|
+
if (/^[\x00-\x1F\x7F-\x9F]+$/.test(line)) {
|
|
5640
|
+
i++;
|
|
5178
5641
|
continue;
|
|
5179
5642
|
}
|
|
5180
|
-
if (
|
|
5181
|
-
|
|
5643
|
+
if ((line.includes("Normal.dot") || line.includes("Microsoft Word") || line.includes("Times New Roman")) && line.length < 30) {
|
|
5644
|
+
i++;
|
|
5182
5645
|
continue;
|
|
5183
5646
|
}
|
|
5184
5647
|
if (line.length < 60 && !line.endsWith(".") && (/^[A-Z0-9\s:_-]+$/.test(line) || line.startsWith("#"))) {
|
|
@@ -5186,24 +5649,26 @@ var DocPlugin = class {
|
|
|
5186
5649
|
html += "</ul>";
|
|
5187
5650
|
inList = false;
|
|
5188
5651
|
}
|
|
5189
|
-
html += `<h2 style="font-size:
|
|
5652
|
+
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>`;
|
|
5190
5653
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
5191
5654
|
if (!inList) {
|
|
5192
5655
|
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
5193
5656
|
inList = true;
|
|
5194
5657
|
}
|
|
5195
5658
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
5196
|
-
html += `<li style="margin: 4px 0; line-height: 1.
|
|
5659
|
+
html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6.sanitize(bulletText)}</li>`;
|
|
5197
5660
|
} else {
|
|
5198
5661
|
if (inList) {
|
|
5199
5662
|
html += "</ul>";
|
|
5200
5663
|
inList = false;
|
|
5201
5664
|
}
|
|
5202
|
-
html += `<p style="line-height: 1.
|
|
5665
|
+
html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6.sanitize(line)}</p>`;
|
|
5203
5666
|
}
|
|
5667
|
+
i++;
|
|
5204
5668
|
}
|
|
5205
5669
|
if (inList) html += "</ul>";
|
|
5206
|
-
|
|
5670
|
+
flushTable();
|
|
5671
|
+
return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify6.sanitize(filename)})</p>`;
|
|
5207
5672
|
}
|
|
5208
5673
|
};
|
|
5209
5674
|
function docPlugin() {
|
|
@@ -5381,7 +5846,7 @@ var PptPlugin = class {
|
|
|
5381
5846
|
if (s.pictureUrl) {
|
|
5382
5847
|
contentHtml = `
|
|
5383
5848
|
<div style="flex: 1; display: flex; justify-content: center; align-items: center; padding: 12px; overflow: hidden;">
|
|
5384
|
-
<img src="${s.pictureUrl}" alt="${
|
|
5849
|
+
<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;" />
|
|
5385
5850
|
</div>
|
|
5386
5851
|
`;
|
|
5387
5852
|
} else if (s.tableColumns.length > 0) {
|
|
@@ -5391,7 +5856,7 @@ var PptPlugin = class {
|
|
|
5391
5856
|
<table style="width: 100%; border-collapse: collapse; border: 1px solid #cbd5e1; border-radius: 6px; overflow: hidden; background: #ffffff;">
|
|
5392
5857
|
<thead>
|
|
5393
5858
|
<tr style="background: #e2e8f0; color: #1e293b; font-weight: 600; font-size: 14px;">
|
|
5394
|
-
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${
|
|
5859
|
+
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify6.sanitize(c)}</th>`).join("")}
|
|
5395
5860
|
</tr>
|
|
5396
5861
|
</thead>
|
|
5397
5862
|
<tbody>
|
|
@@ -5407,7 +5872,7 @@ var PptPlugin = class {
|
|
|
5407
5872
|
} else {
|
|
5408
5873
|
const pTags = s.paragraphs.map((p) => {
|
|
5409
5874
|
const lines = p.split(/[\r\n]+/).map((l) => l.trim()).filter(Boolean);
|
|
5410
|
-
return lines.map((l) => `<p style="margin: 0 0 14px; font-size: 14px; line-height: 1.65; color: #334155; text-align: justify;">${
|
|
5875
|
+
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("");
|
|
5411
5876
|
}).join("");
|
|
5412
5877
|
contentHtml = `
|
|
5413
5878
|
<div style="flex: 1; overflow: auto; padding: 4px 8px; display: flex; flex-direction: column; justify-content: flex-start;">
|
|
@@ -5420,11 +5885,11 @@ var PptPlugin = class {
|
|
|
5420
5885
|
<!-- Header Banner matching PowerPoint design -->
|
|
5421
5886
|
<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;">
|
|
5422
5887
|
<h1 style="margin: 0; font-size: 26px; font-weight: 700; color: #1e293b; letter-spacing: -0.3px;">
|
|
5423
|
-
${
|
|
5888
|
+
${DOMPurify6.sanitize(s.title)}
|
|
5424
5889
|
</h1>
|
|
5425
5890
|
${s.subtitle ? `
|
|
5426
5891
|
<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);">
|
|
5427
|
-
${
|
|
5892
|
+
${DOMPurify6.sanitize(s.subtitle)}
|
|
5428
5893
|
</span>
|
|
5429
5894
|
` : `
|
|
5430
5895
|
<span style="font-size: 12px; color: #365314; font-weight: 600;">
|