@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/react.cjs CHANGED
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var react = require('react');
6
- var DOMPurify2 = require('dompurify');
6
+ var DOMPurify6 = require('dompurify');
7
7
  var pdfjsLib = require('pdfjs-dist');
8
8
  var docx = require('docx-preview');
9
9
  var fflate = require('fflate');
@@ -38,7 +38,7 @@ function _interopNamespace(e) {
38
38
  return Object.freeze(n);
39
39
  }
40
40
 
41
- var DOMPurify2__default = /*#__PURE__*/_interopDefault(DOMPurify2);
41
+ var DOMPurify6__default = /*#__PURE__*/_interopDefault(DOMPurify6);
42
42
  var pdfjsLib__namespace = /*#__PURE__*/_interopNamespace(pdfjsLib);
43
43
  var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
44
44
  var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
@@ -390,7 +390,7 @@ async function sourceToArrayBuffer(source, signal) {
390
390
  if (magicMime === "application/zip") {
391
391
  const ooxmlMime = detectOoxmlType(buffer);
392
392
  if (ooxmlMime && ooxmlMime !== "application/zip") {
393
- metadata.mimeType = ooxmlMime;
393
+ metadata.mimeType = metadata.mimeType ?? ooxmlMime;
394
394
  if (ooxmlMime.includes("wordprocessing")) metadata.extension = metadata.extension ?? ".docx";
395
395
  else if (ooxmlMime.includes("spreadsheet")) metadata.extension = metadata.extension ?? ".xlsx";
396
396
  else if (ooxmlMime.includes("presentation")) metadata.extension = metadata.extension ?? ".pptx";
@@ -419,7 +419,7 @@ async function sourceToArrayBuffer(source, signal) {
419
419
  return { buffer, metadata };
420
420
  }
421
421
  function sanitizeSVG(svg) {
422
- return DOMPurify2__default.default.sanitize(svg, {
422
+ return DOMPurify6__default.default.sanitize(svg, {
423
423
  USE_PROFILES: { svg: true, svgFilters: true }
424
424
  });
425
425
  }
@@ -466,7 +466,8 @@ function createElement(tag, attrs, ...children) {
466
466
  }
467
467
  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>`;
468
468
  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>`;
469
- 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"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" y1="3" x2="14" y2="10"></line><line x1="3" y1="21" x2="10" y2="14"></line></svg>`;
469
+ 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>`;
470
+ 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>`;
470
471
  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>`;
471
472
  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>`;
472
473
  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>`;
@@ -486,6 +487,7 @@ var ICON_MAP = {
486
487
  "zoom-in": ICON_ZOOM_IN,
487
488
  "zoom-out": ICON_ZOOM_OUT,
488
489
  "fit-page": ICON_FIT_PAGE,
490
+ "fit-width": ICON_FIT_WIDTH,
489
491
  "fit-slide": ICON_FIT_PAGE,
490
492
  "rotate-cw": ICON_ROTATE_CW,
491
493
  "rotate-ccw": ICON_ROTATE_CCW,
@@ -1432,6 +1434,7 @@ var PdfPlugin = class {
1432
1434
  let currentPage = 1;
1433
1435
  let zoomScale = 1;
1434
1436
  let rotation = 0;
1437
+ let fitMode = "width";
1435
1438
  let currentRenderTask = null;
1436
1439
  const renderPage = async (pageNum) => {
1437
1440
  if (currentRenderTask) {
@@ -1451,11 +1454,16 @@ var PdfPlugin = class {
1451
1454
  const containerWidth = container.clientWidth || 900;
1452
1455
  const containerHeight = container.clientHeight || 700;
1453
1456
  const unscaledVp = page.getViewport({ scale: 1, rotation });
1454
- const availWidth = Math.max(100, containerWidth - 48);
1455
- const availHeight = Math.max(100, containerHeight - 88);
1457
+ const availWidth = Math.max(280, containerWidth - 48);
1458
+ const availHeight = Math.max(280, containerHeight - 88);
1456
1459
  const scaleW = availWidth / unscaledVp.width;
1457
1460
  const scaleH = availHeight / unscaledVp.height;
1458
- const fitScale = Math.min(scaleW, scaleH);
1461
+ let fitScale;
1462
+ if (fitMode === "page") {
1463
+ fitScale = Math.max(0.5, Math.min(scaleW, scaleH));
1464
+ } else {
1465
+ fitScale = Math.max(0.65, Math.min(1.15, scaleW));
1466
+ }
1459
1467
  const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
1460
1468
  const pixelRatio = window.devicePixelRatio || 1;
1461
1469
  const viewport = page.getViewport({ scale: effectiveScale, rotation });
@@ -1481,7 +1489,19 @@ var PdfPlugin = class {
1481
1489
  }
1482
1490
  };
1483
1491
  await renderPage(1);
1492
+ let resizeTimer = null;
1493
+ const resizeObserver = new ResizeObserver(() => {
1494
+ if (resizeTimer) clearTimeout(resizeTimer);
1495
+ resizeTimer = setTimeout(() => {
1496
+ if (Math.abs(zoomScale - 1) < 0.05) {
1497
+ renderPage(currentPage);
1498
+ }
1499
+ }, 150);
1500
+ });
1501
+ resizeObserver.observe(container);
1484
1502
  const cleanup = () => {
1503
+ resizeObserver.disconnect();
1504
+ if (resizeTimer) clearTimeout(resizeTimer);
1485
1505
  if (currentRenderTask) {
1486
1506
  try {
1487
1507
  currentRenderTask.cancel();
@@ -1512,6 +1532,7 @@ var PdfPlugin = class {
1512
1532
  renderPage(currentPage);
1513
1533
  },
1514
1534
  fitToPage: () => {
1535
+ fitMode = fitMode === "width" ? "page" : "width";
1515
1536
  zoomScale = 1;
1516
1537
  rotation = 0;
1517
1538
  renderPage(currentPage);
@@ -2065,8 +2086,53 @@ var DocxPlugin = class {
2065
2086
  }
2066
2087
  }
2067
2088
  }
2068
- const sections = wrapper.querySelectorAll("section.docx");
2069
- const cards = wrapper.querySelectorAll(".fp-docx-page-card");
2089
+ let sections = Array.from(wrapper.querySelectorAll("section.docx"));
2090
+ const cards = Array.from(wrapper.querySelectorAll(".fp-docx-page-card"));
2091
+ if (sections.length === 1 && cards.length === 0) {
2092
+ const singleSec = sections[0];
2093
+ const pageH = 1056;
2094
+ const secH = singleSec.offsetHeight || singleSec.scrollHeight;
2095
+ if (secH > pageH * 1.25) {
2096
+ const children = Array.from(singleSec.children);
2097
+ if (children.length > 1) {
2098
+ const parent = singleSec.parentElement || wrapper;
2099
+ const newSections = [singleSec];
2100
+ singleSec.innerHTML = "";
2101
+ singleSec.style.minHeight = `${pageH}px`;
2102
+ singleSec.style.maxHeight = `${pageH}px`;
2103
+ singleSec.style.overflow = "hidden";
2104
+ singleSec.style.boxSizing = "border-box";
2105
+ let curSec = singleSec;
2106
+ let curH = 0;
2107
+ const maxH = pageH - 96;
2108
+ for (let i = 0; i < children.length; i++) {
2109
+ const child = children[i];
2110
+ curSec.appendChild(child);
2111
+ const chH = child.offsetHeight || 28;
2112
+ curH += chH;
2113
+ if (curH >= maxH && i < children.length - 1) {
2114
+ const nextSec = document.createElement("section");
2115
+ nextSec.className = singleSec.className;
2116
+ nextSec.style.cssText = singleSec.style.cssText;
2117
+ nextSec.style.width = singleSec.style.width || "816px";
2118
+ nextSec.style.minHeight = `${pageH}px`;
2119
+ nextSec.style.maxHeight = `${pageH}px`;
2120
+ nextSec.style.overflow = "hidden";
2121
+ nextSec.style.boxSizing = "border-box";
2122
+ nextSec.style.backgroundColor = "#ffffff";
2123
+ nextSec.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
2124
+ nextSec.style.borderRadius = "4px";
2125
+ nextSec.style.marginBottom = "24px";
2126
+ parent.appendChild(nextSec);
2127
+ newSections.push(nextSec);
2128
+ curSec = nextSec;
2129
+ curH = 0;
2130
+ }
2131
+ }
2132
+ sections = newSections;
2133
+ }
2134
+ }
2135
+ }
2070
2136
  const pageElements = sections.length > 0 ? sections : cards;
2071
2137
  const totalPages = Math.max(1, pageElements.length);
2072
2138
  let currentPage = 1;
@@ -2110,22 +2176,27 @@ var DocxPlugin = class {
2110
2176
  }
2111
2177
  scale = 1;
2112
2178
  let rotation = 0;
2113
- const calculateFitScale = () => {
2179
+ let fitMode = "width";
2180
+ const calculateFitScale = (mode = fitMode) => {
2114
2181
  const activeEl = pageElements[currentPage - 1] || wrapper.firstElementChild || wrapper;
2115
2182
  const elW = activeEl.offsetWidth || 816;
2116
- const elH = activeEl.offsetHeight || 1056;
2117
- const availW = Math.max(200, ctx.container.clientWidth - 48);
2118
- const availH = Math.max(200, ctx.container.clientHeight - 80);
2183
+ const singlePageH = Math.min(activeEl.offsetHeight || 1056, Math.round(elW * 1.32));
2184
+ const availW = Math.max(280, ctx.container.clientWidth - 48);
2185
+ const availH = Math.max(280, ctx.container.clientHeight - 80);
2119
2186
  const sW = availW / elW;
2120
- const sH = availH / elH;
2121
- return Math.min(1.1, Math.min(sW, sH));
2187
+ const sH = availH / singlePageH;
2188
+ if (mode === "page") {
2189
+ return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
2190
+ }
2191
+ return Math.max(0.65, Math.min(1.05, sW));
2122
2192
  };
2123
2193
  const applyTransform = () => {
2124
2194
  wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
2125
2195
  wrapper.style.transformOrigin = "top center";
2126
2196
  };
2127
2197
  setTimeout(() => {
2128
- scale = calculateFitScale();
2198
+ fitMode = "width";
2199
+ scale = calculateFitScale("width");
2129
2200
  applyTransform();
2130
2201
  }, 60);
2131
2202
  const cleanup = () => {
@@ -2159,7 +2230,8 @@ var DocxPlugin = class {
2159
2230
  applyTransform();
2160
2231
  },
2161
2232
  fitToPage: () => {
2162
- scale = calculateFitScale();
2233
+ fitMode = fitMode === "width" ? "page" : "width";
2234
+ scale = calculateFitScale(fitMode);
2163
2235
  rotation = 0;
2164
2236
  applyTransform();
2165
2237
  },
@@ -2229,90 +2301,149 @@ var DocxPlugin = class {
2229
2301
  console.warn("[DocxPlugin] Error parsing relationships:", relsErr);
2230
2302
  }
2231
2303
  }
2232
- const card = document.createElement("div");
2233
- card.className = "fp-docx-page-card";
2234
- card.style.backgroundColor = "#ffffff";
2235
- card.style.borderRadius = "6px";
2236
- card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
2237
- card.style.padding = "48px 56px";
2238
- card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
2239
- card.style.color = "#1e293b";
2240
- card.style.lineHeight = "1.6";
2304
+ const sectPrs = Array.from(doc.getElementsByTagNameNS("*", "sectPr"));
2305
+ const lastSectPr = sectPrs[sectPrs.length - 1];
2306
+ let defaultW = 12240;
2307
+ let defaultH = 15840;
2308
+ let margins = { top: 1440, right: 1440, bottom: 1440, left: 1440 };
2309
+ if (lastSectPr) {
2310
+ const pgSz = lastSectPr.getElementsByTagNameNS("*", "pgSz")[0];
2311
+ if (pgSz) {
2312
+ defaultW = parseInt(pgSz.getAttribute("w:w") || pgSz.getAttribute("w") || "12240", 10);
2313
+ defaultH = parseInt(pgSz.getAttribute("w:h") || pgSz.getAttribute("h") || "15840", 10);
2314
+ }
2315
+ const pgMar = lastSectPr.getElementsByTagNameNS("*", "pgMar")[0];
2316
+ if (pgMar) {
2317
+ margins.top = parseInt(pgMar.getAttribute("w:top") || pgMar.getAttribute("top") || "1440", 10);
2318
+ margins.bottom = parseInt(pgMar.getAttribute("w:bottom") || pgMar.getAttribute("bottom") || "1440", 10);
2319
+ margins.left = parseInt(pgMar.getAttribute("w:left") || pgMar.getAttribute("left") || "1440", 10);
2320
+ margins.right = parseInt(pgMar.getAttribute("w:right") || pgMar.getAttribute("right") || "1440", 10);
2321
+ }
2322
+ }
2323
+ const createPageCard = () => {
2324
+ const card = document.createElement("div");
2325
+ card.className = "fp-docx-page-card";
2326
+ card.style.backgroundColor = "#ffffff";
2327
+ card.style.borderRadius = "4px";
2328
+ card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
2329
+ card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
2330
+ card.style.color = "#1e293b";
2331
+ card.style.lineHeight = "1.6";
2332
+ card.style.boxSizing = "border-box";
2333
+ card.style.overflow = "hidden";
2334
+ card.style.position = "relative";
2335
+ card.style.marginBottom = "24px";
2336
+ card.style.width = `${defaultW / 15}px`;
2337
+ card.style.height = `${defaultH / 15}px`;
2338
+ card.style.padding = `${margins.top / 15}px ${margins.right / 15}px ${margins.bottom / 15}px ${margins.left / 15}px`;
2339
+ return card;
2340
+ };
2341
+ let currentCard = createPageCard();
2342
+ let currentHtml = "";
2343
+ const pages = [{ card: currentCard, html: "" }];
2344
+ const flushHtml = () => {
2345
+ pages[pages.length - 1].html += currentHtml;
2346
+ currentHtml = "";
2347
+ };
2348
+ const newPage = () => {
2349
+ flushHtml();
2350
+ currentCard = createPageCard();
2351
+ pages.push({ card: currentCard, html: "" });
2352
+ };
2241
2353
  const body = doc.getElementsByTagNameNS("*", "body")[0] || doc.documentElement;
2242
- let html = "";
2243
2354
  for (const child of Array.from(body.children)) {
2244
2355
  const tag = child.localName || child.nodeName.split(":").pop();
2245
2356
  if (tag === "p") {
2246
2357
  const pStyle = child.getElementsByTagNameNS("*", "pStyle")[0];
2247
2358
  const styleVal = pStyle?.getAttribute("w:val") || pStyle?.getAttribute("val") || "";
2248
2359
  const numPr = child.getElementsByTagNameNS("*", "numPr")[0];
2249
- const textContent = this.extractParagraphHtml(child, imageMap);
2250
- if (!textContent.trim()) {
2251
- html += '<div style="height: 10px;"></div>';
2252
- continue;
2253
- }
2254
- const lowerStyle = styleVal.toLowerCase();
2255
- if (lowerStyle.includes("title")) {
2256
- html += `<h1 style="font-size: 28px; font-weight: 700; color: #1e3a8a; margin: 24px 0 12px; border-bottom: 2px solid #e2e8f0; padding-bottom: 8px;">${textContent}</h1>`;
2257
- } else if (lowerStyle.includes("heading1") || styleVal === "1") {
2258
- html += `<h2 style="font-size: 22px; font-weight: 700; color: #1e40af; margin: 20px 0 10px;">${textContent}</h2>`;
2259
- } else if (lowerStyle.includes("heading2") || styleVal === "2") {
2260
- html += `<h3 style="font-size: 18px; font-weight: 600; color: #2563eb; margin: 16px 0 8px;">${textContent}</h3>`;
2261
- } else if (lowerStyle.includes("heading3") || styleVal === "3") {
2262
- html += `<h4 style="font-size: 15px; font-weight: 600; color: #334155; margin: 12px 0 6px;">${textContent}</h4>`;
2263
- } else if (numPr) {
2264
- html += `<div style="display: flex; gap: 8px; margin: 4px 0 4px 20px;"><span style="color: #2563eb; font-weight: bold;">\u2022</span><span>${textContent}</span></div>`;
2265
- } else {
2266
- html += `<p style="margin: 8px 0; font-size: 14px;">${textContent}</p>`;
2360
+ const chunks = this.extractParagraphChunks(child, imageMap);
2361
+ for (let i = 0; i < chunks.length; i++) {
2362
+ if (i > 0) {
2363
+ newPage();
2364
+ }
2365
+ const textContent = chunks[i];
2366
+ if (!textContent.trim() && !textContent.includes("<img")) {
2367
+ currentHtml += '<div style="height: 10px;"></div>';
2368
+ continue;
2369
+ }
2370
+ const lowerStyle = styleVal.toLowerCase();
2371
+ if (lowerStyle.includes("title")) {
2372
+ 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>`;
2373
+ } else if (lowerStyle.includes("heading1") || styleVal === "1") {
2374
+ currentHtml += `<h2 style="font-size: 22px; font-weight: 700; color: #1e40af; margin: 20px 0 10px;">${textContent}</h2>`;
2375
+ } else if (lowerStyle.includes("heading2") || styleVal === "2") {
2376
+ currentHtml += `<h3 style="font-size: 18px; font-weight: 600; color: #2563eb; margin: 16px 0 8px;">${textContent}</h3>`;
2377
+ } else if (lowerStyle.includes("heading3") || styleVal === "3") {
2378
+ currentHtml += `<h4 style="font-size: 15px; font-weight: 600; color: #334155; margin: 12px 0 6px;">${textContent}</h4>`;
2379
+ } else if (numPr) {
2380
+ 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>`;
2381
+ } else {
2382
+ currentHtml += `<p style="margin: 8px 0; font-size: 14px;">${textContent}</p>`;
2383
+ }
2267
2384
  }
2268
2385
  } else if (tag === "tbl") {
2269
- html += '<table style="width: 100%; border-collapse: collapse; margin: 20px 0; border: 1px solid #cbd5e1;">';
2386
+ currentHtml += '<table style="width: 100%; border-collapse: collapse; margin: 20px 0; border: 1px solid #cbd5e1;">';
2270
2387
  const rows = Array.from(child.getElementsByTagNameNS("*", "tr"));
2271
2388
  rows.forEach((tr, rIdx) => {
2272
- html += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
2389
+ currentHtml += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
2273
2390
  const cells = Array.from(tr.getElementsByTagNameNS("*", "tc"));
2274
2391
  cells.forEach((tc) => {
2275
2392
  const cellText = this.extractParagraphHtml(tc, imageMap);
2276
- html += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || "&nbsp;"}</td>`;
2393
+ currentHtml += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || "&nbsp;"}</td>`;
2277
2394
  });
2278
- html += "</tr>";
2395
+ currentHtml += "</tr>";
2279
2396
  });
2280
- html += "</table>";
2397
+ currentHtml += "</table>";
2281
2398
  }
2282
2399
  }
2283
- card.innerHTML = DOMPurify2__default.default.sanitize(html, {
2284
- ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "s", "strike", "img", "div", "br"],
2285
- ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
2286
- });
2287
- wrapper.appendChild(card);
2400
+ flushHtml();
2401
+ for (const page of pages) {
2402
+ page.card.innerHTML = DOMPurify6__default.default.sanitize(page.html, {
2403
+ ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "s", "strike", "img", "div", "br"],
2404
+ ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
2405
+ });
2406
+ wrapper.appendChild(page.card);
2407
+ }
2288
2408
  }
2289
2409
  extractParagraphHtml(pElement, imageMap = {}) {
2290
- let result = "";
2410
+ return this.extractParagraphChunks(pElement, imageMap).join("<br/>");
2411
+ }
2412
+ extractParagraphChunks(pElement, imageMap = {}) {
2413
+ const chunks = [""];
2414
+ let currentChunkIndex = 0;
2291
2415
  const drawings = Array.from(pElement.getElementsByTagNameNS("*", "drawing"));
2292
2416
  for (const drawing of drawings) {
2293
2417
  const blip = drawing.getElementsByTagNameNS("*", "blip")[0];
2294
2418
  const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
2295
2419
  if (rId && imageMap[rId]) {
2296
- result += `<div style="text-align:center; margin: 12px 0;"><img src="${imageMap[rId]}" style="max-width: 100%; height: auto; border-radius: 4px;" /></div>`;
2420
+ chunks[currentChunkIndex] += `<div style="text-align:center; margin: 12px 0;"><img src="${imageMap[rId]}" style="max-width: 100%; height: auto; border-radius: 4px;" /></div>`;
2297
2421
  }
2298
2422
  }
2299
2423
  const runs = Array.from(pElement.getElementsByTagNameNS("*", "r"));
2300
- if (runs.length === 0 && !result) {
2301
- return DOMPurify2__default.default.sanitize(pElement.textContent || "");
2424
+ if (runs.length === 0 && !chunks[currentChunkIndex]) {
2425
+ chunks[currentChunkIndex] = DOMPurify6__default.default.sanitize(pElement.textContent || "");
2426
+ return chunks;
2302
2427
  }
2303
2428
  for (const r of runs) {
2304
2429
  const blip = r.getElementsByTagNameNS("*", "blip")[0] || r.getElementsByTagNameNS("*", "imagedata")[0];
2305
2430
  const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
2306
2431
  if (rId && imageMap[rId]) {
2307
- result += `<img src="${imageMap[rId]}" style="max-width: 100%; height: auto; display: inline-block; margin: 4px;" />`;
2432
+ chunks[currentChunkIndex] += `<img src="${imageMap[rId]}" style="max-width: 100%; height: auto; display: inline-block; margin: 4px;" />`;
2308
2433
  }
2309
- const brs = r.getElementsByTagNameNS("*", "br");
2310
- for (let i = 0; i < brs.length; i++) {
2311
- result += "<br/>";
2434
+ const brs = Array.from(r.getElementsByTagNameNS("*", "br"));
2435
+ for (const br of brs) {
2436
+ const type = br.getAttribute("w:type") || br.getAttribute("type");
2437
+ if (type === "page") {
2438
+ chunks.push("");
2439
+ currentChunkIndex++;
2440
+ } else {
2441
+ chunks[currentChunkIndex] += "<br/>";
2442
+ }
2312
2443
  }
2313
2444
  const tabs = r.getElementsByTagNameNS("*", "tab");
2314
2445
  if (tabs.length > 0) {
2315
- result += "&emsp;";
2446
+ chunks[currentChunkIndex] += "&emsp;";
2316
2447
  }
2317
2448
  const rPr = r.getElementsByTagNameNS("*", "rPr")[0];
2318
2449
  const isBold = !!rPr?.getElementsByTagNameNS("*", "b")[0];
@@ -2326,7 +2457,7 @@ var DocxPlugin = class {
2326
2457
  const texts = Array.from(r.getElementsByTagNameNS("*", "t"));
2327
2458
  let text = texts.map((t) => t.textContent || "").join("");
2328
2459
  if (!text) continue;
2329
- text = DOMPurify2__default.default.sanitize(text);
2460
+ text = DOMPurify6__default.default.sanitize(text);
2330
2461
  let styles = "";
2331
2462
  if (isBold) styles += "font-weight: bold; ";
2332
2463
  if (isItalic) styles += "font-style: italic; ";
@@ -2338,12 +2469,12 @@ var DocxPlugin = class {
2338
2469
  if (!isNaN(pt) && pt > 0) styles += `font-size: ${pt}pt; `;
2339
2470
  }
2340
2471
  if (styles) {
2341
- result += `<span style="${styles}">${text}</span>`;
2472
+ chunks[currentChunkIndex] += `<span style="${styles}">${text}</span>`;
2342
2473
  } else {
2343
- result += text;
2474
+ chunks[currentChunkIndex] += text;
2344
2475
  }
2345
2476
  }
2346
- return result;
2477
+ return chunks;
2347
2478
  }
2348
2479
  renderBinaryDocFallback(ctx, wrapper) {
2349
2480
  const card = document.createElement("div");
@@ -2360,14 +2491,14 @@ var DocxPlugin = class {
2360
2491
  const wordDocStream = cfbf.readStream("WordDocument");
2361
2492
  if (wordDocStream && wordDocStream.length >= 512) {
2362
2493
  const text2 = this.extractReadableStrings(wordDocStream);
2363
- card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify2__default.default.sanitize(text2)}</div>`;
2494
+ card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6__default.default.sanitize(text2)}</div>`;
2364
2495
  wrapper.appendChild(card);
2365
2496
  return;
2366
2497
  }
2367
2498
  } catch {
2368
2499
  }
2369
2500
  const text = this.extractReadableStrings(new Uint8Array(ctx.buffer));
2370
- card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify2__default.default.sanitize(text)}</div>`;
2501
+ card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6__default.default.sanitize(text)}</div>`;
2371
2502
  wrapper.appendChild(card);
2372
2503
  }
2373
2504
  extractReadableStrings(bytes) {
@@ -2544,11 +2675,9 @@ var ExcelPlugin = class {
2544
2675
  const calculateFitScale = () => {
2545
2676
  const table = contentArea.querySelector("table");
2546
2677
  if (!table) return 1;
2547
- const availW = Math.max(200, container.clientWidth - 48);
2548
- const availH = Math.max(200, container.clientHeight - 80);
2678
+ const availW = Math.max(280, container.clientWidth - 48);
2549
2679
  const tW = table.offsetWidth || 800;
2550
- const tH = table.offsetHeight || 600;
2551
- return Math.min(1, Math.min(availW / tW, availH / tH));
2680
+ return Math.max(0.65, Math.min(1, availW / tW));
2552
2681
  };
2553
2682
  try {
2554
2683
  wb = XLSX__namespace.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
@@ -2966,41 +3095,94 @@ var CodePlugin = class {
2966
3095
  async render(ctx) {
2967
3096
  const decoder = new TextDecoder("utf-8");
2968
3097
  const fullText = decoder.decode(ctx.buffer);
2969
- const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
2970
- const rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
3098
+ const extRaw = ctx.metadata.extension?.toLowerCase();
3099
+ const mimeRaw = ctx.metadata.mimeType?.toLowerCase();
3100
+ const isTxt = extRaw === ".txt" || mimeRaw === "text/plain" && (!extRaw || !this.extensions.filter((e) => e !== ".txt").includes(extRaw));
3101
+ let rawPages = [];
3102
+ if (isTxt) {
3103
+ const explicitPages = fullText.split(/(?:\f|\x0C)/);
3104
+ for (const ep of explicitPages) {
3105
+ const lines = ep.split(/\r?\n/);
3106
+ let currentChunk = [];
3107
+ for (let i = 0; i < lines.length; i++) {
3108
+ currentChunk.push(lines[i]);
3109
+ if (currentChunk.length >= 46) {
3110
+ rawPages.push(currentChunk.join("\n"));
3111
+ currentChunk = [];
3112
+ }
3113
+ }
3114
+ if (currentChunk.length > 0 || lines.length === 0) {
3115
+ rawPages.push(currentChunk.join("\n"));
3116
+ }
3117
+ }
3118
+ if (rawPages.length === 0) rawPages = [""];
3119
+ } else {
3120
+ const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
3121
+ rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
3122
+ }
2971
3123
  const totalPages = Math.max(1, rawPages.length);
2972
3124
  let currentPage = 1;
2973
3125
  const container = document.createElement("div");
2974
3126
  container.style.width = "100%";
2975
3127
  container.style.height = "100%";
2976
3128
  container.style.overflow = "auto";
2977
- container.style.backgroundColor = "#1e1e1e";
2978
- container.style.color = "#d4d4d4";
2979
- container.style.padding = "16px";
2980
- container.style.boxSizing = "border-box";
2981
3129
  let fontSize = 13;
2982
3130
  let rotation = 0;
3131
+ let zoomLevel = 1;
2983
3132
  const pre = document.createElement("pre");
2984
- pre.style.margin = "0";
2985
- pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
2986
- pre.style.fontSize = `${fontSize}px`;
2987
- pre.style.lineHeight = "1.5";
2988
- pre.style.whiteSpace = "pre-wrap";
2989
- pre.style.wordBreak = "break-all";
2990
3133
  const code = document.createElement("code");
3134
+ if (isTxt) {
3135
+ container.style.backgroundColor = "#f1f5f9";
3136
+ container.style.padding = "32px";
3137
+ container.style.boxSizing = "border-box";
3138
+ container.style.display = "flex";
3139
+ container.style.flexDirection = "column";
3140
+ container.style.alignItems = "center";
3141
+ pre.style.margin = "0";
3142
+ pre.style.fontFamily = "Consolas, 'Courier New', monospace";
3143
+ pre.style.fontSize = "13px";
3144
+ pre.style.color = "#1e293b";
3145
+ pre.style.lineHeight = "1.5";
3146
+ pre.style.whiteSpace = "pre-wrap";
3147
+ pre.style.wordBreak = "break-word";
3148
+ pre.style.backgroundColor = "#ffffff";
3149
+ pre.style.width = "816px";
3150
+ pre.style.minHeight = "1056px";
3151
+ pre.style.padding = "72px 56px";
3152
+ pre.style.boxSizing = "border-box";
3153
+ pre.style.boxShadow = "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)";
3154
+ pre.style.borderRadius = "4px";
3155
+ pre.style.transformOrigin = "top center";
3156
+ } else {
3157
+ container.style.backgroundColor = "#1e1e1e";
3158
+ container.style.color = "#d4d4d4";
3159
+ container.style.padding = "16px";
3160
+ container.style.boxSizing = "border-box";
3161
+ pre.style.margin = "0";
3162
+ pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
3163
+ pre.style.fontSize = `${fontSize}px`;
3164
+ pre.style.lineHeight = "1.5";
3165
+ pre.style.whiteSpace = "pre-wrap";
3166
+ pre.style.wordBreak = "break-all";
3167
+ pre.style.transformOrigin = "top left";
3168
+ }
2991
3169
  const ext = (ctx.metadata.extension || "").replace(".", "");
2992
3170
  const renderCodePage = (text) => {
2993
- try {
2994
- if (ext && hljs__default.default.getLanguage(ext)) {
2995
- code.innerHTML = hljs__default.default.highlight(text, { language: ext }).value;
2996
- } else {
2997
- code.innerHTML = hljs__default.default.highlightAuto(text).value;
2998
- }
2999
- } catch {
3171
+ if (isTxt) {
3000
3172
  code.textContent = text;
3173
+ } else {
3174
+ try {
3175
+ if (ext && hljs__default.default.getLanguage(ext)) {
3176
+ code.innerHTML = hljs__default.default.highlight(text, { language: ext }).value;
3177
+ } else {
3178
+ code.innerHTML = hljs__default.default.highlightAuto(text).value;
3179
+ }
3180
+ } catch {
3181
+ code.textContent = text;
3182
+ }
3001
3183
  }
3002
3184
  };
3003
- renderCodePage(rawPages[0] || fullText);
3185
+ renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
3004
3186
  pre.appendChild(code);
3005
3187
  container.appendChild(pre);
3006
3188
  let indicator = null;
@@ -3009,15 +3191,22 @@ var CodePlugin = class {
3009
3191
  indicator.className = "fp-code-page-indicator";
3010
3192
  indicator.style.position = "sticky";
3011
3193
  indicator.style.bottom = "16px";
3012
- indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
3013
- indicator.style.backdropFilter = "blur(8px)";
3014
- indicator.style.color = "#f8fafc";
3194
+ if (isTxt) {
3195
+ indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
3196
+ indicator.style.color = "#334155";
3197
+ indicator.style.border = "1px solid #e2e8f0";
3198
+ indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
3199
+ } else {
3200
+ indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
3201
+ indicator.style.color = "#f8fafc";
3202
+ indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
3203
+ indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
3204
+ indicator.style.backdropFilter = "blur(8px)";
3205
+ }
3015
3206
  indicator.style.fontSize = "12px";
3016
3207
  indicator.style.fontWeight = "600";
3017
3208
  indicator.style.padding = "5px 14px";
3018
3209
  indicator.style.borderRadius = "20px";
3019
- indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
3020
- indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
3021
3210
  indicator.style.zIndex = "10";
3022
3211
  indicator.style.userSelect = "none";
3023
3212
  indicator.style.pointerEvents = "none";
@@ -3028,7 +3217,7 @@ var CodePlugin = class {
3028
3217
  }
3029
3218
  const showPage = (pageNum) => {
3030
3219
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
3031
- renderCodePage(rawPages[currentPage - 1] || fullText);
3220
+ renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
3032
3221
  if (indicator) {
3033
3222
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
3034
3223
  }
@@ -3044,39 +3233,57 @@ var CodePlugin = class {
3044
3233
  ctx.container.innerHTML = "";
3045
3234
  };
3046
3235
  ctx.signal.addEventListener("abort", cleanup);
3236
+ const updateTransform = () => {
3237
+ if (isTxt) {
3238
+ pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
3239
+ } else {
3240
+ pre.style.transform = `rotate(${rotation}deg)`;
3241
+ pre.style.fontSize = `${fontSize}px`;
3242
+ }
3243
+ };
3047
3244
  return {
3048
3245
  destroy: cleanup,
3049
3246
  getPageCount: () => totalPages,
3050
3247
  getCurrentPage: () => currentPage,
3051
3248
  goToPage: (page) => showPage(page),
3052
3249
  zoomIn: () => {
3053
- fontSize = Math.min(32, fontSize + 2);
3054
- pre.style.fontSize = `${fontSize}px`;
3250
+ if (isTxt) {
3251
+ zoomLevel = Math.min(3, zoomLevel + 0.1);
3252
+ } else {
3253
+ fontSize = Math.min(32, fontSize + 2);
3254
+ }
3255
+ updateTransform();
3055
3256
  },
3056
3257
  zoomOut: () => {
3057
- fontSize = Math.max(8, fontSize - 2);
3058
- pre.style.fontSize = `${fontSize}px`;
3258
+ if (isTxt) {
3259
+ zoomLevel = Math.max(0.1, zoomLevel - 0.1);
3260
+ } else {
3261
+ fontSize = Math.max(8, fontSize - 2);
3262
+ }
3263
+ updateTransform();
3059
3264
  },
3060
- getZoom: () => fontSize / 13,
3265
+ getZoom: () => isTxt ? zoomLevel : fontSize / 13,
3061
3266
  setZoom: (level) => {
3062
- fontSize = Math.round(13 * level);
3063
- pre.style.fontSize = `${fontSize}px`;
3267
+ if (isTxt) {
3268
+ zoomLevel = level;
3269
+ } else {
3270
+ fontSize = Math.round(13 * level);
3271
+ }
3272
+ updateTransform();
3064
3273
  },
3065
3274
  fitToPage: () => {
3066
3275
  fontSize = 13;
3067
3276
  rotation = 0;
3068
- pre.style.fontSize = "13px";
3069
- pre.style.transform = "none";
3277
+ zoomLevel = isTxt ? Math.max(0.65, Math.min(1.05, (container.clientWidth - 48) / 816)) : 1;
3278
+ updateTransform();
3070
3279
  },
3071
3280
  rotateCW: () => {
3072
3281
  rotation = (rotation + 90) % 360;
3073
- pre.style.transform = `rotate(${rotation}deg)`;
3074
- pre.style.transformOrigin = "top left";
3282
+ updateTransform();
3075
3283
  },
3076
3284
  rotateCCW: () => {
3077
3285
  rotation = (rotation - 90 + 360) % 360;
3078
- pre.style.transform = `rotate(${rotation}deg)`;
3079
- pre.style.transformOrigin = "top left";
3286
+ updateTransform();
3080
3287
  },
3081
3288
  download: () => {
3082
3289
  const mimeType = ctx.metadata.mimeType || "text/plain";
@@ -3375,7 +3582,7 @@ var MarkdownPlugin = class {
3375
3582
  gfm: true,
3376
3583
  breaks: true
3377
3584
  });
3378
- const cleanHtml = DOMPurify2__default.default.sanitize(rawHtml, {
3585
+ const cleanHtml = DOMPurify6__default.default.sanitize(rawHtml, {
3379
3586
  USE_PROFILES: { html: true }
3380
3587
  });
3381
3588
  const wrapper = document.createElement("div");
@@ -4011,6 +4218,14 @@ var RtfPlugin = class {
4011
4218
  group: "actions",
4012
4219
  execute: () => instance.download?.()
4013
4220
  },
4221
+ {
4222
+ id: "copy",
4223
+ icon: "copy",
4224
+ label: "Copy Text",
4225
+ type: "button",
4226
+ group: "actions",
4227
+ execute: () => instance.copy?.()
4228
+ },
4014
4229
  {
4015
4230
  id: "print",
4016
4231
  icon: "print",
@@ -4041,20 +4256,27 @@ var RtfPlugin = class {
4041
4256
  let scale = 1;
4042
4257
  let rotation = 0;
4043
4258
  let pageElements = [];
4044
- const calculateFitScale = () => {
4259
+ let fitMode = "width";
4260
+ const calculateFitScale = (mode = fitMode) => {
4045
4261
  const activeEl = pageElements[currentPage - 1] || wrapper;
4046
4262
  const elW = activeEl.offsetWidth || 850;
4047
- const elH = activeEl.offsetHeight || 1e3;
4048
- const availW = Math.max(200, ctx.container.clientWidth - 48);
4049
- const availH = Math.max(200, ctx.container.clientHeight - 80);
4050
- return Math.min(1.1, Math.min(availW / elW, availH / elH));
4263
+ const singlePageH = Math.min(activeEl.offsetHeight || 1056, Math.round(elW * 1.32));
4264
+ const availW = Math.max(280, ctx.container.clientWidth - 48);
4265
+ const availH = Math.max(280, ctx.container.clientHeight - 80);
4266
+ const sW = availW / elW;
4267
+ const sH = availH / singlePageH;
4268
+ if (mode === "page") {
4269
+ return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
4270
+ }
4271
+ return Math.max(0.65, Math.min(1.05, sW));
4051
4272
  };
4052
4273
  const applyTransform = () => {
4053
4274
  wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
4054
4275
  wrapper.style.transformOrigin = "top center";
4055
4276
  };
4056
4277
  setTimeout(() => {
4057
- scale = calculateFitScale();
4278
+ fitMode = "width";
4279
+ scale = calculateFitScale("width");
4058
4280
  applyTransform();
4059
4281
  }, 60);
4060
4282
  try {
@@ -4072,14 +4294,31 @@ var RtfPlugin = class {
4072
4294
  } catch (err) {
4073
4295
  console.warn("[RtfPlugin] RTF render error, fallback text:", err);
4074
4296
  const text = new TextDecoder("latin1").decode(ctx.buffer);
4075
- const clean = text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "");
4076
- const pre = document.createElement("pre");
4077
- pre.style.whiteSpace = "pre-wrap";
4078
- pre.style.fontFamily = "serif";
4079
- pre.style.color = "#333";
4080
- pre.textContent = clean;
4081
- wrapper.appendChild(pre);
4082
- pageElements = [pre];
4297
+ const rawPages = text.split(/\\page\b/).map((segment) => {
4298
+ return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
4299
+ }).filter((p) => p.length > 0);
4300
+ const pages = rawPages.length > 0 ? rawPages : [text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim()];
4301
+ for (let i = 0; i < pages.length; i++) {
4302
+ const pageCard = document.createElement("div");
4303
+ pageCard.className = "fp-rtf-page-card";
4304
+ pageCard.style.backgroundColor = "#ffffff";
4305
+ pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
4306
+ pageCard.style.borderRadius = "4px";
4307
+ pageCard.style.padding = "72px 56px";
4308
+ pageCard.style.width = "816px";
4309
+ pageCard.style.minHeight = "1056px";
4310
+ pageCard.style.maxWidth = "100%";
4311
+ pageCard.style.boxSizing = "border-box";
4312
+ pageCard.style.fontFamily = "serif";
4313
+ pageCard.style.fontSize = "12pt";
4314
+ pageCard.style.lineHeight = "1.6";
4315
+ pageCard.style.color = "#1e293b";
4316
+ pageCard.style.whiteSpace = "pre-wrap";
4317
+ pageCard.style.display = i === 0 ? "block" : "none";
4318
+ pageCard.textContent = pages[i];
4319
+ wrapper.appendChild(pageCard);
4320
+ pageElements.push(pageCard);
4321
+ }
4083
4322
  }
4084
4323
  const totalPages = Math.max(1, pageElements.length);
4085
4324
  let currentPage = 1;
@@ -4146,7 +4385,8 @@ var RtfPlugin = class {
4146
4385
  applyTransform();
4147
4386
  },
4148
4387
  fitToPage: () => {
4149
- scale = calculateFitScale();
4388
+ fitMode = fitMode === "width" ? "page" : "width";
4389
+ scale = calculateFitScale(fitMode);
4150
4390
  rotation = 0;
4151
4391
  applyTransform();
4152
4392
  },
@@ -4167,6 +4407,10 @@ var RtfPlugin = class {
4167
4407
  a.click();
4168
4408
  URL.revokeObjectURL(url);
4169
4409
  },
4410
+ copy: () => {
4411
+ const text = wrapper.textContent || "";
4412
+ navigator.clipboard?.writeText(text);
4413
+ },
4170
4414
  print: () => {
4171
4415
  window.print();
4172
4416
  }
@@ -4241,7 +4485,7 @@ var HtmlPreviewPlugin = class {
4241
4485
  }
4242
4486
  async render(ctx) {
4243
4487
  const rawHtml = new TextDecoder("utf-8").decode(ctx.buffer);
4244
- const sanitized = DOMPurify2__default.default.sanitize(rawHtml, {
4488
+ const sanitized = DOMPurify6__default.default.sanitize(rawHtml, {
4245
4489
  WHOLE_DOCUMENT: true,
4246
4490
  ADD_TAGS: ["style", "link"],
4247
4491
  ADD_ATTR: ["target", "rel"]
@@ -4461,19 +4705,29 @@ var OpenDocumentPlugin = class {
4461
4705
  ctx.container.appendChild(container);
4462
4706
  let scale = 1;
4463
4707
  let rotation = 0;
4464
- const calculateFitScale = () => {
4708
+ let fitMode = "width";
4709
+ const calculateFitScale = (mode = fitMode) => {
4465
4710
  const elW = wrapper.offsetWidth || 850;
4466
- const elH = wrapper.offsetHeight || (isPresentation ? 540 : 1e3);
4467
- const availW = Math.max(200, ctx.container.clientWidth - 48);
4468
- const availH = Math.max(200, ctx.container.clientHeight - 80);
4469
- return Math.min(1, Math.min(availW / elW, availH / elH));
4711
+ const singlePageH = Math.min(wrapper.offsetHeight || 1056, Math.round(elW * 1.32));
4712
+ const availW = Math.max(280, ctx.container.clientWidth - 48);
4713
+ const availH = Math.max(280, ctx.container.clientHeight - 80);
4714
+ const sW = availW / elW;
4715
+ const sH = availH / (isPresentation ? 540 : singlePageH);
4716
+ if (isPresentation) {
4717
+ return Math.min(1, Math.min(sW, sH));
4718
+ }
4719
+ if (mode === "page") {
4720
+ return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
4721
+ }
4722
+ return Math.max(0.65, Math.min(1.05, sW));
4470
4723
  };
4471
4724
  const applyTransform = () => {
4472
4725
  wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
4473
4726
  wrapper.style.transformOrigin = "top center";
4474
4727
  };
4475
4728
  setTimeout(() => {
4476
- scale = calculateFitScale();
4729
+ fitMode = "width";
4730
+ scale = calculateFitScale("width");
4477
4731
  applyTransform();
4478
4732
  }, 60);
4479
4733
  let currentPage = 1;
@@ -4507,14 +4761,97 @@ var OpenDocumentPlugin = class {
4507
4761
  wrapper.textContent = contentDoc.documentElement.textContent || "Formula content";
4508
4762
  }
4509
4763
  } else {
4510
- wrapper.style.maxWidth = "850px";
4511
- wrapper.style.padding = "48px";
4764
+ wrapper.style.maxWidth = "none";
4765
+ wrapper.style.padding = "0";
4512
4766
  wrapper.style.minHeight = "100%";
4767
+ wrapper.style.backgroundColor = "transparent";
4768
+ wrapper.style.boxShadow = "none";
4769
+ wrapper.style.position = "relative";
4770
+ const dims = this.getPageDimensions(stylesDoc, contentDoc);
4513
4771
  const bodyHtml = this.renderOdfBody(contentDoc, styleMap, imageUrls);
4514
- wrapper.innerHTML = DOMPurify2__default.default.sanitize(bodyHtml, {
4515
- ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub"],
4772
+ const tempDiv = document.createElement("div");
4773
+ tempDiv.style.width = `${dims.width - dims.marginLeft - dims.marginRight}px`;
4774
+ tempDiv.style.position = "absolute";
4775
+ tempDiv.style.visibility = "hidden";
4776
+ tempDiv.innerHTML = DOMPurify6__default.default.sanitize(bodyHtml, {
4777
+ ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub", "hr"],
4516
4778
  ADD_ATTR: ["style", "colspan", "rowspan"]
4517
4779
  });
4780
+ document.body.appendChild(tempDiv);
4781
+ const contentHeight = dims.height - dims.marginTop - dims.marginBottom;
4782
+ const pageElements = [[]];
4783
+ let currentHeight = 0;
4784
+ let currentPageIdx = 0;
4785
+ Array.from(tempDiv.children).forEach((child) => {
4786
+ const el = child;
4787
+ const style = el.getAttribute("style") || "";
4788
+ const isBreakBefore = style.includes("page-break-before: always");
4789
+ const isBreakAfter = style.includes("page-break-after: always");
4790
+ const isSoftBreak = el.classList.contains("odf-page-break");
4791
+ if (isBreakBefore) {
4792
+ if (pageElements[currentPageIdx].length > 0) {
4793
+ currentPageIdx++;
4794
+ pageElements.push([]);
4795
+ currentHeight = 0;
4796
+ }
4797
+ }
4798
+ const h = el.offsetHeight || 0;
4799
+ if (currentHeight + h > contentHeight && pageElements[currentPageIdx].length > 0 && !isSoftBreak) {
4800
+ currentPageIdx++;
4801
+ pageElements.push([]);
4802
+ currentHeight = 0;
4803
+ }
4804
+ if (!isSoftBreak) {
4805
+ pageElements[currentPageIdx].push(el.cloneNode(true));
4806
+ currentHeight += h;
4807
+ }
4808
+ if (isBreakAfter || isSoftBreak) {
4809
+ currentPageIdx++;
4810
+ pageElements.push([]);
4811
+ currentHeight = 0;
4812
+ }
4813
+ });
4814
+ document.body.removeChild(tempDiv);
4815
+ if (pageElements.length > 1 && pageElements[pageElements.length - 1].length === 0) {
4816
+ pageElements.pop();
4817
+ }
4818
+ totalPages = Math.max(1, pageElements.length);
4819
+ pageElements.forEach((elements, idx) => {
4820
+ const page = document.createElement("div");
4821
+ page.className = `fp-odt-page fp-odt-page-${idx + 1}`;
4822
+ page.style.width = `${dims.width}px`;
4823
+ page.style.minHeight = `${dims.height}px`;
4824
+ page.style.padding = `${dims.marginTop}px ${dims.marginRight}px ${dims.marginBottom}px ${dims.marginLeft}px`;
4825
+ page.style.margin = "0 auto";
4826
+ page.style.backgroundColor = "#ffffff";
4827
+ page.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
4828
+ page.style.borderRadius = "4px";
4829
+ page.style.boxSizing = "border-box";
4830
+ page.style.display = idx === 0 ? "block" : "none";
4831
+ page.style.position = "absolute";
4832
+ page.style.top = "0";
4833
+ page.style.left = "50%";
4834
+ page.style.transform = "translateX(-50%)";
4835
+ elements.forEach((el) => page.appendChild(el));
4836
+ wrapper.appendChild(page);
4837
+ slides.push(page);
4838
+ });
4839
+ const pageIndicator = document.createElement("div");
4840
+ pageIndicator.className = "fp-odt-page-indicator";
4841
+ pageIndicator.style.position = "sticky";
4842
+ pageIndicator.style.bottom = "16px";
4843
+ pageIndicator.style.left = "50%";
4844
+ pageIndicator.style.transform = "translateX(-50%)";
4845
+ pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
4846
+ pageIndicator.style.color = "#fff";
4847
+ pageIndicator.style.padding = "6px 12px";
4848
+ pageIndicator.style.borderRadius = "16px";
4849
+ pageIndicator.style.fontSize = "12px";
4850
+ pageIndicator.style.zIndex = "100";
4851
+ pageIndicator.style.display = "inline-block";
4852
+ pageIndicator.style.width = "fit-content";
4853
+ pageIndicator.textContent = `Page 1 of ${totalPages}`;
4854
+ container.appendChild(pageIndicator);
4518
4855
  }
4519
4856
  const cleanup = () => {
4520
4857
  imageUrls.forEach((url) => URL.revokeObjectURL(url));
@@ -4523,11 +4860,15 @@ var OpenDocumentPlugin = class {
4523
4860
  };
4524
4861
  ctx.signal.addEventListener("abort", cleanup);
4525
4862
  const goToPage = (page) => {
4526
- if (!isPresentation || page < 1 || page > totalPages) return;
4863
+ if (page < 1 || page > totalPages) return;
4527
4864
  currentPage = page;
4528
4865
  slides.forEach((s, idx) => {
4529
4866
  s.style.display = idx === page - 1 ? "block" : "none";
4530
4867
  });
4868
+ const indicator = container.querySelector(".fp-odt-page-indicator");
4869
+ if (indicator) {
4870
+ indicator.textContent = `Page ${currentPage} of ${totalPages}`;
4871
+ }
4531
4872
  ctx.emit("page-change", { page: currentPage, total: totalPages });
4532
4873
  };
4533
4874
  return {
@@ -4547,7 +4888,8 @@ var OpenDocumentPlugin = class {
4547
4888
  applyTransform();
4548
4889
  },
4549
4890
  fitToPage: () => {
4550
- scale = calculateFitScale();
4891
+ fitMode = fitMode === "width" ? "page" : "width";
4892
+ scale = calculateFitScale(fitMode);
4551
4893
  rotation = 0;
4552
4894
  applyTransform();
4553
4895
  },
@@ -4596,6 +4938,43 @@ var OpenDocumentPlugin = class {
4596
4938
  }
4597
4939
  };
4598
4940
  }
4941
+ getPageDimensions(stylesDoc, contentDoc) {
4942
+ let width = 850;
4943
+ let height = 1123;
4944
+ let marginTop = 48;
4945
+ let marginBottom = 48;
4946
+ let marginLeft = 48;
4947
+ let marginRight = 48;
4948
+ const parseUnit = (val) => {
4949
+ if (!val) return null;
4950
+ if (val.endsWith("cm")) return parseFloat(val) * 37.8;
4951
+ if (val.endsWith("mm")) return parseFloat(val) * 3.78;
4952
+ if (val.endsWith("in")) return parseFloat(val) * 96;
4953
+ if (val.endsWith("pt")) return parseFloat(val) * 1.33;
4954
+ if (val.endsWith("px")) return parseFloat(val);
4955
+ return parseFloat(val);
4956
+ };
4957
+ const docs = [stylesDoc, contentDoc].filter(Boolean);
4958
+ for (const doc of docs) {
4959
+ const pageLayout = doc.querySelector("page-layout-properties, [page-width]");
4960
+ if (pageLayout) {
4961
+ const w = parseUnit(pageLayout.getAttribute("fo:page-width") || pageLayout.getAttribute("page-width"));
4962
+ const h = parseUnit(pageLayout.getAttribute("fo:page-height") || pageLayout.getAttribute("page-height"));
4963
+ const mt = parseUnit(pageLayout.getAttribute("fo:margin-top") || pageLayout.getAttribute("margin-top"));
4964
+ const mb = parseUnit(pageLayout.getAttribute("fo:margin-bottom") || pageLayout.getAttribute("margin-bottom"));
4965
+ const ml = parseUnit(pageLayout.getAttribute("fo:margin-left") || pageLayout.getAttribute("margin-left"));
4966
+ const mr = parseUnit(pageLayout.getAttribute("fo:margin-right") || pageLayout.getAttribute("margin-right"));
4967
+ if (w !== null) width = w;
4968
+ if (h !== null) height = h;
4969
+ if (mt !== null) marginTop = mt;
4970
+ if (mb !== null) marginBottom = mb;
4971
+ if (ml !== null) marginLeft = ml;
4972
+ if (mr !== null) marginRight = mr;
4973
+ break;
4974
+ }
4975
+ }
4976
+ return { width, height, marginTop, marginBottom, marginLeft, marginRight };
4977
+ }
4599
4978
  extractStyles(stylesDoc, contentDoc) {
4600
4979
  const map = /* @__PURE__ */ new Map();
4601
4980
  const styleNodes = [];
@@ -4618,14 +4997,21 @@ var OpenDocumentPlugin = class {
4618
4997
  if (color) css += `color: ${color}; `;
4619
4998
  if (size) css += `font-size: ${size}; `;
4620
4999
  }
4621
- const paraProp = node.querySelector("paragraph-properties, [text-align]");
5000
+ let paraProp = node.querySelector("paragraph-properties, [text-align]");
5001
+ if (!paraProp) {
5002
+ paraProp = Array.from(node.children).find((c) => c.tagName.includes("paragraph-properties")) || null;
5003
+ }
4622
5004
  if (paraProp) {
4623
5005
  const align = paraProp.getAttribute("fo:text-align") || paraProp.getAttribute("text-align");
4624
5006
  const mt = paraProp.getAttribute("fo:margin-top") || paraProp.getAttribute("margin-top");
4625
5007
  const mb = paraProp.getAttribute("fo:margin-bottom") || paraProp.getAttribute("margin-bottom");
5008
+ const breakBefore = paraProp.getAttribute("fo:break-before") || paraProp.getAttribute("break-before");
5009
+ const breakAfter = paraProp.getAttribute("fo:break-after") || paraProp.getAttribute("break-after");
4626
5010
  if (align) css += `text-align: ${align}; `;
4627
5011
  if (mt) css += `margin-top: ${mt}; `;
4628
5012
  if (mb) css += `margin-bottom: ${mb}; `;
5013
+ if (breakBefore === "page") css += "page-break-before: always; ";
5014
+ if (breakAfter === "page") css += "page-break-after: always; ";
4629
5015
  }
4630
5016
  if (css) map.set(name, css);
4631
5017
  }
@@ -4710,6 +5096,8 @@ var OpenDocumentPlugin = class {
4710
5096
  result += "&emsp;";
4711
5097
  } else if (tag === "line-break") {
4712
5098
  result += "<br/>";
5099
+ } else if (tag === "soft-page-break") {
5100
+ result += '<hr class="odf-page-break" style="page-break-after: always; border: none; margin: 0; padding: 0; height: 0;" />';
4713
5101
  } else {
4714
5102
  result += el.textContent || "";
4715
5103
  }
@@ -4870,20 +5258,9 @@ var DocPlugin = class {
4870
5258
  container.style.overflow = "auto";
4871
5259
  container.style.padding = "32px 16px";
4872
5260
  container.style.backgroundColor = "#f1f5f9";
4873
- const wrapper = document.createElement("div");
4874
- wrapper.className = "fp-doc-wrapper";
4875
- wrapper.style.maxWidth = "850px";
4876
- wrapper.style.margin = "0 auto";
4877
- wrapper.style.backgroundColor = "#ffffff";
4878
- wrapper.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
4879
- wrapper.style.borderRadius = "4px";
4880
- wrapper.style.padding = "56px 48px";
4881
- wrapper.style.minHeight = "100%";
4882
- wrapper.style.transformOrigin = "top center";
4883
- wrapper.style.transition = "transform 0.2s ease";
4884
- wrapper.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
4885
- wrapper.style.color = "#1e293b";
4886
- container.appendChild(wrapper);
5261
+ container.style.display = "flex";
5262
+ container.style.justifyContent = "center";
5263
+ container.style.alignItems = "flex-start";
4887
5264
  ctx.container.appendChild(container);
4888
5265
  let scale = 1;
4889
5266
  let extractedRawText = "";
@@ -4910,21 +5287,27 @@ var DocPlugin = class {
4910
5287
  const rawPages = this.splitIntoPages(extractedRawText);
4911
5288
  const totalPages = Math.max(1, rawPages.length);
4912
5289
  let currentPage = 1;
4913
- wrapper.innerHTML = "";
4914
5290
  const pageCards = [];
4915
5291
  for (let i = 0; i < totalPages; i++) {
4916
5292
  const pageCard = document.createElement("div");
4917
5293
  pageCard.className = "fp-doc-page-card";
5294
+ pageCard.style.width = "816px";
5295
+ pageCard.style.height = "1056px";
4918
5296
  pageCard.style.backgroundColor = "#ffffff";
4919
5297
  pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
4920
5298
  pageCard.style.borderRadius = "4px";
4921
- pageCard.style.padding = "56px 48px";
4922
- pageCard.style.minHeight = "100%";
5299
+ pageCard.style.padding = "96px 72px";
5300
+ pageCard.style.boxSizing = "border-box";
5301
+ pageCard.style.overflow = "hidden";
4923
5302
  pageCard.style.display = i === 0 ? "block" : "none";
5303
+ pageCard.style.transformOrigin = "top center";
5304
+ pageCard.style.transition = "transform 0.2s ease";
5305
+ pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5306
+ pageCard.style.color = "#1e293b";
4924
5307
  if (isFallback && i === 0) {
4925
5308
  pageCard.innerHTML = `
4926
5309
  <div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
4927
- <h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify2__default.default.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
5310
+ <h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify6__default.default.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
4928
5311
  <span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
4929
5312
  </div>
4930
5313
  ${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
@@ -4932,15 +5315,17 @@ var DocPlugin = class {
4932
5315
  } else {
4933
5316
  pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
4934
5317
  }
4935
- wrapper.appendChild(pageCard);
5318
+ container.appendChild(pageCard);
4936
5319
  pageCards.push(pageCard);
4937
5320
  }
4938
5321
  let indicator = null;
4939
5322
  if (totalPages > 1) {
4940
5323
  indicator = document.createElement("div");
4941
5324
  indicator.className = "fp-doc-page-indicator";
4942
- indicator.style.position = "sticky";
5325
+ indicator.style.position = "fixed";
4943
5326
  indicator.style.bottom = "16px";
5327
+ indicator.style.left = "50%";
5328
+ indicator.style.transform = "translateX(-50%)";
4944
5329
  indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
4945
5330
  indicator.style.backdropFilter = "blur(8px)";
4946
5331
  indicator.style.color = "#f8fafc";
@@ -4954,17 +5339,25 @@ var DocPlugin = class {
4954
5339
  indicator.style.userSelect = "none";
4955
5340
  indicator.style.pointerEvents = "none";
4956
5341
  indicator.style.textAlign = "center";
4957
- indicator.style.width = "fit-content";
4958
- indicator.style.margin = "16px auto 0";
4959
5342
  container.appendChild(indicator);
4960
5343
  }
5344
+ let rotation = 0;
5345
+ const applyTransform = () => {
5346
+ const activeCard = pageCards[currentPage - 1];
5347
+ if (activeCard) {
5348
+ activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5349
+ }
5350
+ };
4961
5351
  const showPage = (pageNum) => {
4962
5352
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
4963
- if (totalPages > 1) {
4964
- pageCards.forEach((card, idx) => {
4965
- card.style.display = idx + 1 === currentPage ? "block" : "none";
4966
- });
4967
- }
5353
+ pageCards.forEach((card, idx) => {
5354
+ if (idx + 1 === currentPage) {
5355
+ card.style.display = "block";
5356
+ card.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5357
+ } else {
5358
+ card.style.display = "none";
5359
+ }
5360
+ });
4968
5361
  if (indicator) {
4969
5362
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
4970
5363
  }
@@ -4973,21 +5366,22 @@ var DocPlugin = class {
4973
5366
  if (totalPages > 1) {
4974
5367
  showPage(1);
4975
5368
  }
4976
- let rotation = 0;
4977
- const calculateFitScale = () => {
4978
- const activeCard = pageCards[currentPage - 1] || wrapper;
4979
- const elW = activeCard.offsetWidth || 850;
4980
- const elH = activeCard.offsetHeight || 1e3;
4981
- const availW = Math.max(200, ctx.container.clientWidth - 48);
4982
- const availH = Math.max(200, ctx.container.clientHeight - 80);
4983
- return Math.min(1.1, Math.min(availW / elW, availH / elH));
4984
- };
4985
- const applyTransform = () => {
4986
- wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
4987
- wrapper.style.transformOrigin = "top center";
5369
+ let fitMode = "width";
5370
+ const calculateFitScale = (mode = fitMode) => {
5371
+ const elW = 816;
5372
+ const elH = 1056;
5373
+ const availW = Math.max(280, ctx.container.clientWidth - 48);
5374
+ const availH = Math.max(280, ctx.container.clientHeight - 80);
5375
+ const sW = availW / elW;
5376
+ const sH = availH / elH;
5377
+ if (mode === "page") {
5378
+ return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
5379
+ }
5380
+ return Math.max(0.65, Math.min(1.05, sW));
4988
5381
  };
4989
5382
  setTimeout(() => {
4990
- scale = calculateFitScale();
5383
+ fitMode = "width";
5384
+ scale = calculateFitScale("width");
4991
5385
  applyTransform();
4992
5386
  }, 60);
4993
5387
  const cleanup = () => {
@@ -5015,7 +5409,8 @@ var DocPlugin = class {
5015
5409
  applyTransform();
5016
5410
  },
5017
5411
  fitToPage: () => {
5018
- scale = calculateFitScale();
5412
+ fitMode = fitMode === "width" ? "page" : "width";
5413
+ scale = calculateFitScale(fitMode);
5019
5414
  rotation = 0;
5020
5415
  applyTransform();
5021
5416
  },
@@ -5143,8 +5538,28 @@ var DocPlugin = class {
5143
5538
  }
5144
5539
  splitIntoPages(text) {
5145
5540
  if (!text) return [""];
5146
- const parts = 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);
5147
- return parts.length > 0 ? parts : [text];
5541
+ 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);
5542
+ if (explicitParts.length === 0) explicitParts.push(text);
5543
+ const maxLinesPerPage = 48;
5544
+ const finalPages = [];
5545
+ for (const part of explicitParts) {
5546
+ const lines = part.split(/\r?\n/);
5547
+ let currentLines = [];
5548
+ let count = 0;
5549
+ for (const line of lines) {
5550
+ currentLines.push(line);
5551
+ count++;
5552
+ if (count >= maxLinesPerPage) {
5553
+ finalPages.push(currentLines.join("\n"));
5554
+ currentLines = [];
5555
+ count = 0;
5556
+ }
5557
+ }
5558
+ if (currentLines.length > 0) {
5559
+ finalPages.push(currentLines.join("\n"));
5560
+ }
5561
+ }
5562
+ return finalPages.length > 0 ? finalPages : [text];
5148
5563
  }
5149
5564
  /**
5150
5565
  * Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
@@ -5153,17 +5568,65 @@ var DocPlugin = class {
5153
5568
  const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
5154
5569
  let html = "";
5155
5570
  let inList = false;
5156
- for (const rawLine of lines) {
5157
- const line = rawLine.trim();
5571
+ let tableLines = [];
5572
+ const flushTable = () => {
5573
+ if (tableLines.length > 0) {
5574
+ html += '<table style="width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 12px;">';
5575
+ for (const tLine of tableLines) {
5576
+ html += "<tr>";
5577
+ const cols = tLine.split(" ");
5578
+ for (const col of cols) {
5579
+ html += `<td style="border: 1px solid #cbd5e1; padding: 6px 8px;">${DOMPurify6__default.default.sanitize(col.trim())}</td>`;
5580
+ }
5581
+ html += "</tr>";
5582
+ }
5583
+ html += "</table>";
5584
+ tableLines = [];
5585
+ }
5586
+ };
5587
+ let i = 0;
5588
+ while (i < lines.length) {
5589
+ let line = lines[i];
5590
+ let tabCount = (line.match(/\t/g) || []).length;
5591
+ if (tabCount > 0) {
5592
+ let consecutiveTableLines = 1;
5593
+ let j = i + 1;
5594
+ while (j < lines.length) {
5595
+ const nextTabCount = (lines[j].match(/\t/g) || []).length;
5596
+ if (nextTabCount === tabCount) {
5597
+ consecutiveTableLines++;
5598
+ j++;
5599
+ } else {
5600
+ break;
5601
+ }
5602
+ }
5603
+ if (consecutiveTableLines >= 3) {
5604
+ if (inList) {
5605
+ html += "</ul>";
5606
+ inList = false;
5607
+ }
5608
+ tableLines = lines.slice(i, j);
5609
+ flushTable();
5610
+ i = j;
5611
+ continue;
5612
+ }
5613
+ }
5614
+ line = line.trim();
5158
5615
  if (!line) {
5159
5616
  if (inList) {
5160
5617
  html += "</ul>";
5161
5618
  inList = false;
5162
5619
  }
5620
+ html += '<div style="height: 1.15em;"></div>';
5621
+ i++;
5622
+ continue;
5623
+ }
5624
+ if (/^[\x00-\x1F\x7F-\x9F]+$/.test(line)) {
5625
+ i++;
5163
5626
  continue;
5164
5627
  }
5165
- if (/^[\x00-\x1F\x7F-\x9F]+$/.test(line)) continue;
5166
- if (line.includes("Normal.dot") || line.includes("Microsoft Word") || line.includes("Times New Roman") && line.length < 30) {
5628
+ if ((line.includes("Normal.dot") || line.includes("Microsoft Word") || line.includes("Times New Roman")) && line.length < 30) {
5629
+ i++;
5167
5630
  continue;
5168
5631
  }
5169
5632
  if (line.length < 60 && !line.endsWith(".") && (/^[A-Z0-9\s:_-]+$/.test(line) || line.startsWith("#"))) {
@@ -5171,24 +5634,26 @@ var DocPlugin = class {
5171
5634
  html += "</ul>";
5172
5635
  inList = false;
5173
5636
  }
5174
- html += `<h2 style="font-size: 18px; font-weight: 700; color: #1e3a8a; margin: 20px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify2__default.default.sanitize(line)}</h2>`;
5637
+ html += `<h2 style="font-size: 16px; font-weight: 700; color: #1e3a8a; margin: 16px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify6__default.default.sanitize(line)}</h2>`;
5175
5638
  } else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
5176
5639
  if (!inList) {
5177
5640
  html += '<ul style="margin: 8px 0; padding-left: 24px;">';
5178
5641
  inList = true;
5179
5642
  }
5180
5643
  const bulletText = line.replace(/^[•\-\*]\s*/, "");
5181
- html += `<li style="margin: 4px 0; line-height: 1.6;">${DOMPurify2__default.default.sanitize(bulletText)}</li>`;
5644
+ html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6__default.default.sanitize(bulletText)}</li>`;
5182
5645
  } else {
5183
5646
  if (inList) {
5184
5647
  html += "</ul>";
5185
5648
  inList = false;
5186
5649
  }
5187
- html += `<p style="line-height: 1.7; margin: 10px 0; font-size: 14px; text-align: justify;">${DOMPurify2__default.default.sanitize(line)}</p>`;
5650
+ html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6__default.default.sanitize(line)}</p>`;
5188
5651
  }
5652
+ i++;
5189
5653
  }
5190
5654
  if (inList) html += "</ul>";
5191
- return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify2__default.default.sanitize(filename)})</p>`;
5655
+ flushTable();
5656
+ return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify6__default.default.sanitize(filename)})</p>`;
5192
5657
  }
5193
5658
  };
5194
5659
  function docPlugin() {
@@ -5366,7 +5831,7 @@ var PptPlugin = class {
5366
5831
  if (s.pictureUrl) {
5367
5832
  contentHtml = `
5368
5833
  <div style="flex: 1; display: flex; justify-content: center; align-items: center; padding: 12px; overflow: hidden;">
5369
- <img src="${s.pictureUrl}" alt="${DOMPurify2__default.default.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;" />
5834
+ <img src="${s.pictureUrl}" alt="${DOMPurify6__default.default.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;" />
5370
5835
  </div>
5371
5836
  `;
5372
5837
  } else if (s.tableColumns.length > 0) {
@@ -5376,7 +5841,7 @@ var PptPlugin = class {
5376
5841
  <table style="width: 100%; border-collapse: collapse; border: 1px solid #cbd5e1; border-radius: 6px; overflow: hidden; background: #ffffff;">
5377
5842
  <thead>
5378
5843
  <tr style="background: #e2e8f0; color: #1e293b; font-weight: 600; font-size: 14px;">
5379
- ${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify2__default.default.sanitize(c)}</th>`).join("")}
5844
+ ${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify6__default.default.sanitize(c)}</th>`).join("")}
5380
5845
  </tr>
5381
5846
  </thead>
5382
5847
  <tbody>
@@ -5392,7 +5857,7 @@ var PptPlugin = class {
5392
5857
  } else {
5393
5858
  const pTags = s.paragraphs.map((p) => {
5394
5859
  const lines = p.split(/[\r\n]+/).map((l) => l.trim()).filter(Boolean);
5395
- return lines.map((l) => `<p style="margin: 0 0 14px; font-size: 14px; line-height: 1.65; color: #334155; text-align: justify;">${DOMPurify2__default.default.sanitize(l)}</p>`).join("");
5860
+ return lines.map((l) => `<p style="margin: 0 0 14px; font-size: 14px; line-height: 1.65; color: #334155; text-align: justify;">${DOMPurify6__default.default.sanitize(l)}</p>`).join("");
5396
5861
  }).join("");
5397
5862
  contentHtml = `
5398
5863
  <div style="flex: 1; overflow: auto; padding: 4px 8px; display: flex; flex-direction: column; justify-content: flex-start;">
@@ -5405,11 +5870,11 @@ var PptPlugin = class {
5405
5870
  <!-- Header Banner matching PowerPoint design -->
5406
5871
  <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;">
5407
5872
  <h1 style="margin: 0; font-size: 26px; font-weight: 700; color: #1e293b; letter-spacing: -0.3px;">
5408
- ${DOMPurify2__default.default.sanitize(s.title)}
5873
+ ${DOMPurify6__default.default.sanitize(s.title)}
5409
5874
  </h1>
5410
5875
  ${s.subtitle ? `
5411
5876
  <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);">
5412
- ${DOMPurify2__default.default.sanitize(s.subtitle)}
5877
+ ${DOMPurify6__default.default.sanitize(s.subtitle)}
5413
5878
  </span>
5414
5879
  ` : `
5415
5880
  <span style="font-size: 12px; color: #365314; font-weight: 600;">