@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 CHANGED
@@ -4,7 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var core = require('@angular/core');
6
6
  var common = require('@angular/common');
7
- var DOMPurify2 = require('dompurify');
7
+ var DOMPurify6 = require('dompurify');
8
8
  var pdfjsLib = require('pdfjs-dist');
9
9
  var docx = require('docx-preview');
10
10
  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);
@@ -437,7 +437,7 @@ async function sourceToArrayBuffer(source, signal) {
437
437
  if (magicMime === "application/zip") {
438
438
  const ooxmlMime = detectOoxmlType(buffer);
439
439
  if (ooxmlMime && ooxmlMime !== "application/zip") {
440
- metadata.mimeType = ooxmlMime;
440
+ metadata.mimeType = metadata.mimeType ?? ooxmlMime;
441
441
  if (ooxmlMime.includes("wordprocessing")) metadata.extension = metadata.extension ?? ".docx";
442
442
  else if (ooxmlMime.includes("spreadsheet")) metadata.extension = metadata.extension ?? ".xlsx";
443
443
  else if (ooxmlMime.includes("presentation")) metadata.extension = metadata.extension ?? ".pptx";
@@ -466,7 +466,7 @@ async function sourceToArrayBuffer(source, signal) {
466
466
  return { buffer, metadata };
467
467
  }
468
468
  function sanitizeSVG(svg) {
469
- return DOMPurify2__default.default.sanitize(svg, {
469
+ return DOMPurify6__default.default.sanitize(svg, {
470
470
  USE_PROFILES: { svg: true, svgFilters: true }
471
471
  });
472
472
  }
@@ -513,7 +513,8 @@ function createElement(tag, attrs, ...children) {
513
513
  }
514
514
  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>`;
515
515
  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>`;
516
- 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>`;
516
+ 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>`;
517
+ 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>`;
517
518
  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>`;
518
519
  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>`;
519
520
  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>`;
@@ -533,6 +534,7 @@ var ICON_MAP = {
533
534
  "zoom-in": ICON_ZOOM_IN,
534
535
  "zoom-out": ICON_ZOOM_OUT,
535
536
  "fit-page": ICON_FIT_PAGE,
537
+ "fit-width": ICON_FIT_WIDTH,
536
538
  "fit-slide": ICON_FIT_PAGE,
537
539
  "rotate-cw": ICON_ROTATE_CW,
538
540
  "rotate-ccw": ICON_ROTATE_CCW,
@@ -1479,6 +1481,7 @@ var PdfPlugin = class {
1479
1481
  let currentPage = 1;
1480
1482
  let zoomScale = 1;
1481
1483
  let rotation = 0;
1484
+ let fitMode = "width";
1482
1485
  let currentRenderTask = null;
1483
1486
  const renderPage = async (pageNum) => {
1484
1487
  if (currentRenderTask) {
@@ -1498,11 +1501,16 @@ var PdfPlugin = class {
1498
1501
  const containerWidth = container.clientWidth || 900;
1499
1502
  const containerHeight = container.clientHeight || 700;
1500
1503
  const unscaledVp = page.getViewport({ scale: 1, rotation });
1501
- const availWidth = Math.max(100, containerWidth - 48);
1502
- const availHeight = Math.max(100, containerHeight - 88);
1504
+ const availWidth = Math.max(280, containerWidth - 48);
1505
+ const availHeight = Math.max(280, containerHeight - 88);
1503
1506
  const scaleW = availWidth / unscaledVp.width;
1504
1507
  const scaleH = availHeight / unscaledVp.height;
1505
- const fitScale = Math.min(scaleW, scaleH);
1508
+ let fitScale;
1509
+ if (fitMode === "page") {
1510
+ fitScale = Math.max(0.5, Math.min(scaleW, scaleH));
1511
+ } else {
1512
+ fitScale = Math.max(0.65, Math.min(1.15, scaleW));
1513
+ }
1506
1514
  const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
1507
1515
  const pixelRatio = window.devicePixelRatio || 1;
1508
1516
  const viewport = page.getViewport({ scale: effectiveScale, rotation });
@@ -1528,7 +1536,19 @@ var PdfPlugin = class {
1528
1536
  }
1529
1537
  };
1530
1538
  await renderPage(1);
1539
+ let resizeTimer = null;
1540
+ const resizeObserver = new ResizeObserver(() => {
1541
+ if (resizeTimer) clearTimeout(resizeTimer);
1542
+ resizeTimer = setTimeout(() => {
1543
+ if (Math.abs(zoomScale - 1) < 0.05) {
1544
+ renderPage(currentPage);
1545
+ }
1546
+ }, 150);
1547
+ });
1548
+ resizeObserver.observe(container);
1531
1549
  const cleanup = () => {
1550
+ resizeObserver.disconnect();
1551
+ if (resizeTimer) clearTimeout(resizeTimer);
1532
1552
  if (currentRenderTask) {
1533
1553
  try {
1534
1554
  currentRenderTask.cancel();
@@ -1559,6 +1579,7 @@ var PdfPlugin = class {
1559
1579
  renderPage(currentPage);
1560
1580
  },
1561
1581
  fitToPage: () => {
1582
+ fitMode = fitMode === "width" ? "page" : "width";
1562
1583
  zoomScale = 1;
1563
1584
  rotation = 0;
1564
1585
  renderPage(currentPage);
@@ -2112,8 +2133,53 @@ var DocxPlugin = class {
2112
2133
  }
2113
2134
  }
2114
2135
  }
2115
- const sections = wrapper.querySelectorAll("section.docx");
2116
- const cards = wrapper.querySelectorAll(".fp-docx-page-card");
2136
+ let sections = Array.from(wrapper.querySelectorAll("section.docx"));
2137
+ const cards = Array.from(wrapper.querySelectorAll(".fp-docx-page-card"));
2138
+ if (sections.length === 1 && cards.length === 0) {
2139
+ const singleSec = sections[0];
2140
+ const pageH = 1056;
2141
+ const secH = singleSec.offsetHeight || singleSec.scrollHeight;
2142
+ if (secH > pageH * 1.25) {
2143
+ const children = Array.from(singleSec.children);
2144
+ if (children.length > 1) {
2145
+ const parent = singleSec.parentElement || wrapper;
2146
+ const newSections = [singleSec];
2147
+ singleSec.innerHTML = "";
2148
+ singleSec.style.minHeight = `${pageH}px`;
2149
+ singleSec.style.maxHeight = `${pageH}px`;
2150
+ singleSec.style.overflow = "hidden";
2151
+ singleSec.style.boxSizing = "border-box";
2152
+ let curSec = singleSec;
2153
+ let curH = 0;
2154
+ const maxH = pageH - 96;
2155
+ for (let i = 0; i < children.length; i++) {
2156
+ const child = children[i];
2157
+ curSec.appendChild(child);
2158
+ const chH = child.offsetHeight || 28;
2159
+ curH += chH;
2160
+ if (curH >= maxH && i < children.length - 1) {
2161
+ const nextSec = document.createElement("section");
2162
+ nextSec.className = singleSec.className;
2163
+ nextSec.style.cssText = singleSec.style.cssText;
2164
+ nextSec.style.width = singleSec.style.width || "816px";
2165
+ nextSec.style.minHeight = `${pageH}px`;
2166
+ nextSec.style.maxHeight = `${pageH}px`;
2167
+ nextSec.style.overflow = "hidden";
2168
+ nextSec.style.boxSizing = "border-box";
2169
+ nextSec.style.backgroundColor = "#ffffff";
2170
+ nextSec.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
2171
+ nextSec.style.borderRadius = "4px";
2172
+ nextSec.style.marginBottom = "24px";
2173
+ parent.appendChild(nextSec);
2174
+ newSections.push(nextSec);
2175
+ curSec = nextSec;
2176
+ curH = 0;
2177
+ }
2178
+ }
2179
+ sections = newSections;
2180
+ }
2181
+ }
2182
+ }
2117
2183
  const pageElements = sections.length > 0 ? sections : cards;
2118
2184
  const totalPages = Math.max(1, pageElements.length);
2119
2185
  let currentPage = 1;
@@ -2157,22 +2223,27 @@ var DocxPlugin = class {
2157
2223
  }
2158
2224
  scale = 1;
2159
2225
  let rotation = 0;
2160
- const calculateFitScale = () => {
2226
+ let fitMode = "width";
2227
+ const calculateFitScale = (mode = fitMode) => {
2161
2228
  const activeEl = pageElements[currentPage - 1] || wrapper.firstElementChild || wrapper;
2162
2229
  const elW = activeEl.offsetWidth || 816;
2163
- const elH = activeEl.offsetHeight || 1056;
2164
- const availW = Math.max(200, ctx.container.clientWidth - 48);
2165
- const availH = Math.max(200, ctx.container.clientHeight - 80);
2230
+ const singlePageH = Math.min(activeEl.offsetHeight || 1056, Math.round(elW * 1.32));
2231
+ const availW = Math.max(280, ctx.container.clientWidth - 48);
2232
+ const availH = Math.max(280, ctx.container.clientHeight - 80);
2166
2233
  const sW = availW / elW;
2167
- const sH = availH / elH;
2168
- return Math.min(1.1, Math.min(sW, sH));
2234
+ const sH = availH / singlePageH;
2235
+ if (mode === "page") {
2236
+ return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
2237
+ }
2238
+ return Math.max(0.65, Math.min(1.05, sW));
2169
2239
  };
2170
2240
  const applyTransform = () => {
2171
2241
  wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
2172
2242
  wrapper.style.transformOrigin = "top center";
2173
2243
  };
2174
2244
  setTimeout(() => {
2175
- scale = calculateFitScale();
2245
+ fitMode = "width";
2246
+ scale = calculateFitScale("width");
2176
2247
  applyTransform();
2177
2248
  }, 60);
2178
2249
  const cleanup = () => {
@@ -2206,7 +2277,8 @@ var DocxPlugin = class {
2206
2277
  applyTransform();
2207
2278
  },
2208
2279
  fitToPage: () => {
2209
- scale = calculateFitScale();
2280
+ fitMode = fitMode === "width" ? "page" : "width";
2281
+ scale = calculateFitScale(fitMode);
2210
2282
  rotation = 0;
2211
2283
  applyTransform();
2212
2284
  },
@@ -2276,90 +2348,149 @@ var DocxPlugin = class {
2276
2348
  console.warn("[DocxPlugin] Error parsing relationships:", relsErr);
2277
2349
  }
2278
2350
  }
2279
- const card = document.createElement("div");
2280
- card.className = "fp-docx-page-card";
2281
- card.style.backgroundColor = "#ffffff";
2282
- card.style.borderRadius = "6px";
2283
- card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
2284
- card.style.padding = "48px 56px";
2285
- card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
2286
- card.style.color = "#1e293b";
2287
- card.style.lineHeight = "1.6";
2351
+ const sectPrs = Array.from(doc.getElementsByTagNameNS("*", "sectPr"));
2352
+ const lastSectPr = sectPrs[sectPrs.length - 1];
2353
+ let defaultW = 12240;
2354
+ let defaultH = 15840;
2355
+ let margins = { top: 1440, right: 1440, bottom: 1440, left: 1440 };
2356
+ if (lastSectPr) {
2357
+ const pgSz = lastSectPr.getElementsByTagNameNS("*", "pgSz")[0];
2358
+ if (pgSz) {
2359
+ defaultW = parseInt(pgSz.getAttribute("w:w") || pgSz.getAttribute("w") || "12240", 10);
2360
+ defaultH = parseInt(pgSz.getAttribute("w:h") || pgSz.getAttribute("h") || "15840", 10);
2361
+ }
2362
+ const pgMar = lastSectPr.getElementsByTagNameNS("*", "pgMar")[0];
2363
+ if (pgMar) {
2364
+ margins.top = parseInt(pgMar.getAttribute("w:top") || pgMar.getAttribute("top") || "1440", 10);
2365
+ margins.bottom = parseInt(pgMar.getAttribute("w:bottom") || pgMar.getAttribute("bottom") || "1440", 10);
2366
+ margins.left = parseInt(pgMar.getAttribute("w:left") || pgMar.getAttribute("left") || "1440", 10);
2367
+ margins.right = parseInt(pgMar.getAttribute("w:right") || pgMar.getAttribute("right") || "1440", 10);
2368
+ }
2369
+ }
2370
+ const createPageCard = () => {
2371
+ const card = document.createElement("div");
2372
+ card.className = "fp-docx-page-card";
2373
+ card.style.backgroundColor = "#ffffff";
2374
+ card.style.borderRadius = "4px";
2375
+ card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
2376
+ card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
2377
+ card.style.color = "#1e293b";
2378
+ card.style.lineHeight = "1.6";
2379
+ card.style.boxSizing = "border-box";
2380
+ card.style.overflow = "hidden";
2381
+ card.style.position = "relative";
2382
+ card.style.marginBottom = "24px";
2383
+ card.style.width = `${defaultW / 15}px`;
2384
+ card.style.height = `${defaultH / 15}px`;
2385
+ card.style.padding = `${margins.top / 15}px ${margins.right / 15}px ${margins.bottom / 15}px ${margins.left / 15}px`;
2386
+ return card;
2387
+ };
2388
+ let currentCard = createPageCard();
2389
+ let currentHtml = "";
2390
+ const pages = [{ card: currentCard, html: "" }];
2391
+ const flushHtml = () => {
2392
+ pages[pages.length - 1].html += currentHtml;
2393
+ currentHtml = "";
2394
+ };
2395
+ const newPage = () => {
2396
+ flushHtml();
2397
+ currentCard = createPageCard();
2398
+ pages.push({ card: currentCard, html: "" });
2399
+ };
2288
2400
  const body = doc.getElementsByTagNameNS("*", "body")[0] || doc.documentElement;
2289
- let html = "";
2290
2401
  for (const child of Array.from(body.children)) {
2291
2402
  const tag = child.localName || child.nodeName.split(":").pop();
2292
2403
  if (tag === "p") {
2293
2404
  const pStyle = child.getElementsByTagNameNS("*", "pStyle")[0];
2294
2405
  const styleVal = pStyle?.getAttribute("w:val") || pStyle?.getAttribute("val") || "";
2295
2406
  const numPr = child.getElementsByTagNameNS("*", "numPr")[0];
2296
- const textContent = this.extractParagraphHtml(child, imageMap);
2297
- if (!textContent.trim()) {
2298
- html += '<div style="height: 10px;"></div>';
2299
- continue;
2300
- }
2301
- const lowerStyle = styleVal.toLowerCase();
2302
- if (lowerStyle.includes("title")) {
2303
- 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>`;
2304
- } else if (lowerStyle.includes("heading1") || styleVal === "1") {
2305
- html += `<h2 style="font-size: 22px; font-weight: 700; color: #1e40af; margin: 20px 0 10px;">${textContent}</h2>`;
2306
- } else if (lowerStyle.includes("heading2") || styleVal === "2") {
2307
- html += `<h3 style="font-size: 18px; font-weight: 600; color: #2563eb; margin: 16px 0 8px;">${textContent}</h3>`;
2308
- } else if (lowerStyle.includes("heading3") || styleVal === "3") {
2309
- html += `<h4 style="font-size: 15px; font-weight: 600; color: #334155; margin: 12px 0 6px;">${textContent}</h4>`;
2310
- } else if (numPr) {
2311
- 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>`;
2312
- } else {
2313
- html += `<p style="margin: 8px 0; font-size: 14px;">${textContent}</p>`;
2407
+ const chunks = this.extractParagraphChunks(child, imageMap);
2408
+ for (let i = 0; i < chunks.length; i++) {
2409
+ if (i > 0) {
2410
+ newPage();
2411
+ }
2412
+ const textContent = chunks[i];
2413
+ if (!textContent.trim() && !textContent.includes("<img")) {
2414
+ currentHtml += '<div style="height: 10px;"></div>';
2415
+ continue;
2416
+ }
2417
+ const lowerStyle = styleVal.toLowerCase();
2418
+ if (lowerStyle.includes("title")) {
2419
+ 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>`;
2420
+ } else if (lowerStyle.includes("heading1") || styleVal === "1") {
2421
+ currentHtml += `<h2 style="font-size: 22px; font-weight: 700; color: #1e40af; margin: 20px 0 10px;">${textContent}</h2>`;
2422
+ } else if (lowerStyle.includes("heading2") || styleVal === "2") {
2423
+ currentHtml += `<h3 style="font-size: 18px; font-weight: 600; color: #2563eb; margin: 16px 0 8px;">${textContent}</h3>`;
2424
+ } else if (lowerStyle.includes("heading3") || styleVal === "3") {
2425
+ currentHtml += `<h4 style="font-size: 15px; font-weight: 600; color: #334155; margin: 12px 0 6px;">${textContent}</h4>`;
2426
+ } else if (numPr) {
2427
+ 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>`;
2428
+ } else {
2429
+ currentHtml += `<p style="margin: 8px 0; font-size: 14px;">${textContent}</p>`;
2430
+ }
2314
2431
  }
2315
2432
  } else if (tag === "tbl") {
2316
- html += '<table style="width: 100%; border-collapse: collapse; margin: 20px 0; border: 1px solid #cbd5e1;">';
2433
+ currentHtml += '<table style="width: 100%; border-collapse: collapse; margin: 20px 0; border: 1px solid #cbd5e1;">';
2317
2434
  const rows = Array.from(child.getElementsByTagNameNS("*", "tr"));
2318
2435
  rows.forEach((tr, rIdx) => {
2319
- html += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
2436
+ currentHtml += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
2320
2437
  const cells = Array.from(tr.getElementsByTagNameNS("*", "tc"));
2321
2438
  cells.forEach((tc) => {
2322
2439
  const cellText = this.extractParagraphHtml(tc, imageMap);
2323
- html += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || "&nbsp;"}</td>`;
2440
+ currentHtml += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || "&nbsp;"}</td>`;
2324
2441
  });
2325
- html += "</tr>";
2442
+ currentHtml += "</tr>";
2326
2443
  });
2327
- html += "</table>";
2444
+ currentHtml += "</table>";
2328
2445
  }
2329
2446
  }
2330
- card.innerHTML = DOMPurify2__default.default.sanitize(html, {
2331
- ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "s", "strike", "img", "div", "br"],
2332
- ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
2333
- });
2334
- wrapper.appendChild(card);
2447
+ flushHtml();
2448
+ for (const page of pages) {
2449
+ page.card.innerHTML = DOMPurify6__default.default.sanitize(page.html, {
2450
+ ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "s", "strike", "img", "div", "br"],
2451
+ ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
2452
+ });
2453
+ wrapper.appendChild(page.card);
2454
+ }
2335
2455
  }
2336
2456
  extractParagraphHtml(pElement, imageMap = {}) {
2337
- let result = "";
2457
+ return this.extractParagraphChunks(pElement, imageMap).join("<br/>");
2458
+ }
2459
+ extractParagraphChunks(pElement, imageMap = {}) {
2460
+ const chunks = [""];
2461
+ let currentChunkIndex = 0;
2338
2462
  const drawings = Array.from(pElement.getElementsByTagNameNS("*", "drawing"));
2339
2463
  for (const drawing of drawings) {
2340
2464
  const blip = drawing.getElementsByTagNameNS("*", "blip")[0];
2341
2465
  const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
2342
2466
  if (rId && imageMap[rId]) {
2343
- result += `<div style="text-align:center; margin: 12px 0;"><img src="${imageMap[rId]}" style="max-width: 100%; height: auto; border-radius: 4px;" /></div>`;
2467
+ chunks[currentChunkIndex] += `<div style="text-align:center; margin: 12px 0;"><img src="${imageMap[rId]}" style="max-width: 100%; height: auto; border-radius: 4px;" /></div>`;
2344
2468
  }
2345
2469
  }
2346
2470
  const runs = Array.from(pElement.getElementsByTagNameNS("*", "r"));
2347
- if (runs.length === 0 && !result) {
2348
- return DOMPurify2__default.default.sanitize(pElement.textContent || "");
2471
+ if (runs.length === 0 && !chunks[currentChunkIndex]) {
2472
+ chunks[currentChunkIndex] = DOMPurify6__default.default.sanitize(pElement.textContent || "");
2473
+ return chunks;
2349
2474
  }
2350
2475
  for (const r of runs) {
2351
2476
  const blip = r.getElementsByTagNameNS("*", "blip")[0] || r.getElementsByTagNameNS("*", "imagedata")[0];
2352
2477
  const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
2353
2478
  if (rId && imageMap[rId]) {
2354
- result += `<img src="${imageMap[rId]}" style="max-width: 100%; height: auto; display: inline-block; margin: 4px;" />`;
2479
+ chunks[currentChunkIndex] += `<img src="${imageMap[rId]}" style="max-width: 100%; height: auto; display: inline-block; margin: 4px;" />`;
2355
2480
  }
2356
- const brs = r.getElementsByTagNameNS("*", "br");
2357
- for (let i = 0; i < brs.length; i++) {
2358
- result += "<br/>";
2481
+ const brs = Array.from(r.getElementsByTagNameNS("*", "br"));
2482
+ for (const br of brs) {
2483
+ const type = br.getAttribute("w:type") || br.getAttribute("type");
2484
+ if (type === "page") {
2485
+ chunks.push("");
2486
+ currentChunkIndex++;
2487
+ } else {
2488
+ chunks[currentChunkIndex] += "<br/>";
2489
+ }
2359
2490
  }
2360
2491
  const tabs = r.getElementsByTagNameNS("*", "tab");
2361
2492
  if (tabs.length > 0) {
2362
- result += "&emsp;";
2493
+ chunks[currentChunkIndex] += "&emsp;";
2363
2494
  }
2364
2495
  const rPr = r.getElementsByTagNameNS("*", "rPr")[0];
2365
2496
  const isBold = !!rPr?.getElementsByTagNameNS("*", "b")[0];
@@ -2373,7 +2504,7 @@ var DocxPlugin = class {
2373
2504
  const texts = Array.from(r.getElementsByTagNameNS("*", "t"));
2374
2505
  let text = texts.map((t) => t.textContent || "").join("");
2375
2506
  if (!text) continue;
2376
- text = DOMPurify2__default.default.sanitize(text);
2507
+ text = DOMPurify6__default.default.sanitize(text);
2377
2508
  let styles = "";
2378
2509
  if (isBold) styles += "font-weight: bold; ";
2379
2510
  if (isItalic) styles += "font-style: italic; ";
@@ -2385,12 +2516,12 @@ var DocxPlugin = class {
2385
2516
  if (!isNaN(pt) && pt > 0) styles += `font-size: ${pt}pt; `;
2386
2517
  }
2387
2518
  if (styles) {
2388
- result += `<span style="${styles}">${text}</span>`;
2519
+ chunks[currentChunkIndex] += `<span style="${styles}">${text}</span>`;
2389
2520
  } else {
2390
- result += text;
2521
+ chunks[currentChunkIndex] += text;
2391
2522
  }
2392
2523
  }
2393
- return result;
2524
+ return chunks;
2394
2525
  }
2395
2526
  renderBinaryDocFallback(ctx, wrapper) {
2396
2527
  const card = document.createElement("div");
@@ -2407,14 +2538,14 @@ var DocxPlugin = class {
2407
2538
  const wordDocStream = cfbf.readStream("WordDocument");
2408
2539
  if (wordDocStream && wordDocStream.length >= 512) {
2409
2540
  const text2 = this.extractReadableStrings(wordDocStream);
2410
- card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify2__default.default.sanitize(text2)}</div>`;
2541
+ card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6__default.default.sanitize(text2)}</div>`;
2411
2542
  wrapper.appendChild(card);
2412
2543
  return;
2413
2544
  }
2414
2545
  } catch {
2415
2546
  }
2416
2547
  const text = this.extractReadableStrings(new Uint8Array(ctx.buffer));
2417
- card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify2__default.default.sanitize(text)}</div>`;
2548
+ card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6__default.default.sanitize(text)}</div>`;
2418
2549
  wrapper.appendChild(card);
2419
2550
  }
2420
2551
  extractReadableStrings(bytes) {
@@ -2591,11 +2722,9 @@ var ExcelPlugin = class {
2591
2722
  const calculateFitScale = () => {
2592
2723
  const table = contentArea.querySelector("table");
2593
2724
  if (!table) return 1;
2594
- const availW = Math.max(200, container.clientWidth - 48);
2595
- const availH = Math.max(200, container.clientHeight - 80);
2725
+ const availW = Math.max(280, container.clientWidth - 48);
2596
2726
  const tW = table.offsetWidth || 800;
2597
- const tH = table.offsetHeight || 600;
2598
- return Math.min(1, Math.min(availW / tW, availH / tH));
2727
+ return Math.max(0.65, Math.min(1, availW / tW));
2599
2728
  };
2600
2729
  try {
2601
2730
  wb = XLSX__namespace.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
@@ -3013,41 +3142,94 @@ var CodePlugin = class {
3013
3142
  async render(ctx) {
3014
3143
  const decoder = new TextDecoder("utf-8");
3015
3144
  const fullText = decoder.decode(ctx.buffer);
3016
- const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
3017
- const rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
3145
+ const extRaw = ctx.metadata.extension?.toLowerCase();
3146
+ const mimeRaw = ctx.metadata.mimeType?.toLowerCase();
3147
+ const isTxt = extRaw === ".txt" || mimeRaw === "text/plain" && (!extRaw || !this.extensions.filter((e) => e !== ".txt").includes(extRaw));
3148
+ let rawPages = [];
3149
+ if (isTxt) {
3150
+ const explicitPages = fullText.split(/(?:\f|\x0C)/);
3151
+ for (const ep of explicitPages) {
3152
+ const lines = ep.split(/\r?\n/);
3153
+ let currentChunk = [];
3154
+ for (let i = 0; i < lines.length; i++) {
3155
+ currentChunk.push(lines[i]);
3156
+ if (currentChunk.length >= 46) {
3157
+ rawPages.push(currentChunk.join("\n"));
3158
+ currentChunk = [];
3159
+ }
3160
+ }
3161
+ if (currentChunk.length > 0 || lines.length === 0) {
3162
+ rawPages.push(currentChunk.join("\n"));
3163
+ }
3164
+ }
3165
+ if (rawPages.length === 0) rawPages = [""];
3166
+ } else {
3167
+ const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
3168
+ rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
3169
+ }
3018
3170
  const totalPages = Math.max(1, rawPages.length);
3019
3171
  let currentPage = 1;
3020
3172
  const container = document.createElement("div");
3021
3173
  container.style.width = "100%";
3022
3174
  container.style.height = "100%";
3023
3175
  container.style.overflow = "auto";
3024
- container.style.backgroundColor = "#1e1e1e";
3025
- container.style.color = "#d4d4d4";
3026
- container.style.padding = "16px";
3027
- container.style.boxSizing = "border-box";
3028
3176
  let fontSize = 13;
3029
3177
  let rotation = 0;
3178
+ let zoomLevel = 1;
3030
3179
  const pre = document.createElement("pre");
3031
- pre.style.margin = "0";
3032
- pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
3033
- pre.style.fontSize = `${fontSize}px`;
3034
- pre.style.lineHeight = "1.5";
3035
- pre.style.whiteSpace = "pre-wrap";
3036
- pre.style.wordBreak = "break-all";
3037
3180
  const code = document.createElement("code");
3181
+ if (isTxt) {
3182
+ container.style.backgroundColor = "#f1f5f9";
3183
+ container.style.padding = "32px";
3184
+ container.style.boxSizing = "border-box";
3185
+ container.style.display = "flex";
3186
+ container.style.flexDirection = "column";
3187
+ container.style.alignItems = "center";
3188
+ pre.style.margin = "0";
3189
+ pre.style.fontFamily = "Consolas, 'Courier New', monospace";
3190
+ pre.style.fontSize = "13px";
3191
+ pre.style.color = "#1e293b";
3192
+ pre.style.lineHeight = "1.5";
3193
+ pre.style.whiteSpace = "pre-wrap";
3194
+ pre.style.wordBreak = "break-word";
3195
+ pre.style.backgroundColor = "#ffffff";
3196
+ pre.style.width = "816px";
3197
+ pre.style.minHeight = "1056px";
3198
+ pre.style.padding = "72px 56px";
3199
+ pre.style.boxSizing = "border-box";
3200
+ pre.style.boxShadow = "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)";
3201
+ pre.style.borderRadius = "4px";
3202
+ pre.style.transformOrigin = "top center";
3203
+ } else {
3204
+ container.style.backgroundColor = "#1e1e1e";
3205
+ container.style.color = "#d4d4d4";
3206
+ container.style.padding = "16px";
3207
+ container.style.boxSizing = "border-box";
3208
+ pre.style.margin = "0";
3209
+ pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
3210
+ pre.style.fontSize = `${fontSize}px`;
3211
+ pre.style.lineHeight = "1.5";
3212
+ pre.style.whiteSpace = "pre-wrap";
3213
+ pre.style.wordBreak = "break-all";
3214
+ pre.style.transformOrigin = "top left";
3215
+ }
3038
3216
  const ext = (ctx.metadata.extension || "").replace(".", "");
3039
3217
  const renderCodePage = (text) => {
3040
- try {
3041
- if (ext && hljs__default.default.getLanguage(ext)) {
3042
- code.innerHTML = hljs__default.default.highlight(text, { language: ext }).value;
3043
- } else {
3044
- code.innerHTML = hljs__default.default.highlightAuto(text).value;
3045
- }
3046
- } catch {
3218
+ if (isTxt) {
3047
3219
  code.textContent = text;
3220
+ } else {
3221
+ try {
3222
+ if (ext && hljs__default.default.getLanguage(ext)) {
3223
+ code.innerHTML = hljs__default.default.highlight(text, { language: ext }).value;
3224
+ } else {
3225
+ code.innerHTML = hljs__default.default.highlightAuto(text).value;
3226
+ }
3227
+ } catch {
3228
+ code.textContent = text;
3229
+ }
3048
3230
  }
3049
3231
  };
3050
- renderCodePage(rawPages[0] || fullText);
3232
+ renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
3051
3233
  pre.appendChild(code);
3052
3234
  container.appendChild(pre);
3053
3235
  let indicator = null;
@@ -3056,15 +3238,22 @@ var CodePlugin = class {
3056
3238
  indicator.className = "fp-code-page-indicator";
3057
3239
  indicator.style.position = "sticky";
3058
3240
  indicator.style.bottom = "16px";
3059
- indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
3060
- indicator.style.backdropFilter = "blur(8px)";
3061
- indicator.style.color = "#f8fafc";
3241
+ if (isTxt) {
3242
+ indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
3243
+ indicator.style.color = "#334155";
3244
+ indicator.style.border = "1px solid #e2e8f0";
3245
+ indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
3246
+ } else {
3247
+ indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
3248
+ indicator.style.color = "#f8fafc";
3249
+ indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
3250
+ indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
3251
+ indicator.style.backdropFilter = "blur(8px)";
3252
+ }
3062
3253
  indicator.style.fontSize = "12px";
3063
3254
  indicator.style.fontWeight = "600";
3064
3255
  indicator.style.padding = "5px 14px";
3065
3256
  indicator.style.borderRadius = "20px";
3066
- indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
3067
- indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
3068
3257
  indicator.style.zIndex = "10";
3069
3258
  indicator.style.userSelect = "none";
3070
3259
  indicator.style.pointerEvents = "none";
@@ -3075,7 +3264,7 @@ var CodePlugin = class {
3075
3264
  }
3076
3265
  const showPage = (pageNum) => {
3077
3266
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
3078
- renderCodePage(rawPages[currentPage - 1] || fullText);
3267
+ renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
3079
3268
  if (indicator) {
3080
3269
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
3081
3270
  }
@@ -3091,39 +3280,57 @@ var CodePlugin = class {
3091
3280
  ctx.container.innerHTML = "";
3092
3281
  };
3093
3282
  ctx.signal.addEventListener("abort", cleanup);
3283
+ const updateTransform = () => {
3284
+ if (isTxt) {
3285
+ pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
3286
+ } else {
3287
+ pre.style.transform = `rotate(${rotation}deg)`;
3288
+ pre.style.fontSize = `${fontSize}px`;
3289
+ }
3290
+ };
3094
3291
  return {
3095
3292
  destroy: cleanup,
3096
3293
  getPageCount: () => totalPages,
3097
3294
  getCurrentPage: () => currentPage,
3098
3295
  goToPage: (page) => showPage(page),
3099
3296
  zoomIn: () => {
3100
- fontSize = Math.min(32, fontSize + 2);
3101
- pre.style.fontSize = `${fontSize}px`;
3297
+ if (isTxt) {
3298
+ zoomLevel = Math.min(3, zoomLevel + 0.1);
3299
+ } else {
3300
+ fontSize = Math.min(32, fontSize + 2);
3301
+ }
3302
+ updateTransform();
3102
3303
  },
3103
3304
  zoomOut: () => {
3104
- fontSize = Math.max(8, fontSize - 2);
3105
- pre.style.fontSize = `${fontSize}px`;
3305
+ if (isTxt) {
3306
+ zoomLevel = Math.max(0.1, zoomLevel - 0.1);
3307
+ } else {
3308
+ fontSize = Math.max(8, fontSize - 2);
3309
+ }
3310
+ updateTransform();
3106
3311
  },
3107
- getZoom: () => fontSize / 13,
3312
+ getZoom: () => isTxt ? zoomLevel : fontSize / 13,
3108
3313
  setZoom: (level) => {
3109
- fontSize = Math.round(13 * level);
3110
- pre.style.fontSize = `${fontSize}px`;
3314
+ if (isTxt) {
3315
+ zoomLevel = level;
3316
+ } else {
3317
+ fontSize = Math.round(13 * level);
3318
+ }
3319
+ updateTransform();
3111
3320
  },
3112
3321
  fitToPage: () => {
3113
3322
  fontSize = 13;
3114
3323
  rotation = 0;
3115
- pre.style.fontSize = "13px";
3116
- pre.style.transform = "none";
3324
+ zoomLevel = isTxt ? Math.max(0.65, Math.min(1.05, (container.clientWidth - 48) / 816)) : 1;
3325
+ updateTransform();
3117
3326
  },
3118
3327
  rotateCW: () => {
3119
3328
  rotation = (rotation + 90) % 360;
3120
- pre.style.transform = `rotate(${rotation}deg)`;
3121
- pre.style.transformOrigin = "top left";
3329
+ updateTransform();
3122
3330
  },
3123
3331
  rotateCCW: () => {
3124
3332
  rotation = (rotation - 90 + 360) % 360;
3125
- pre.style.transform = `rotate(${rotation}deg)`;
3126
- pre.style.transformOrigin = "top left";
3333
+ updateTransform();
3127
3334
  },
3128
3335
  download: () => {
3129
3336
  const mimeType = ctx.metadata.mimeType || "text/plain";
@@ -3422,7 +3629,7 @@ var MarkdownPlugin = class {
3422
3629
  gfm: true,
3423
3630
  breaks: true
3424
3631
  });
3425
- const cleanHtml = DOMPurify2__default.default.sanitize(rawHtml, {
3632
+ const cleanHtml = DOMPurify6__default.default.sanitize(rawHtml, {
3426
3633
  USE_PROFILES: { html: true }
3427
3634
  });
3428
3635
  const wrapper = document.createElement("div");
@@ -4058,6 +4265,14 @@ var RtfPlugin = class {
4058
4265
  group: "actions",
4059
4266
  execute: () => instance.download?.()
4060
4267
  },
4268
+ {
4269
+ id: "copy",
4270
+ icon: "copy",
4271
+ label: "Copy Text",
4272
+ type: "button",
4273
+ group: "actions",
4274
+ execute: () => instance.copy?.()
4275
+ },
4061
4276
  {
4062
4277
  id: "print",
4063
4278
  icon: "print",
@@ -4088,20 +4303,27 @@ var RtfPlugin = class {
4088
4303
  let scale = 1;
4089
4304
  let rotation = 0;
4090
4305
  let pageElements = [];
4091
- const calculateFitScale = () => {
4306
+ let fitMode = "width";
4307
+ const calculateFitScale = (mode = fitMode) => {
4092
4308
  const activeEl = pageElements[currentPage - 1] || wrapper;
4093
4309
  const elW = activeEl.offsetWidth || 850;
4094
- const elH = activeEl.offsetHeight || 1e3;
4095
- const availW = Math.max(200, ctx.container.clientWidth - 48);
4096
- const availH = Math.max(200, ctx.container.clientHeight - 80);
4097
- return Math.min(1.1, Math.min(availW / elW, availH / elH));
4310
+ const singlePageH = Math.min(activeEl.offsetHeight || 1056, Math.round(elW * 1.32));
4311
+ const availW = Math.max(280, ctx.container.clientWidth - 48);
4312
+ const availH = Math.max(280, ctx.container.clientHeight - 80);
4313
+ const sW = availW / elW;
4314
+ const sH = availH / singlePageH;
4315
+ if (mode === "page") {
4316
+ return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
4317
+ }
4318
+ return Math.max(0.65, Math.min(1.05, sW));
4098
4319
  };
4099
4320
  const applyTransform = () => {
4100
4321
  wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
4101
4322
  wrapper.style.transformOrigin = "top center";
4102
4323
  };
4103
4324
  setTimeout(() => {
4104
- scale = calculateFitScale();
4325
+ fitMode = "width";
4326
+ scale = calculateFitScale("width");
4105
4327
  applyTransform();
4106
4328
  }, 60);
4107
4329
  try {
@@ -4119,14 +4341,31 @@ var RtfPlugin = class {
4119
4341
  } catch (err) {
4120
4342
  console.warn("[RtfPlugin] RTF render error, fallback text:", err);
4121
4343
  const text = new TextDecoder("latin1").decode(ctx.buffer);
4122
- const clean = text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "");
4123
- const pre = document.createElement("pre");
4124
- pre.style.whiteSpace = "pre-wrap";
4125
- pre.style.fontFamily = "serif";
4126
- pre.style.color = "#333";
4127
- pre.textContent = clean;
4128
- wrapper.appendChild(pre);
4129
- pageElements = [pre];
4344
+ const rawPages = text.split(/\\page\b/).map((segment) => {
4345
+ return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
4346
+ }).filter((p) => p.length > 0);
4347
+ const pages = rawPages.length > 0 ? rawPages : [text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim()];
4348
+ for (let i = 0; i < pages.length; i++) {
4349
+ const pageCard = document.createElement("div");
4350
+ pageCard.className = "fp-rtf-page-card";
4351
+ pageCard.style.backgroundColor = "#ffffff";
4352
+ pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
4353
+ pageCard.style.borderRadius = "4px";
4354
+ pageCard.style.padding = "72px 56px";
4355
+ pageCard.style.width = "816px";
4356
+ pageCard.style.minHeight = "1056px";
4357
+ pageCard.style.maxWidth = "100%";
4358
+ pageCard.style.boxSizing = "border-box";
4359
+ pageCard.style.fontFamily = "serif";
4360
+ pageCard.style.fontSize = "12pt";
4361
+ pageCard.style.lineHeight = "1.6";
4362
+ pageCard.style.color = "#1e293b";
4363
+ pageCard.style.whiteSpace = "pre-wrap";
4364
+ pageCard.style.display = i === 0 ? "block" : "none";
4365
+ pageCard.textContent = pages[i];
4366
+ wrapper.appendChild(pageCard);
4367
+ pageElements.push(pageCard);
4368
+ }
4130
4369
  }
4131
4370
  const totalPages = Math.max(1, pageElements.length);
4132
4371
  let currentPage = 1;
@@ -4193,7 +4432,8 @@ var RtfPlugin = class {
4193
4432
  applyTransform();
4194
4433
  },
4195
4434
  fitToPage: () => {
4196
- scale = calculateFitScale();
4435
+ fitMode = fitMode === "width" ? "page" : "width";
4436
+ scale = calculateFitScale(fitMode);
4197
4437
  rotation = 0;
4198
4438
  applyTransform();
4199
4439
  },
@@ -4214,6 +4454,10 @@ var RtfPlugin = class {
4214
4454
  a.click();
4215
4455
  URL.revokeObjectURL(url);
4216
4456
  },
4457
+ copy: () => {
4458
+ const text = wrapper.textContent || "";
4459
+ navigator.clipboard?.writeText(text);
4460
+ },
4217
4461
  print: () => {
4218
4462
  window.print();
4219
4463
  }
@@ -4288,7 +4532,7 @@ var HtmlPreviewPlugin = class {
4288
4532
  }
4289
4533
  async render(ctx) {
4290
4534
  const rawHtml = new TextDecoder("utf-8").decode(ctx.buffer);
4291
- const sanitized = DOMPurify2__default.default.sanitize(rawHtml, {
4535
+ const sanitized = DOMPurify6__default.default.sanitize(rawHtml, {
4292
4536
  WHOLE_DOCUMENT: true,
4293
4537
  ADD_TAGS: ["style", "link"],
4294
4538
  ADD_ATTR: ["target", "rel"]
@@ -4508,19 +4752,29 @@ var OpenDocumentPlugin = class {
4508
4752
  ctx.container.appendChild(container);
4509
4753
  let scale = 1;
4510
4754
  let rotation = 0;
4511
- const calculateFitScale = () => {
4755
+ let fitMode = "width";
4756
+ const calculateFitScale = (mode = fitMode) => {
4512
4757
  const elW = wrapper.offsetWidth || 850;
4513
- const elH = wrapper.offsetHeight || (isPresentation ? 540 : 1e3);
4514
- const availW = Math.max(200, ctx.container.clientWidth - 48);
4515
- const availH = Math.max(200, ctx.container.clientHeight - 80);
4516
- return Math.min(1, Math.min(availW / elW, availH / elH));
4758
+ const singlePageH = Math.min(wrapper.offsetHeight || 1056, Math.round(elW * 1.32));
4759
+ const availW = Math.max(280, ctx.container.clientWidth - 48);
4760
+ const availH = Math.max(280, ctx.container.clientHeight - 80);
4761
+ const sW = availW / elW;
4762
+ const sH = availH / (isPresentation ? 540 : singlePageH);
4763
+ if (isPresentation) {
4764
+ return Math.min(1, Math.min(sW, sH));
4765
+ }
4766
+ if (mode === "page") {
4767
+ return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
4768
+ }
4769
+ return Math.max(0.65, Math.min(1.05, sW));
4517
4770
  };
4518
4771
  const applyTransform = () => {
4519
4772
  wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
4520
4773
  wrapper.style.transformOrigin = "top center";
4521
4774
  };
4522
4775
  setTimeout(() => {
4523
- scale = calculateFitScale();
4776
+ fitMode = "width";
4777
+ scale = calculateFitScale("width");
4524
4778
  applyTransform();
4525
4779
  }, 60);
4526
4780
  let currentPage = 1;
@@ -4554,14 +4808,97 @@ var OpenDocumentPlugin = class {
4554
4808
  wrapper.textContent = contentDoc.documentElement.textContent || "Formula content";
4555
4809
  }
4556
4810
  } else {
4557
- wrapper.style.maxWidth = "850px";
4558
- wrapper.style.padding = "48px";
4811
+ wrapper.style.maxWidth = "none";
4812
+ wrapper.style.padding = "0";
4559
4813
  wrapper.style.minHeight = "100%";
4814
+ wrapper.style.backgroundColor = "transparent";
4815
+ wrapper.style.boxShadow = "none";
4816
+ wrapper.style.position = "relative";
4817
+ const dims = this.getPageDimensions(stylesDoc, contentDoc);
4560
4818
  const bodyHtml = this.renderOdfBody(contentDoc, styleMap, imageUrls);
4561
- wrapper.innerHTML = DOMPurify2__default.default.sanitize(bodyHtml, {
4562
- ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub"],
4819
+ const tempDiv = document.createElement("div");
4820
+ tempDiv.style.width = `${dims.width - dims.marginLeft - dims.marginRight}px`;
4821
+ tempDiv.style.position = "absolute";
4822
+ tempDiv.style.visibility = "hidden";
4823
+ tempDiv.innerHTML = DOMPurify6__default.default.sanitize(bodyHtml, {
4824
+ ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub", "hr"],
4563
4825
  ADD_ATTR: ["style", "colspan", "rowspan"]
4564
4826
  });
4827
+ document.body.appendChild(tempDiv);
4828
+ const contentHeight = dims.height - dims.marginTop - dims.marginBottom;
4829
+ const pageElements = [[]];
4830
+ let currentHeight = 0;
4831
+ let currentPageIdx = 0;
4832
+ Array.from(tempDiv.children).forEach((child) => {
4833
+ const el = child;
4834
+ const style = el.getAttribute("style") || "";
4835
+ const isBreakBefore = style.includes("page-break-before: always");
4836
+ const isBreakAfter = style.includes("page-break-after: always");
4837
+ const isSoftBreak = el.classList.contains("odf-page-break");
4838
+ if (isBreakBefore) {
4839
+ if (pageElements[currentPageIdx].length > 0) {
4840
+ currentPageIdx++;
4841
+ pageElements.push([]);
4842
+ currentHeight = 0;
4843
+ }
4844
+ }
4845
+ const h = el.offsetHeight || 0;
4846
+ if (currentHeight + h > contentHeight && pageElements[currentPageIdx].length > 0 && !isSoftBreak) {
4847
+ currentPageIdx++;
4848
+ pageElements.push([]);
4849
+ currentHeight = 0;
4850
+ }
4851
+ if (!isSoftBreak) {
4852
+ pageElements[currentPageIdx].push(el.cloneNode(true));
4853
+ currentHeight += h;
4854
+ }
4855
+ if (isBreakAfter || isSoftBreak) {
4856
+ currentPageIdx++;
4857
+ pageElements.push([]);
4858
+ currentHeight = 0;
4859
+ }
4860
+ });
4861
+ document.body.removeChild(tempDiv);
4862
+ if (pageElements.length > 1 && pageElements[pageElements.length - 1].length === 0) {
4863
+ pageElements.pop();
4864
+ }
4865
+ totalPages = Math.max(1, pageElements.length);
4866
+ pageElements.forEach((elements, idx) => {
4867
+ const page = document.createElement("div");
4868
+ page.className = `fp-odt-page fp-odt-page-${idx + 1}`;
4869
+ page.style.width = `${dims.width}px`;
4870
+ page.style.minHeight = `${dims.height}px`;
4871
+ page.style.padding = `${dims.marginTop}px ${dims.marginRight}px ${dims.marginBottom}px ${dims.marginLeft}px`;
4872
+ page.style.margin = "0 auto";
4873
+ page.style.backgroundColor = "#ffffff";
4874
+ page.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
4875
+ page.style.borderRadius = "4px";
4876
+ page.style.boxSizing = "border-box";
4877
+ page.style.display = idx === 0 ? "block" : "none";
4878
+ page.style.position = "absolute";
4879
+ page.style.top = "0";
4880
+ page.style.left = "50%";
4881
+ page.style.transform = "translateX(-50%)";
4882
+ elements.forEach((el) => page.appendChild(el));
4883
+ wrapper.appendChild(page);
4884
+ slides.push(page);
4885
+ });
4886
+ const pageIndicator = document.createElement("div");
4887
+ pageIndicator.className = "fp-odt-page-indicator";
4888
+ pageIndicator.style.position = "sticky";
4889
+ pageIndicator.style.bottom = "16px";
4890
+ pageIndicator.style.left = "50%";
4891
+ pageIndicator.style.transform = "translateX(-50%)";
4892
+ pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
4893
+ pageIndicator.style.color = "#fff";
4894
+ pageIndicator.style.padding = "6px 12px";
4895
+ pageIndicator.style.borderRadius = "16px";
4896
+ pageIndicator.style.fontSize = "12px";
4897
+ pageIndicator.style.zIndex = "100";
4898
+ pageIndicator.style.display = "inline-block";
4899
+ pageIndicator.style.width = "fit-content";
4900
+ pageIndicator.textContent = `Page 1 of ${totalPages}`;
4901
+ container.appendChild(pageIndicator);
4565
4902
  }
4566
4903
  const cleanup = () => {
4567
4904
  imageUrls.forEach((url) => URL.revokeObjectURL(url));
@@ -4570,11 +4907,15 @@ var OpenDocumentPlugin = class {
4570
4907
  };
4571
4908
  ctx.signal.addEventListener("abort", cleanup);
4572
4909
  const goToPage = (page) => {
4573
- if (!isPresentation || page < 1 || page > totalPages) return;
4910
+ if (page < 1 || page > totalPages) return;
4574
4911
  currentPage = page;
4575
4912
  slides.forEach((s, idx) => {
4576
4913
  s.style.display = idx === page - 1 ? "block" : "none";
4577
4914
  });
4915
+ const indicator = container.querySelector(".fp-odt-page-indicator");
4916
+ if (indicator) {
4917
+ indicator.textContent = `Page ${currentPage} of ${totalPages}`;
4918
+ }
4578
4919
  ctx.emit("page-change", { page: currentPage, total: totalPages });
4579
4920
  };
4580
4921
  return {
@@ -4594,7 +4935,8 @@ var OpenDocumentPlugin = class {
4594
4935
  applyTransform();
4595
4936
  },
4596
4937
  fitToPage: () => {
4597
- scale = calculateFitScale();
4938
+ fitMode = fitMode === "width" ? "page" : "width";
4939
+ scale = calculateFitScale(fitMode);
4598
4940
  rotation = 0;
4599
4941
  applyTransform();
4600
4942
  },
@@ -4643,6 +4985,43 @@ var OpenDocumentPlugin = class {
4643
4985
  }
4644
4986
  };
4645
4987
  }
4988
+ getPageDimensions(stylesDoc, contentDoc) {
4989
+ let width = 850;
4990
+ let height = 1123;
4991
+ let marginTop = 48;
4992
+ let marginBottom = 48;
4993
+ let marginLeft = 48;
4994
+ let marginRight = 48;
4995
+ const parseUnit = (val) => {
4996
+ if (!val) return null;
4997
+ if (val.endsWith("cm")) return parseFloat(val) * 37.8;
4998
+ if (val.endsWith("mm")) return parseFloat(val) * 3.78;
4999
+ if (val.endsWith("in")) return parseFloat(val) * 96;
5000
+ if (val.endsWith("pt")) return parseFloat(val) * 1.33;
5001
+ if (val.endsWith("px")) return parseFloat(val);
5002
+ return parseFloat(val);
5003
+ };
5004
+ const docs = [stylesDoc, contentDoc].filter(Boolean);
5005
+ for (const doc of docs) {
5006
+ const pageLayout = doc.querySelector("page-layout-properties, [page-width]");
5007
+ if (pageLayout) {
5008
+ const w = parseUnit(pageLayout.getAttribute("fo:page-width") || pageLayout.getAttribute("page-width"));
5009
+ const h = parseUnit(pageLayout.getAttribute("fo:page-height") || pageLayout.getAttribute("page-height"));
5010
+ const mt = parseUnit(pageLayout.getAttribute("fo:margin-top") || pageLayout.getAttribute("margin-top"));
5011
+ const mb = parseUnit(pageLayout.getAttribute("fo:margin-bottom") || pageLayout.getAttribute("margin-bottom"));
5012
+ const ml = parseUnit(pageLayout.getAttribute("fo:margin-left") || pageLayout.getAttribute("margin-left"));
5013
+ const mr = parseUnit(pageLayout.getAttribute("fo:margin-right") || pageLayout.getAttribute("margin-right"));
5014
+ if (w !== null) width = w;
5015
+ if (h !== null) height = h;
5016
+ if (mt !== null) marginTop = mt;
5017
+ if (mb !== null) marginBottom = mb;
5018
+ if (ml !== null) marginLeft = ml;
5019
+ if (mr !== null) marginRight = mr;
5020
+ break;
5021
+ }
5022
+ }
5023
+ return { width, height, marginTop, marginBottom, marginLeft, marginRight };
5024
+ }
4646
5025
  extractStyles(stylesDoc, contentDoc) {
4647
5026
  const map = /* @__PURE__ */ new Map();
4648
5027
  const styleNodes = [];
@@ -4665,14 +5044,21 @@ var OpenDocumentPlugin = class {
4665
5044
  if (color) css += `color: ${color}; `;
4666
5045
  if (size) css += `font-size: ${size}; `;
4667
5046
  }
4668
- const paraProp = node.querySelector("paragraph-properties, [text-align]");
5047
+ let paraProp = node.querySelector("paragraph-properties, [text-align]");
5048
+ if (!paraProp) {
5049
+ paraProp = Array.from(node.children).find((c) => c.tagName.includes("paragraph-properties")) || null;
5050
+ }
4669
5051
  if (paraProp) {
4670
5052
  const align = paraProp.getAttribute("fo:text-align") || paraProp.getAttribute("text-align");
4671
5053
  const mt = paraProp.getAttribute("fo:margin-top") || paraProp.getAttribute("margin-top");
4672
5054
  const mb = paraProp.getAttribute("fo:margin-bottom") || paraProp.getAttribute("margin-bottom");
5055
+ const breakBefore = paraProp.getAttribute("fo:break-before") || paraProp.getAttribute("break-before");
5056
+ const breakAfter = paraProp.getAttribute("fo:break-after") || paraProp.getAttribute("break-after");
4673
5057
  if (align) css += `text-align: ${align}; `;
4674
5058
  if (mt) css += `margin-top: ${mt}; `;
4675
5059
  if (mb) css += `margin-bottom: ${mb}; `;
5060
+ if (breakBefore === "page") css += "page-break-before: always; ";
5061
+ if (breakAfter === "page") css += "page-break-after: always; ";
4676
5062
  }
4677
5063
  if (css) map.set(name, css);
4678
5064
  }
@@ -4757,6 +5143,8 @@ var OpenDocumentPlugin = class {
4757
5143
  result += "&emsp;";
4758
5144
  } else if (tag === "line-break") {
4759
5145
  result += "<br/>";
5146
+ } else if (tag === "soft-page-break") {
5147
+ result += '<hr class="odf-page-break" style="page-break-after: always; border: none; margin: 0; padding: 0; height: 0;" />';
4760
5148
  } else {
4761
5149
  result += el.textContent || "";
4762
5150
  }
@@ -4917,20 +5305,9 @@ var DocPlugin = class {
4917
5305
  container.style.overflow = "auto";
4918
5306
  container.style.padding = "32px 16px";
4919
5307
  container.style.backgroundColor = "#f1f5f9";
4920
- const wrapper = document.createElement("div");
4921
- wrapper.className = "fp-doc-wrapper";
4922
- wrapper.style.maxWidth = "850px";
4923
- wrapper.style.margin = "0 auto";
4924
- wrapper.style.backgroundColor = "#ffffff";
4925
- wrapper.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
4926
- wrapper.style.borderRadius = "4px";
4927
- wrapper.style.padding = "56px 48px";
4928
- wrapper.style.minHeight = "100%";
4929
- wrapper.style.transformOrigin = "top center";
4930
- wrapper.style.transition = "transform 0.2s ease";
4931
- wrapper.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
4932
- wrapper.style.color = "#1e293b";
4933
- container.appendChild(wrapper);
5308
+ container.style.display = "flex";
5309
+ container.style.justifyContent = "center";
5310
+ container.style.alignItems = "flex-start";
4934
5311
  ctx.container.appendChild(container);
4935
5312
  let scale = 1;
4936
5313
  let extractedRawText = "";
@@ -4957,21 +5334,27 @@ var DocPlugin = class {
4957
5334
  const rawPages = this.splitIntoPages(extractedRawText);
4958
5335
  const totalPages = Math.max(1, rawPages.length);
4959
5336
  let currentPage = 1;
4960
- wrapper.innerHTML = "";
4961
5337
  const pageCards = [];
4962
5338
  for (let i = 0; i < totalPages; i++) {
4963
5339
  const pageCard = document.createElement("div");
4964
5340
  pageCard.className = "fp-doc-page-card";
5341
+ pageCard.style.width = "816px";
5342
+ pageCard.style.height = "1056px";
4965
5343
  pageCard.style.backgroundColor = "#ffffff";
4966
5344
  pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
4967
5345
  pageCard.style.borderRadius = "4px";
4968
- pageCard.style.padding = "56px 48px";
4969
- pageCard.style.minHeight = "100%";
5346
+ pageCard.style.padding = "96px 72px";
5347
+ pageCard.style.boxSizing = "border-box";
5348
+ pageCard.style.overflow = "hidden";
4970
5349
  pageCard.style.display = i === 0 ? "block" : "none";
5350
+ pageCard.style.transformOrigin = "top center";
5351
+ pageCard.style.transition = "transform 0.2s ease";
5352
+ pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5353
+ pageCard.style.color = "#1e293b";
4971
5354
  if (isFallback && i === 0) {
4972
5355
  pageCard.innerHTML = `
4973
5356
  <div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
4974
- <h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify2__default.default.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
5357
+ <h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify6__default.default.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
4975
5358
  <span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
4976
5359
  </div>
4977
5360
  ${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
@@ -4979,15 +5362,17 @@ var DocPlugin = class {
4979
5362
  } else {
4980
5363
  pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
4981
5364
  }
4982
- wrapper.appendChild(pageCard);
5365
+ container.appendChild(pageCard);
4983
5366
  pageCards.push(pageCard);
4984
5367
  }
4985
5368
  let indicator = null;
4986
5369
  if (totalPages > 1) {
4987
5370
  indicator = document.createElement("div");
4988
5371
  indicator.className = "fp-doc-page-indicator";
4989
- indicator.style.position = "sticky";
5372
+ indicator.style.position = "fixed";
4990
5373
  indicator.style.bottom = "16px";
5374
+ indicator.style.left = "50%";
5375
+ indicator.style.transform = "translateX(-50%)";
4991
5376
  indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
4992
5377
  indicator.style.backdropFilter = "blur(8px)";
4993
5378
  indicator.style.color = "#f8fafc";
@@ -5001,17 +5386,25 @@ var DocPlugin = class {
5001
5386
  indicator.style.userSelect = "none";
5002
5387
  indicator.style.pointerEvents = "none";
5003
5388
  indicator.style.textAlign = "center";
5004
- indicator.style.width = "fit-content";
5005
- indicator.style.margin = "16px auto 0";
5006
5389
  container.appendChild(indicator);
5007
5390
  }
5391
+ let rotation = 0;
5392
+ const applyTransform = () => {
5393
+ const activeCard = pageCards[currentPage - 1];
5394
+ if (activeCard) {
5395
+ activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5396
+ }
5397
+ };
5008
5398
  const showPage = (pageNum) => {
5009
5399
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
5010
- if (totalPages > 1) {
5011
- pageCards.forEach((card, idx) => {
5012
- card.style.display = idx + 1 === currentPage ? "block" : "none";
5013
- });
5014
- }
5400
+ pageCards.forEach((card, idx) => {
5401
+ if (idx + 1 === currentPage) {
5402
+ card.style.display = "block";
5403
+ card.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5404
+ } else {
5405
+ card.style.display = "none";
5406
+ }
5407
+ });
5015
5408
  if (indicator) {
5016
5409
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
5017
5410
  }
@@ -5020,21 +5413,22 @@ var DocPlugin = class {
5020
5413
  if (totalPages > 1) {
5021
5414
  showPage(1);
5022
5415
  }
5023
- let rotation = 0;
5024
- const calculateFitScale = () => {
5025
- const activeCard = pageCards[currentPage - 1] || wrapper;
5026
- const elW = activeCard.offsetWidth || 850;
5027
- const elH = activeCard.offsetHeight || 1e3;
5028
- const availW = Math.max(200, ctx.container.clientWidth - 48);
5029
- const availH = Math.max(200, ctx.container.clientHeight - 80);
5030
- return Math.min(1.1, Math.min(availW / elW, availH / elH));
5031
- };
5032
- const applyTransform = () => {
5033
- wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5034
- wrapper.style.transformOrigin = "top center";
5416
+ let fitMode = "width";
5417
+ const calculateFitScale = (mode = fitMode) => {
5418
+ const elW = 816;
5419
+ const elH = 1056;
5420
+ const availW = Math.max(280, ctx.container.clientWidth - 48);
5421
+ const availH = Math.max(280, ctx.container.clientHeight - 80);
5422
+ const sW = availW / elW;
5423
+ const sH = availH / elH;
5424
+ if (mode === "page") {
5425
+ return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
5426
+ }
5427
+ return Math.max(0.65, Math.min(1.05, sW));
5035
5428
  };
5036
5429
  setTimeout(() => {
5037
- scale = calculateFitScale();
5430
+ fitMode = "width";
5431
+ scale = calculateFitScale("width");
5038
5432
  applyTransform();
5039
5433
  }, 60);
5040
5434
  const cleanup = () => {
@@ -5062,7 +5456,8 @@ var DocPlugin = class {
5062
5456
  applyTransform();
5063
5457
  },
5064
5458
  fitToPage: () => {
5065
- scale = calculateFitScale();
5459
+ fitMode = fitMode === "width" ? "page" : "width";
5460
+ scale = calculateFitScale(fitMode);
5066
5461
  rotation = 0;
5067
5462
  applyTransform();
5068
5463
  },
@@ -5190,8 +5585,28 @@ var DocPlugin = class {
5190
5585
  }
5191
5586
  splitIntoPages(text) {
5192
5587
  if (!text) return [""];
5193
- 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);
5194
- return parts.length > 0 ? parts : [text];
5588
+ 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);
5589
+ if (explicitParts.length === 0) explicitParts.push(text);
5590
+ const maxLinesPerPage = 48;
5591
+ const finalPages = [];
5592
+ for (const part of explicitParts) {
5593
+ const lines = part.split(/\r?\n/);
5594
+ let currentLines = [];
5595
+ let count = 0;
5596
+ for (const line of lines) {
5597
+ currentLines.push(line);
5598
+ count++;
5599
+ if (count >= maxLinesPerPage) {
5600
+ finalPages.push(currentLines.join("\n"));
5601
+ currentLines = [];
5602
+ count = 0;
5603
+ }
5604
+ }
5605
+ if (currentLines.length > 0) {
5606
+ finalPages.push(currentLines.join("\n"));
5607
+ }
5608
+ }
5609
+ return finalPages.length > 0 ? finalPages : [text];
5195
5610
  }
5196
5611
  /**
5197
5612
  * Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
@@ -5200,17 +5615,65 @@ var DocPlugin = class {
5200
5615
  const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
5201
5616
  let html = "";
5202
5617
  let inList = false;
5203
- for (const rawLine of lines) {
5204
- const line = rawLine.trim();
5618
+ let tableLines = [];
5619
+ const flushTable = () => {
5620
+ if (tableLines.length > 0) {
5621
+ html += '<table style="width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 12px;">';
5622
+ for (const tLine of tableLines) {
5623
+ html += "<tr>";
5624
+ const cols = tLine.split(" ");
5625
+ for (const col of cols) {
5626
+ html += `<td style="border: 1px solid #cbd5e1; padding: 6px 8px;">${DOMPurify6__default.default.sanitize(col.trim())}</td>`;
5627
+ }
5628
+ html += "</tr>";
5629
+ }
5630
+ html += "</table>";
5631
+ tableLines = [];
5632
+ }
5633
+ };
5634
+ let i = 0;
5635
+ while (i < lines.length) {
5636
+ let line = lines[i];
5637
+ let tabCount = (line.match(/\t/g) || []).length;
5638
+ if (tabCount > 0) {
5639
+ let consecutiveTableLines = 1;
5640
+ let j = i + 1;
5641
+ while (j < lines.length) {
5642
+ const nextTabCount = (lines[j].match(/\t/g) || []).length;
5643
+ if (nextTabCount === tabCount) {
5644
+ consecutiveTableLines++;
5645
+ j++;
5646
+ } else {
5647
+ break;
5648
+ }
5649
+ }
5650
+ if (consecutiveTableLines >= 3) {
5651
+ if (inList) {
5652
+ html += "</ul>";
5653
+ inList = false;
5654
+ }
5655
+ tableLines = lines.slice(i, j);
5656
+ flushTable();
5657
+ i = j;
5658
+ continue;
5659
+ }
5660
+ }
5661
+ line = line.trim();
5205
5662
  if (!line) {
5206
5663
  if (inList) {
5207
5664
  html += "</ul>";
5208
5665
  inList = false;
5209
5666
  }
5667
+ html += '<div style="height: 1.15em;"></div>';
5668
+ i++;
5669
+ continue;
5670
+ }
5671
+ if (/^[\x00-\x1F\x7F-\x9F]+$/.test(line)) {
5672
+ i++;
5210
5673
  continue;
5211
5674
  }
5212
- if (/^[\x00-\x1F\x7F-\x9F]+$/.test(line)) continue;
5213
- if (line.includes("Normal.dot") || line.includes("Microsoft Word") || line.includes("Times New Roman") && line.length < 30) {
5675
+ if ((line.includes("Normal.dot") || line.includes("Microsoft Word") || line.includes("Times New Roman")) && line.length < 30) {
5676
+ i++;
5214
5677
  continue;
5215
5678
  }
5216
5679
  if (line.length < 60 && !line.endsWith(".") && (/^[A-Z0-9\s:_-]+$/.test(line) || line.startsWith("#"))) {
@@ -5218,24 +5681,26 @@ var DocPlugin = class {
5218
5681
  html += "</ul>";
5219
5682
  inList = false;
5220
5683
  }
5221
- 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>`;
5684
+ 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>`;
5222
5685
  } else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
5223
5686
  if (!inList) {
5224
5687
  html += '<ul style="margin: 8px 0; padding-left: 24px;">';
5225
5688
  inList = true;
5226
5689
  }
5227
5690
  const bulletText = line.replace(/^[•\-\*]\s*/, "");
5228
- html += `<li style="margin: 4px 0; line-height: 1.6;">${DOMPurify2__default.default.sanitize(bulletText)}</li>`;
5691
+ html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6__default.default.sanitize(bulletText)}</li>`;
5229
5692
  } else {
5230
5693
  if (inList) {
5231
5694
  html += "</ul>";
5232
5695
  inList = false;
5233
5696
  }
5234
- html += `<p style="line-height: 1.7; margin: 10px 0; font-size: 14px; text-align: justify;">${DOMPurify2__default.default.sanitize(line)}</p>`;
5697
+ html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6__default.default.sanitize(line)}</p>`;
5235
5698
  }
5699
+ i++;
5236
5700
  }
5237
5701
  if (inList) html += "</ul>";
5238
- return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify2__default.default.sanitize(filename)})</p>`;
5702
+ flushTable();
5703
+ return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify6__default.default.sanitize(filename)})</p>`;
5239
5704
  }
5240
5705
  };
5241
5706
  function docPlugin() {
@@ -5413,7 +5878,7 @@ var PptPlugin = class {
5413
5878
  if (s.pictureUrl) {
5414
5879
  contentHtml = `
5415
5880
  <div style="flex: 1; display: flex; justify-content: center; align-items: center; padding: 12px; overflow: hidden;">
5416
- <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;" />
5881
+ <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;" />
5417
5882
  </div>
5418
5883
  `;
5419
5884
  } else if (s.tableColumns.length > 0) {
@@ -5423,7 +5888,7 @@ var PptPlugin = class {
5423
5888
  <table style="width: 100%; border-collapse: collapse; border: 1px solid #cbd5e1; border-radius: 6px; overflow: hidden; background: #ffffff;">
5424
5889
  <thead>
5425
5890
  <tr style="background: #e2e8f0; color: #1e293b; font-weight: 600; font-size: 14px;">
5426
- ${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify2__default.default.sanitize(c)}</th>`).join("")}
5891
+ ${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify6__default.default.sanitize(c)}</th>`).join("")}
5427
5892
  </tr>
5428
5893
  </thead>
5429
5894
  <tbody>
@@ -5439,7 +5904,7 @@ var PptPlugin = class {
5439
5904
  } else {
5440
5905
  const pTags = s.paragraphs.map((p) => {
5441
5906
  const lines = p.split(/[\r\n]+/).map((l) => l.trim()).filter(Boolean);
5442
- 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("");
5907
+ 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("");
5443
5908
  }).join("");
5444
5909
  contentHtml = `
5445
5910
  <div style="flex: 1; overflow: auto; padding: 4px 8px; display: flex; flex-direction: column; justify-content: flex-start;">
@@ -5452,11 +5917,11 @@ var PptPlugin = class {
5452
5917
  <!-- Header Banner matching PowerPoint design -->
5453
5918
  <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;">
5454
5919
  <h1 style="margin: 0; font-size: 26px; font-weight: 700; color: #1e293b; letter-spacing: -0.3px;">
5455
- ${DOMPurify2__default.default.sanitize(s.title)}
5920
+ ${DOMPurify6__default.default.sanitize(s.title)}
5456
5921
  </h1>
5457
5922
  ${s.subtitle ? `
5458
5923
  <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);">
5459
- ${DOMPurify2__default.default.sanitize(s.subtitle)}
5924
+ ${DOMPurify6__default.default.sanitize(s.subtitle)}
5460
5925
  </span>
5461
5926
  ` : `
5462
5927
  <span style="font-size: 12px; color: #365314; font-weight: 600;">