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