@files-preview-app/preview-file 1.2.6 → 1.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.cjs CHANGED
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var react = require('react');
6
- var DOMPurify2 = require('dompurify');
6
+ var DOMPurify6 = require('dompurify');
7
7
  var pdfjsLib = require('pdfjs-dist');
8
8
  var docx = require('docx-preview');
9
9
  var fflate = require('fflate');
@@ -38,7 +38,7 @@ function _interopNamespace(e) {
38
38
  return Object.freeze(n);
39
39
  }
40
40
 
41
- var DOMPurify2__default = /*#__PURE__*/_interopDefault(DOMPurify2);
41
+ var DOMPurify6__default = /*#__PURE__*/_interopDefault(DOMPurify6);
42
42
  var pdfjsLib__namespace = /*#__PURE__*/_interopNamespace(pdfjsLib);
43
43
  var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
44
44
  var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
@@ -390,7 +390,7 @@ async function sourceToArrayBuffer(source, signal) {
390
390
  if (magicMime === "application/zip") {
391
391
  const ooxmlMime = detectOoxmlType(buffer);
392
392
  if (ooxmlMime && ooxmlMime !== "application/zip") {
393
- metadata.mimeType = ooxmlMime;
393
+ metadata.mimeType = metadata.mimeType ?? ooxmlMime;
394
394
  if (ooxmlMime.includes("wordprocessing")) metadata.extension = metadata.extension ?? ".docx";
395
395
  else if (ooxmlMime.includes("spreadsheet")) metadata.extension = metadata.extension ?? ".xlsx";
396
396
  else if (ooxmlMime.includes("presentation")) metadata.extension = metadata.extension ?? ".pptx";
@@ -419,7 +419,7 @@ async function sourceToArrayBuffer(source, signal) {
419
419
  return { buffer, metadata };
420
420
  }
421
421
  function sanitizeSVG(svg) {
422
- return DOMPurify2__default.default.sanitize(svg, {
422
+ return DOMPurify6__default.default.sanitize(svg, {
423
423
  USE_PROFILES: { svg: true, svgFilters: true }
424
424
  });
425
425
  }
@@ -1481,7 +1481,19 @@ var PdfPlugin = class {
1481
1481
  }
1482
1482
  };
1483
1483
  await renderPage(1);
1484
+ let resizeTimer = null;
1485
+ const resizeObserver = new ResizeObserver(() => {
1486
+ if (resizeTimer) clearTimeout(resizeTimer);
1487
+ resizeTimer = setTimeout(() => {
1488
+ if (Math.abs(zoomScale - 1) < 0.05) {
1489
+ renderPage(currentPage);
1490
+ }
1491
+ }, 150);
1492
+ });
1493
+ resizeObserver.observe(container);
1484
1494
  const cleanup = () => {
1495
+ resizeObserver.disconnect();
1496
+ if (resizeTimer) clearTimeout(resizeTimer);
1485
1497
  if (currentRenderTask) {
1486
1498
  try {
1487
1499
  currentRenderTask.cancel();
@@ -2229,90 +2241,149 @@ var DocxPlugin = class {
2229
2241
  console.warn("[DocxPlugin] Error parsing relationships:", relsErr);
2230
2242
  }
2231
2243
  }
2232
- const card = document.createElement("div");
2233
- card.className = "fp-docx-page-card";
2234
- card.style.backgroundColor = "#ffffff";
2235
- card.style.borderRadius = "6px";
2236
- card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
2237
- card.style.padding = "48px 56px";
2238
- card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
2239
- card.style.color = "#1e293b";
2240
- card.style.lineHeight = "1.6";
2244
+ const sectPrs = Array.from(doc.getElementsByTagNameNS("*", "sectPr"));
2245
+ const lastSectPr = sectPrs[sectPrs.length - 1];
2246
+ let defaultW = 12240;
2247
+ let defaultH = 15840;
2248
+ let margins = { top: 1440, right: 1440, bottom: 1440, left: 1440 };
2249
+ if (lastSectPr) {
2250
+ const pgSz = lastSectPr.getElementsByTagNameNS("*", "pgSz")[0];
2251
+ if (pgSz) {
2252
+ defaultW = parseInt(pgSz.getAttribute("w:w") || pgSz.getAttribute("w") || "12240", 10);
2253
+ defaultH = parseInt(pgSz.getAttribute("w:h") || pgSz.getAttribute("h") || "15840", 10);
2254
+ }
2255
+ const pgMar = lastSectPr.getElementsByTagNameNS("*", "pgMar")[0];
2256
+ if (pgMar) {
2257
+ margins.top = parseInt(pgMar.getAttribute("w:top") || pgMar.getAttribute("top") || "1440", 10);
2258
+ margins.bottom = parseInt(pgMar.getAttribute("w:bottom") || pgMar.getAttribute("bottom") || "1440", 10);
2259
+ margins.left = parseInt(pgMar.getAttribute("w:left") || pgMar.getAttribute("left") || "1440", 10);
2260
+ margins.right = parseInt(pgMar.getAttribute("w:right") || pgMar.getAttribute("right") || "1440", 10);
2261
+ }
2262
+ }
2263
+ const createPageCard = () => {
2264
+ const card = document.createElement("div");
2265
+ card.className = "fp-docx-page-card";
2266
+ card.style.backgroundColor = "#ffffff";
2267
+ card.style.borderRadius = "4px";
2268
+ card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
2269
+ card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
2270
+ card.style.color = "#1e293b";
2271
+ card.style.lineHeight = "1.6";
2272
+ card.style.boxSizing = "border-box";
2273
+ card.style.overflow = "hidden";
2274
+ card.style.position = "relative";
2275
+ card.style.marginBottom = "24px";
2276
+ card.style.width = `${defaultW / 15}px`;
2277
+ card.style.height = `${defaultH / 15}px`;
2278
+ card.style.padding = `${margins.top / 15}px ${margins.right / 15}px ${margins.bottom / 15}px ${margins.left / 15}px`;
2279
+ return card;
2280
+ };
2281
+ let currentCard = createPageCard();
2282
+ let currentHtml = "";
2283
+ const pages = [{ card: currentCard, html: "" }];
2284
+ const flushHtml = () => {
2285
+ pages[pages.length - 1].html += currentHtml;
2286
+ currentHtml = "";
2287
+ };
2288
+ const newPage = () => {
2289
+ flushHtml();
2290
+ currentCard = createPageCard();
2291
+ pages.push({ card: currentCard, html: "" });
2292
+ };
2241
2293
  const body = doc.getElementsByTagNameNS("*", "body")[0] || doc.documentElement;
2242
- let html = "";
2243
2294
  for (const child of Array.from(body.children)) {
2244
2295
  const tag = child.localName || child.nodeName.split(":").pop();
2245
2296
  if (tag === "p") {
2246
2297
  const pStyle = child.getElementsByTagNameNS("*", "pStyle")[0];
2247
2298
  const styleVal = pStyle?.getAttribute("w:val") || pStyle?.getAttribute("val") || "";
2248
2299
  const numPr = child.getElementsByTagNameNS("*", "numPr")[0];
2249
- const textContent = this.extractParagraphHtml(child, imageMap);
2250
- if (!textContent.trim()) {
2251
- html += '<div style="height: 10px;"></div>';
2252
- continue;
2253
- }
2254
- const lowerStyle = styleVal.toLowerCase();
2255
- if (lowerStyle.includes("title")) {
2256
- html += `<h1 style="font-size: 28px; font-weight: 700; color: #1e3a8a; margin: 24px 0 12px; border-bottom: 2px solid #e2e8f0; padding-bottom: 8px;">${textContent}</h1>`;
2257
- } else if (lowerStyle.includes("heading1") || styleVal === "1") {
2258
- html += `<h2 style="font-size: 22px; font-weight: 700; color: #1e40af; margin: 20px 0 10px;">${textContent}</h2>`;
2259
- } else if (lowerStyle.includes("heading2") || styleVal === "2") {
2260
- html += `<h3 style="font-size: 18px; font-weight: 600; color: #2563eb; margin: 16px 0 8px;">${textContent}</h3>`;
2261
- } else if (lowerStyle.includes("heading3") || styleVal === "3") {
2262
- html += `<h4 style="font-size: 15px; font-weight: 600; color: #334155; margin: 12px 0 6px;">${textContent}</h4>`;
2263
- } else if (numPr) {
2264
- html += `<div style="display: flex; gap: 8px; margin: 4px 0 4px 20px;"><span style="color: #2563eb; font-weight: bold;">\u2022</span><span>${textContent}</span></div>`;
2265
- } else {
2266
- html += `<p style="margin: 8px 0; font-size: 14px;">${textContent}</p>`;
2300
+ const chunks = this.extractParagraphChunks(child, imageMap);
2301
+ for (let i = 0; i < chunks.length; i++) {
2302
+ if (i > 0) {
2303
+ newPage();
2304
+ }
2305
+ const textContent = chunks[i];
2306
+ if (!textContent.trim() && !textContent.includes("<img")) {
2307
+ currentHtml += '<div style="height: 10px;"></div>';
2308
+ continue;
2309
+ }
2310
+ const lowerStyle = styleVal.toLowerCase();
2311
+ if (lowerStyle.includes("title")) {
2312
+ 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>`;
2313
+ } else if (lowerStyle.includes("heading1") || styleVal === "1") {
2314
+ currentHtml += `<h2 style="font-size: 22px; font-weight: 700; color: #1e40af; margin: 20px 0 10px;">${textContent}</h2>`;
2315
+ } else if (lowerStyle.includes("heading2") || styleVal === "2") {
2316
+ currentHtml += `<h3 style="font-size: 18px; font-weight: 600; color: #2563eb; margin: 16px 0 8px;">${textContent}</h3>`;
2317
+ } else if (lowerStyle.includes("heading3") || styleVal === "3") {
2318
+ currentHtml += `<h4 style="font-size: 15px; font-weight: 600; color: #334155; margin: 12px 0 6px;">${textContent}</h4>`;
2319
+ } else if (numPr) {
2320
+ 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>`;
2321
+ } else {
2322
+ currentHtml += `<p style="margin: 8px 0; font-size: 14px;">${textContent}</p>`;
2323
+ }
2267
2324
  }
2268
2325
  } else if (tag === "tbl") {
2269
- html += '<table style="width: 100%; border-collapse: collapse; margin: 20px 0; border: 1px solid #cbd5e1;">';
2326
+ currentHtml += '<table style="width: 100%; border-collapse: collapse; margin: 20px 0; border: 1px solid #cbd5e1;">';
2270
2327
  const rows = Array.from(child.getElementsByTagNameNS("*", "tr"));
2271
2328
  rows.forEach((tr, rIdx) => {
2272
- html += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
2329
+ currentHtml += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
2273
2330
  const cells = Array.from(tr.getElementsByTagNameNS("*", "tc"));
2274
2331
  cells.forEach((tc) => {
2275
2332
  const cellText = this.extractParagraphHtml(tc, imageMap);
2276
- html += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || "&nbsp;"}</td>`;
2333
+ currentHtml += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || "&nbsp;"}</td>`;
2277
2334
  });
2278
- html += "</tr>";
2335
+ currentHtml += "</tr>";
2279
2336
  });
2280
- html += "</table>";
2337
+ currentHtml += "</table>";
2281
2338
  }
2282
2339
  }
2283
- card.innerHTML = DOMPurify2__default.default.sanitize(html, {
2284
- ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "s", "strike", "img", "div", "br"],
2285
- ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
2286
- });
2287
- wrapper.appendChild(card);
2340
+ flushHtml();
2341
+ for (const page of pages) {
2342
+ page.card.innerHTML = DOMPurify6__default.default.sanitize(page.html, {
2343
+ ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "s", "strike", "img", "div", "br"],
2344
+ ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
2345
+ });
2346
+ wrapper.appendChild(page.card);
2347
+ }
2288
2348
  }
2289
2349
  extractParagraphHtml(pElement, imageMap = {}) {
2290
- let result = "";
2350
+ return this.extractParagraphChunks(pElement, imageMap).join("<br/>");
2351
+ }
2352
+ extractParagraphChunks(pElement, imageMap = {}) {
2353
+ const chunks = [""];
2354
+ let currentChunkIndex = 0;
2291
2355
  const drawings = Array.from(pElement.getElementsByTagNameNS("*", "drawing"));
2292
2356
  for (const drawing of drawings) {
2293
2357
  const blip = drawing.getElementsByTagNameNS("*", "blip")[0];
2294
2358
  const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
2295
2359
  if (rId && imageMap[rId]) {
2296
- result += `<div style="text-align:center; margin: 12px 0;"><img src="${imageMap[rId]}" style="max-width: 100%; height: auto; border-radius: 4px;" /></div>`;
2360
+ chunks[currentChunkIndex] += `<div style="text-align:center; margin: 12px 0;"><img src="${imageMap[rId]}" style="max-width: 100%; height: auto; border-radius: 4px;" /></div>`;
2297
2361
  }
2298
2362
  }
2299
2363
  const runs = Array.from(pElement.getElementsByTagNameNS("*", "r"));
2300
- if (runs.length === 0 && !result) {
2301
- return DOMPurify2__default.default.sanitize(pElement.textContent || "");
2364
+ if (runs.length === 0 && !chunks[currentChunkIndex]) {
2365
+ chunks[currentChunkIndex] = DOMPurify6__default.default.sanitize(pElement.textContent || "");
2366
+ return chunks;
2302
2367
  }
2303
2368
  for (const r of runs) {
2304
2369
  const blip = r.getElementsByTagNameNS("*", "blip")[0] || r.getElementsByTagNameNS("*", "imagedata")[0];
2305
2370
  const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
2306
2371
  if (rId && imageMap[rId]) {
2307
- result += `<img src="${imageMap[rId]}" style="max-width: 100%; height: auto; display: inline-block; margin: 4px;" />`;
2372
+ chunks[currentChunkIndex] += `<img src="${imageMap[rId]}" style="max-width: 100%; height: auto; display: inline-block; margin: 4px;" />`;
2308
2373
  }
2309
- const brs = r.getElementsByTagNameNS("*", "br");
2310
- for (let i = 0; i < brs.length; i++) {
2311
- result += "<br/>";
2374
+ const brs = Array.from(r.getElementsByTagNameNS("*", "br"));
2375
+ for (const br of brs) {
2376
+ const type = br.getAttribute("w:type") || br.getAttribute("type");
2377
+ if (type === "page") {
2378
+ chunks.push("");
2379
+ currentChunkIndex++;
2380
+ } else {
2381
+ chunks[currentChunkIndex] += "<br/>";
2382
+ }
2312
2383
  }
2313
2384
  const tabs = r.getElementsByTagNameNS("*", "tab");
2314
2385
  if (tabs.length > 0) {
2315
- result += "&emsp;";
2386
+ chunks[currentChunkIndex] += "&emsp;";
2316
2387
  }
2317
2388
  const rPr = r.getElementsByTagNameNS("*", "rPr")[0];
2318
2389
  const isBold = !!rPr?.getElementsByTagNameNS("*", "b")[0];
@@ -2326,7 +2397,7 @@ var DocxPlugin = class {
2326
2397
  const texts = Array.from(r.getElementsByTagNameNS("*", "t"));
2327
2398
  let text = texts.map((t) => t.textContent || "").join("");
2328
2399
  if (!text) continue;
2329
- text = DOMPurify2__default.default.sanitize(text);
2400
+ text = DOMPurify6__default.default.sanitize(text);
2330
2401
  let styles = "";
2331
2402
  if (isBold) styles += "font-weight: bold; ";
2332
2403
  if (isItalic) styles += "font-style: italic; ";
@@ -2338,12 +2409,12 @@ var DocxPlugin = class {
2338
2409
  if (!isNaN(pt) && pt > 0) styles += `font-size: ${pt}pt; `;
2339
2410
  }
2340
2411
  if (styles) {
2341
- result += `<span style="${styles}">${text}</span>`;
2412
+ chunks[currentChunkIndex] += `<span style="${styles}">${text}</span>`;
2342
2413
  } else {
2343
- result += text;
2414
+ chunks[currentChunkIndex] += text;
2344
2415
  }
2345
2416
  }
2346
- return result;
2417
+ return chunks;
2347
2418
  }
2348
2419
  renderBinaryDocFallback(ctx, wrapper) {
2349
2420
  const card = document.createElement("div");
@@ -2360,14 +2431,14 @@ var DocxPlugin = class {
2360
2431
  const wordDocStream = cfbf.readStream("WordDocument");
2361
2432
  if (wordDocStream && wordDocStream.length >= 512) {
2362
2433
  const text2 = this.extractReadableStrings(wordDocStream);
2363
- card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify2__default.default.sanitize(text2)}</div>`;
2434
+ card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6__default.default.sanitize(text2)}</div>`;
2364
2435
  wrapper.appendChild(card);
2365
2436
  return;
2366
2437
  }
2367
2438
  } catch {
2368
2439
  }
2369
2440
  const text = this.extractReadableStrings(new Uint8Array(ctx.buffer));
2370
- card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify2__default.default.sanitize(text)}</div>`;
2441
+ card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6__default.default.sanitize(text)}</div>`;
2371
2442
  wrapper.appendChild(card);
2372
2443
  }
2373
2444
  extractReadableStrings(bytes) {
@@ -2966,41 +3037,94 @@ var CodePlugin = class {
2966
3037
  async render(ctx) {
2967
3038
  const decoder = new TextDecoder("utf-8");
2968
3039
  const fullText = decoder.decode(ctx.buffer);
2969
- const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
2970
- const rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
3040
+ const extRaw = ctx.metadata.extension?.toLowerCase();
3041
+ const mimeRaw = ctx.metadata.mimeType?.toLowerCase();
3042
+ const isTxt = extRaw === ".txt" || mimeRaw === "text/plain" && (!extRaw || !this.extensions.filter((e) => e !== ".txt").includes(extRaw));
3043
+ let rawPages = [];
3044
+ if (isTxt) {
3045
+ const explicitPages = fullText.split(/(?:\f|\x0C)/);
3046
+ for (const ep of explicitPages) {
3047
+ const lines = ep.split(/\r?\n/);
3048
+ let currentChunk = [];
3049
+ for (let i = 0; i < lines.length; i++) {
3050
+ currentChunk.push(lines[i]);
3051
+ if (currentChunk.length >= 46) {
3052
+ rawPages.push(currentChunk.join("\n"));
3053
+ currentChunk = [];
3054
+ }
3055
+ }
3056
+ if (currentChunk.length > 0 || lines.length === 0) {
3057
+ rawPages.push(currentChunk.join("\n"));
3058
+ }
3059
+ }
3060
+ if (rawPages.length === 0) rawPages = [""];
3061
+ } else {
3062
+ const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
3063
+ rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
3064
+ }
2971
3065
  const totalPages = Math.max(1, rawPages.length);
2972
3066
  let currentPage = 1;
2973
3067
  const container = document.createElement("div");
2974
3068
  container.style.width = "100%";
2975
3069
  container.style.height = "100%";
2976
3070
  container.style.overflow = "auto";
2977
- container.style.backgroundColor = "#1e1e1e";
2978
- container.style.color = "#d4d4d4";
2979
- container.style.padding = "16px";
2980
- container.style.boxSizing = "border-box";
2981
3071
  let fontSize = 13;
2982
3072
  let rotation = 0;
3073
+ let zoomLevel = 1;
2983
3074
  const pre = document.createElement("pre");
2984
- pre.style.margin = "0";
2985
- pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
2986
- pre.style.fontSize = `${fontSize}px`;
2987
- pre.style.lineHeight = "1.5";
2988
- pre.style.whiteSpace = "pre-wrap";
2989
- pre.style.wordBreak = "break-all";
2990
3075
  const code = document.createElement("code");
3076
+ if (isTxt) {
3077
+ container.style.backgroundColor = "#f1f5f9";
3078
+ container.style.padding = "32px";
3079
+ container.style.boxSizing = "border-box";
3080
+ container.style.display = "flex";
3081
+ container.style.flexDirection = "column";
3082
+ container.style.alignItems = "center";
3083
+ pre.style.margin = "0";
3084
+ pre.style.fontFamily = "Consolas, 'Courier New', monospace";
3085
+ pre.style.fontSize = "13px";
3086
+ pre.style.color = "#1e293b";
3087
+ pre.style.lineHeight = "1.5";
3088
+ pre.style.whiteSpace = "pre-wrap";
3089
+ pre.style.wordBreak = "break-word";
3090
+ pre.style.backgroundColor = "#ffffff";
3091
+ pre.style.width = "816px";
3092
+ pre.style.minHeight = "1056px";
3093
+ pre.style.padding = "72px 56px";
3094
+ pre.style.boxSizing = "border-box";
3095
+ pre.style.boxShadow = "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)";
3096
+ pre.style.borderRadius = "4px";
3097
+ pre.style.transformOrigin = "top center";
3098
+ } else {
3099
+ container.style.backgroundColor = "#1e1e1e";
3100
+ container.style.color = "#d4d4d4";
3101
+ container.style.padding = "16px";
3102
+ container.style.boxSizing = "border-box";
3103
+ pre.style.margin = "0";
3104
+ pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
3105
+ pre.style.fontSize = `${fontSize}px`;
3106
+ pre.style.lineHeight = "1.5";
3107
+ pre.style.whiteSpace = "pre-wrap";
3108
+ pre.style.wordBreak = "break-all";
3109
+ pre.style.transformOrigin = "top left";
3110
+ }
2991
3111
  const ext = (ctx.metadata.extension || "").replace(".", "");
2992
3112
  const renderCodePage = (text) => {
2993
- try {
2994
- if (ext && hljs__default.default.getLanguage(ext)) {
2995
- code.innerHTML = hljs__default.default.highlight(text, { language: ext }).value;
2996
- } else {
2997
- code.innerHTML = hljs__default.default.highlightAuto(text).value;
2998
- }
2999
- } catch {
3113
+ if (isTxt) {
3000
3114
  code.textContent = text;
3115
+ } else {
3116
+ try {
3117
+ if (ext && hljs__default.default.getLanguage(ext)) {
3118
+ code.innerHTML = hljs__default.default.highlight(text, { language: ext }).value;
3119
+ } else {
3120
+ code.innerHTML = hljs__default.default.highlightAuto(text).value;
3121
+ }
3122
+ } catch {
3123
+ code.textContent = text;
3124
+ }
3001
3125
  }
3002
3126
  };
3003
- renderCodePage(rawPages[0] || fullText);
3127
+ renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
3004
3128
  pre.appendChild(code);
3005
3129
  container.appendChild(pre);
3006
3130
  let indicator = null;
@@ -3009,15 +3133,22 @@ var CodePlugin = class {
3009
3133
  indicator.className = "fp-code-page-indicator";
3010
3134
  indicator.style.position = "sticky";
3011
3135
  indicator.style.bottom = "16px";
3012
- indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
3013
- indicator.style.backdropFilter = "blur(8px)";
3014
- indicator.style.color = "#f8fafc";
3136
+ if (isTxt) {
3137
+ indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
3138
+ indicator.style.color = "#334155";
3139
+ indicator.style.border = "1px solid #e2e8f0";
3140
+ indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
3141
+ } else {
3142
+ indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
3143
+ indicator.style.color = "#f8fafc";
3144
+ indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
3145
+ indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
3146
+ indicator.style.backdropFilter = "blur(8px)";
3147
+ }
3015
3148
  indicator.style.fontSize = "12px";
3016
3149
  indicator.style.fontWeight = "600";
3017
3150
  indicator.style.padding = "5px 14px";
3018
3151
  indicator.style.borderRadius = "20px";
3019
- indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
3020
- indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
3021
3152
  indicator.style.zIndex = "10";
3022
3153
  indicator.style.userSelect = "none";
3023
3154
  indicator.style.pointerEvents = "none";
@@ -3028,7 +3159,7 @@ var CodePlugin = class {
3028
3159
  }
3029
3160
  const showPage = (pageNum) => {
3030
3161
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
3031
- renderCodePage(rawPages[currentPage - 1] || fullText);
3162
+ renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
3032
3163
  if (indicator) {
3033
3164
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
3034
3165
  }
@@ -3044,39 +3175,57 @@ var CodePlugin = class {
3044
3175
  ctx.container.innerHTML = "";
3045
3176
  };
3046
3177
  ctx.signal.addEventListener("abort", cleanup);
3178
+ const updateTransform = () => {
3179
+ if (isTxt) {
3180
+ pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
3181
+ } else {
3182
+ pre.style.transform = `rotate(${rotation}deg)`;
3183
+ pre.style.fontSize = `${fontSize}px`;
3184
+ }
3185
+ };
3047
3186
  return {
3048
3187
  destroy: cleanup,
3049
3188
  getPageCount: () => totalPages,
3050
3189
  getCurrentPage: () => currentPage,
3051
3190
  goToPage: (page) => showPage(page),
3052
3191
  zoomIn: () => {
3053
- fontSize = Math.min(32, fontSize + 2);
3054
- pre.style.fontSize = `${fontSize}px`;
3192
+ if (isTxt) {
3193
+ zoomLevel = Math.min(3, zoomLevel + 0.1);
3194
+ } else {
3195
+ fontSize = Math.min(32, fontSize + 2);
3196
+ }
3197
+ updateTransform();
3055
3198
  },
3056
3199
  zoomOut: () => {
3057
- fontSize = Math.max(8, fontSize - 2);
3058
- pre.style.fontSize = `${fontSize}px`;
3200
+ if (isTxt) {
3201
+ zoomLevel = Math.max(0.1, zoomLevel - 0.1);
3202
+ } else {
3203
+ fontSize = Math.max(8, fontSize - 2);
3204
+ }
3205
+ updateTransform();
3059
3206
  },
3060
- getZoom: () => fontSize / 13,
3207
+ getZoom: () => isTxt ? zoomLevel : fontSize / 13,
3061
3208
  setZoom: (level) => {
3062
- fontSize = Math.round(13 * level);
3063
- pre.style.fontSize = `${fontSize}px`;
3209
+ if (isTxt) {
3210
+ zoomLevel = level;
3211
+ } else {
3212
+ fontSize = Math.round(13 * level);
3213
+ }
3214
+ updateTransform();
3064
3215
  },
3065
3216
  fitToPage: () => {
3066
3217
  fontSize = 13;
3067
3218
  rotation = 0;
3068
- pre.style.fontSize = "13px";
3069
- pre.style.transform = "none";
3219
+ zoomLevel = 1;
3220
+ updateTransform();
3070
3221
  },
3071
3222
  rotateCW: () => {
3072
3223
  rotation = (rotation + 90) % 360;
3073
- pre.style.transform = `rotate(${rotation}deg)`;
3074
- pre.style.transformOrigin = "top left";
3224
+ updateTransform();
3075
3225
  },
3076
3226
  rotateCCW: () => {
3077
3227
  rotation = (rotation - 90 + 360) % 360;
3078
- pre.style.transform = `rotate(${rotation}deg)`;
3079
- pre.style.transformOrigin = "top left";
3228
+ updateTransform();
3080
3229
  },
3081
3230
  download: () => {
3082
3231
  const mimeType = ctx.metadata.mimeType || "text/plain";
@@ -3375,7 +3524,7 @@ var MarkdownPlugin = class {
3375
3524
  gfm: true,
3376
3525
  breaks: true
3377
3526
  });
3378
- const cleanHtml = DOMPurify2__default.default.sanitize(rawHtml, {
3527
+ const cleanHtml = DOMPurify6__default.default.sanitize(rawHtml, {
3379
3528
  USE_PROFILES: { html: true }
3380
3529
  });
3381
3530
  const wrapper = document.createElement("div");
@@ -4011,6 +4160,14 @@ var RtfPlugin = class {
4011
4160
  group: "actions",
4012
4161
  execute: () => instance.download?.()
4013
4162
  },
4163
+ {
4164
+ id: "copy",
4165
+ icon: "copy",
4166
+ label: "Copy Text",
4167
+ type: "button",
4168
+ group: "actions",
4169
+ execute: () => instance.copy?.()
4170
+ },
4014
4171
  {
4015
4172
  id: "print",
4016
4173
  icon: "print",
@@ -4072,14 +4229,31 @@ var RtfPlugin = class {
4072
4229
  } catch (err) {
4073
4230
  console.warn("[RtfPlugin] RTF render error, fallback text:", err);
4074
4231
  const text = new TextDecoder("latin1").decode(ctx.buffer);
4075
- const clean = text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "");
4076
- const pre = document.createElement("pre");
4077
- pre.style.whiteSpace = "pre-wrap";
4078
- pre.style.fontFamily = "serif";
4079
- pre.style.color = "#333";
4080
- pre.textContent = clean;
4081
- wrapper.appendChild(pre);
4082
- pageElements = [pre];
4232
+ const rawPages = text.split(/\\page\b/).map((segment) => {
4233
+ return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
4234
+ }).filter((p) => p.length > 0);
4235
+ const pages = rawPages.length > 0 ? rawPages : [text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim()];
4236
+ for (let i = 0; i < pages.length; i++) {
4237
+ const pageCard = document.createElement("div");
4238
+ pageCard.className = "fp-rtf-page-card";
4239
+ pageCard.style.backgroundColor = "#ffffff";
4240
+ pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
4241
+ pageCard.style.borderRadius = "4px";
4242
+ pageCard.style.padding = "72px 56px";
4243
+ pageCard.style.width = "816px";
4244
+ pageCard.style.minHeight = "1056px";
4245
+ pageCard.style.maxWidth = "100%";
4246
+ pageCard.style.boxSizing = "border-box";
4247
+ pageCard.style.fontFamily = "serif";
4248
+ pageCard.style.fontSize = "12pt";
4249
+ pageCard.style.lineHeight = "1.6";
4250
+ pageCard.style.color = "#1e293b";
4251
+ pageCard.style.whiteSpace = "pre-wrap";
4252
+ pageCard.style.display = i === 0 ? "block" : "none";
4253
+ pageCard.textContent = pages[i];
4254
+ wrapper.appendChild(pageCard);
4255
+ pageElements.push(pageCard);
4256
+ }
4083
4257
  }
4084
4258
  const totalPages = Math.max(1, pageElements.length);
4085
4259
  let currentPage = 1;
@@ -4167,6 +4341,10 @@ var RtfPlugin = class {
4167
4341
  a.click();
4168
4342
  URL.revokeObjectURL(url);
4169
4343
  },
4344
+ copy: () => {
4345
+ const text = wrapper.textContent || "";
4346
+ navigator.clipboard?.writeText(text);
4347
+ },
4170
4348
  print: () => {
4171
4349
  window.print();
4172
4350
  }
@@ -4241,7 +4419,7 @@ var HtmlPreviewPlugin = class {
4241
4419
  }
4242
4420
  async render(ctx) {
4243
4421
  const rawHtml = new TextDecoder("utf-8").decode(ctx.buffer);
4244
- const sanitized = DOMPurify2__default.default.sanitize(rawHtml, {
4422
+ const sanitized = DOMPurify6__default.default.sanitize(rawHtml, {
4245
4423
  WHOLE_DOCUMENT: true,
4246
4424
  ADD_TAGS: ["style", "link"],
4247
4425
  ADD_ATTR: ["target", "rel"]
@@ -4507,14 +4685,97 @@ var OpenDocumentPlugin = class {
4507
4685
  wrapper.textContent = contentDoc.documentElement.textContent || "Formula content";
4508
4686
  }
4509
4687
  } else {
4510
- wrapper.style.maxWidth = "850px";
4511
- wrapper.style.padding = "48px";
4688
+ wrapper.style.maxWidth = "none";
4689
+ wrapper.style.padding = "0";
4512
4690
  wrapper.style.minHeight = "100%";
4691
+ wrapper.style.backgroundColor = "transparent";
4692
+ wrapper.style.boxShadow = "none";
4693
+ wrapper.style.position = "relative";
4694
+ const dims = this.getPageDimensions(stylesDoc, contentDoc);
4513
4695
  const bodyHtml = this.renderOdfBody(contentDoc, styleMap, imageUrls);
4514
- wrapper.innerHTML = DOMPurify2__default.default.sanitize(bodyHtml, {
4515
- ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub"],
4696
+ const tempDiv = document.createElement("div");
4697
+ tempDiv.style.width = `${dims.width - dims.marginLeft - dims.marginRight}px`;
4698
+ tempDiv.style.position = "absolute";
4699
+ tempDiv.style.visibility = "hidden";
4700
+ tempDiv.innerHTML = DOMPurify6__default.default.sanitize(bodyHtml, {
4701
+ ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub", "hr"],
4516
4702
  ADD_ATTR: ["style", "colspan", "rowspan"]
4517
4703
  });
4704
+ document.body.appendChild(tempDiv);
4705
+ const contentHeight = dims.height - dims.marginTop - dims.marginBottom;
4706
+ const pageElements = [[]];
4707
+ let currentHeight = 0;
4708
+ let currentPageIdx = 0;
4709
+ Array.from(tempDiv.children).forEach((child) => {
4710
+ const el = child;
4711
+ const style = el.getAttribute("style") || "";
4712
+ const isBreakBefore = style.includes("page-break-before: always");
4713
+ const isBreakAfter = style.includes("page-break-after: always");
4714
+ const isSoftBreak = el.classList.contains("odf-page-break");
4715
+ if (isBreakBefore) {
4716
+ if (pageElements[currentPageIdx].length > 0) {
4717
+ currentPageIdx++;
4718
+ pageElements.push([]);
4719
+ currentHeight = 0;
4720
+ }
4721
+ }
4722
+ const h = el.offsetHeight || 0;
4723
+ if (currentHeight + h > contentHeight && pageElements[currentPageIdx].length > 0 && !isSoftBreak) {
4724
+ currentPageIdx++;
4725
+ pageElements.push([]);
4726
+ currentHeight = 0;
4727
+ }
4728
+ if (!isSoftBreak) {
4729
+ pageElements[currentPageIdx].push(el.cloneNode(true));
4730
+ currentHeight += h;
4731
+ }
4732
+ if (isBreakAfter || isSoftBreak) {
4733
+ currentPageIdx++;
4734
+ pageElements.push([]);
4735
+ currentHeight = 0;
4736
+ }
4737
+ });
4738
+ document.body.removeChild(tempDiv);
4739
+ if (pageElements.length > 1 && pageElements[pageElements.length - 1].length === 0) {
4740
+ pageElements.pop();
4741
+ }
4742
+ totalPages = Math.max(1, pageElements.length);
4743
+ pageElements.forEach((elements, idx) => {
4744
+ const page = document.createElement("div");
4745
+ page.className = `fp-odt-page fp-odt-page-${idx + 1}`;
4746
+ page.style.width = `${dims.width}px`;
4747
+ page.style.minHeight = `${dims.height}px`;
4748
+ page.style.padding = `${dims.marginTop}px ${dims.marginRight}px ${dims.marginBottom}px ${dims.marginLeft}px`;
4749
+ page.style.margin = "0 auto";
4750
+ page.style.backgroundColor = "#ffffff";
4751
+ page.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
4752
+ page.style.borderRadius = "4px";
4753
+ page.style.boxSizing = "border-box";
4754
+ page.style.display = idx === 0 ? "block" : "none";
4755
+ page.style.position = "absolute";
4756
+ page.style.top = "0";
4757
+ page.style.left = "50%";
4758
+ page.style.transform = "translateX(-50%)";
4759
+ elements.forEach((el) => page.appendChild(el));
4760
+ wrapper.appendChild(page);
4761
+ slides.push(page);
4762
+ });
4763
+ const pageIndicator = document.createElement("div");
4764
+ pageIndicator.className = "fp-odt-page-indicator";
4765
+ pageIndicator.style.position = "sticky";
4766
+ pageIndicator.style.bottom = "16px";
4767
+ pageIndicator.style.left = "50%";
4768
+ pageIndicator.style.transform = "translateX(-50%)";
4769
+ pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
4770
+ pageIndicator.style.color = "#fff";
4771
+ pageIndicator.style.padding = "6px 12px";
4772
+ pageIndicator.style.borderRadius = "16px";
4773
+ pageIndicator.style.fontSize = "12px";
4774
+ pageIndicator.style.zIndex = "100";
4775
+ pageIndicator.style.display = "inline-block";
4776
+ pageIndicator.style.width = "fit-content";
4777
+ pageIndicator.textContent = `Page 1 of ${totalPages}`;
4778
+ container.appendChild(pageIndicator);
4518
4779
  }
4519
4780
  const cleanup = () => {
4520
4781
  imageUrls.forEach((url) => URL.revokeObjectURL(url));
@@ -4523,11 +4784,15 @@ var OpenDocumentPlugin = class {
4523
4784
  };
4524
4785
  ctx.signal.addEventListener("abort", cleanup);
4525
4786
  const goToPage = (page) => {
4526
- if (!isPresentation || page < 1 || page > totalPages) return;
4787
+ if (page < 1 || page > totalPages) return;
4527
4788
  currentPage = page;
4528
4789
  slides.forEach((s, idx) => {
4529
4790
  s.style.display = idx === page - 1 ? "block" : "none";
4530
4791
  });
4792
+ const indicator = container.querySelector(".fp-odt-page-indicator");
4793
+ if (indicator) {
4794
+ indicator.textContent = `Page ${currentPage} of ${totalPages}`;
4795
+ }
4531
4796
  ctx.emit("page-change", { page: currentPage, total: totalPages });
4532
4797
  };
4533
4798
  return {
@@ -4596,6 +4861,43 @@ var OpenDocumentPlugin = class {
4596
4861
  }
4597
4862
  };
4598
4863
  }
4864
+ getPageDimensions(stylesDoc, contentDoc) {
4865
+ let width = 850;
4866
+ let height = 1123;
4867
+ let marginTop = 48;
4868
+ let marginBottom = 48;
4869
+ let marginLeft = 48;
4870
+ let marginRight = 48;
4871
+ const parseUnit = (val) => {
4872
+ if (!val) return null;
4873
+ if (val.endsWith("cm")) return parseFloat(val) * 37.8;
4874
+ if (val.endsWith("mm")) return parseFloat(val) * 3.78;
4875
+ if (val.endsWith("in")) return parseFloat(val) * 96;
4876
+ if (val.endsWith("pt")) return parseFloat(val) * 1.33;
4877
+ if (val.endsWith("px")) return parseFloat(val);
4878
+ return parseFloat(val);
4879
+ };
4880
+ const docs = [stylesDoc, contentDoc].filter(Boolean);
4881
+ for (const doc of docs) {
4882
+ const pageLayout = doc.querySelector("page-layout-properties, [page-width]");
4883
+ if (pageLayout) {
4884
+ const w = parseUnit(pageLayout.getAttribute("fo:page-width") || pageLayout.getAttribute("page-width"));
4885
+ const h = parseUnit(pageLayout.getAttribute("fo:page-height") || pageLayout.getAttribute("page-height"));
4886
+ const mt = parseUnit(pageLayout.getAttribute("fo:margin-top") || pageLayout.getAttribute("margin-top"));
4887
+ const mb = parseUnit(pageLayout.getAttribute("fo:margin-bottom") || pageLayout.getAttribute("margin-bottom"));
4888
+ const ml = parseUnit(pageLayout.getAttribute("fo:margin-left") || pageLayout.getAttribute("margin-left"));
4889
+ const mr = parseUnit(pageLayout.getAttribute("fo:margin-right") || pageLayout.getAttribute("margin-right"));
4890
+ if (w !== null) width = w;
4891
+ if (h !== null) height = h;
4892
+ if (mt !== null) marginTop = mt;
4893
+ if (mb !== null) marginBottom = mb;
4894
+ if (ml !== null) marginLeft = ml;
4895
+ if (mr !== null) marginRight = mr;
4896
+ break;
4897
+ }
4898
+ }
4899
+ return { width, height, marginTop, marginBottom, marginLeft, marginRight };
4900
+ }
4599
4901
  extractStyles(stylesDoc, contentDoc) {
4600
4902
  const map = /* @__PURE__ */ new Map();
4601
4903
  const styleNodes = [];
@@ -4618,14 +4920,21 @@ var OpenDocumentPlugin = class {
4618
4920
  if (color) css += `color: ${color}; `;
4619
4921
  if (size) css += `font-size: ${size}; `;
4620
4922
  }
4621
- const paraProp = node.querySelector("paragraph-properties, [text-align]");
4923
+ let paraProp = node.querySelector("paragraph-properties, [text-align]");
4924
+ if (!paraProp) {
4925
+ paraProp = Array.from(node.children).find((c) => c.tagName.includes("paragraph-properties")) || null;
4926
+ }
4622
4927
  if (paraProp) {
4623
4928
  const align = paraProp.getAttribute("fo:text-align") || paraProp.getAttribute("text-align");
4624
4929
  const mt = paraProp.getAttribute("fo:margin-top") || paraProp.getAttribute("margin-top");
4625
4930
  const mb = paraProp.getAttribute("fo:margin-bottom") || paraProp.getAttribute("margin-bottom");
4931
+ const breakBefore = paraProp.getAttribute("fo:break-before") || paraProp.getAttribute("break-before");
4932
+ const breakAfter = paraProp.getAttribute("fo:break-after") || paraProp.getAttribute("break-after");
4626
4933
  if (align) css += `text-align: ${align}; `;
4627
4934
  if (mt) css += `margin-top: ${mt}; `;
4628
4935
  if (mb) css += `margin-bottom: ${mb}; `;
4936
+ if (breakBefore === "page") css += "page-break-before: always; ";
4937
+ if (breakAfter === "page") css += "page-break-after: always; ";
4629
4938
  }
4630
4939
  if (css) map.set(name, css);
4631
4940
  }
@@ -4710,6 +5019,8 @@ var OpenDocumentPlugin = class {
4710
5019
  result += "&emsp;";
4711
5020
  } else if (tag === "line-break") {
4712
5021
  result += "<br/>";
5022
+ } else if (tag === "soft-page-break") {
5023
+ result += '<hr class="odf-page-break" style="page-break-after: always; border: none; margin: 0; padding: 0; height: 0;" />';
4713
5024
  } else {
4714
5025
  result += el.textContent || "";
4715
5026
  }
@@ -4870,20 +5181,9 @@ var DocPlugin = class {
4870
5181
  container.style.overflow = "auto";
4871
5182
  container.style.padding = "32px 16px";
4872
5183
  container.style.backgroundColor = "#f1f5f9";
4873
- const wrapper = document.createElement("div");
4874
- wrapper.className = "fp-doc-wrapper";
4875
- wrapper.style.maxWidth = "850px";
4876
- wrapper.style.margin = "0 auto";
4877
- wrapper.style.backgroundColor = "#ffffff";
4878
- wrapper.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
4879
- wrapper.style.borderRadius = "4px";
4880
- wrapper.style.padding = "56px 48px";
4881
- wrapper.style.minHeight = "100%";
4882
- wrapper.style.transformOrigin = "top center";
4883
- wrapper.style.transition = "transform 0.2s ease";
4884
- wrapper.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
4885
- wrapper.style.color = "#1e293b";
4886
- container.appendChild(wrapper);
5184
+ container.style.display = "flex";
5185
+ container.style.justifyContent = "center";
5186
+ container.style.alignItems = "flex-start";
4887
5187
  ctx.container.appendChild(container);
4888
5188
  let scale = 1;
4889
5189
  let extractedRawText = "";
@@ -4910,21 +5210,27 @@ var DocPlugin = class {
4910
5210
  const rawPages = this.splitIntoPages(extractedRawText);
4911
5211
  const totalPages = Math.max(1, rawPages.length);
4912
5212
  let currentPage = 1;
4913
- wrapper.innerHTML = "";
4914
5213
  const pageCards = [];
4915
5214
  for (let i = 0; i < totalPages; i++) {
4916
5215
  const pageCard = document.createElement("div");
4917
5216
  pageCard.className = "fp-doc-page-card";
5217
+ pageCard.style.width = "816px";
5218
+ pageCard.style.height = "1056px";
4918
5219
  pageCard.style.backgroundColor = "#ffffff";
4919
5220
  pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
4920
5221
  pageCard.style.borderRadius = "4px";
4921
- pageCard.style.padding = "56px 48px";
4922
- pageCard.style.minHeight = "100%";
5222
+ pageCard.style.padding = "96px 72px";
5223
+ pageCard.style.boxSizing = "border-box";
5224
+ pageCard.style.overflow = "hidden";
4923
5225
  pageCard.style.display = i === 0 ? "block" : "none";
5226
+ pageCard.style.transformOrigin = "top center";
5227
+ pageCard.style.transition = "transform 0.2s ease";
5228
+ pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5229
+ pageCard.style.color = "#1e293b";
4924
5230
  if (isFallback && i === 0) {
4925
5231
  pageCard.innerHTML = `
4926
5232
  <div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
4927
- <h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify2__default.default.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
5233
+ <h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify6__default.default.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
4928
5234
  <span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
4929
5235
  </div>
4930
5236
  ${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
@@ -4932,15 +5238,17 @@ var DocPlugin = class {
4932
5238
  } else {
4933
5239
  pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
4934
5240
  }
4935
- wrapper.appendChild(pageCard);
5241
+ container.appendChild(pageCard);
4936
5242
  pageCards.push(pageCard);
4937
5243
  }
4938
5244
  let indicator = null;
4939
5245
  if (totalPages > 1) {
4940
5246
  indicator = document.createElement("div");
4941
5247
  indicator.className = "fp-doc-page-indicator";
4942
- indicator.style.position = "sticky";
5248
+ indicator.style.position = "fixed";
4943
5249
  indicator.style.bottom = "16px";
5250
+ indicator.style.left = "50%";
5251
+ indicator.style.transform = "translateX(-50%)";
4944
5252
  indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
4945
5253
  indicator.style.backdropFilter = "blur(8px)";
4946
5254
  indicator.style.color = "#f8fafc";
@@ -4954,17 +5262,25 @@ var DocPlugin = class {
4954
5262
  indicator.style.userSelect = "none";
4955
5263
  indicator.style.pointerEvents = "none";
4956
5264
  indicator.style.textAlign = "center";
4957
- indicator.style.width = "fit-content";
4958
- indicator.style.margin = "16px auto 0";
4959
5265
  container.appendChild(indicator);
4960
5266
  }
5267
+ let rotation = 0;
5268
+ const applyTransform = () => {
5269
+ const activeCard = pageCards[currentPage - 1];
5270
+ if (activeCard) {
5271
+ activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5272
+ }
5273
+ };
4961
5274
  const showPage = (pageNum) => {
4962
5275
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
4963
- if (totalPages > 1) {
4964
- pageCards.forEach((card, idx) => {
4965
- card.style.display = idx + 1 === currentPage ? "block" : "none";
4966
- });
4967
- }
5276
+ pageCards.forEach((card, idx) => {
5277
+ if (idx + 1 === currentPage) {
5278
+ card.style.display = "block";
5279
+ card.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5280
+ } else {
5281
+ card.style.display = "none";
5282
+ }
5283
+ });
4968
5284
  if (indicator) {
4969
5285
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
4970
5286
  }
@@ -4973,19 +5289,13 @@ var DocPlugin = class {
4973
5289
  if (totalPages > 1) {
4974
5290
  showPage(1);
4975
5291
  }
4976
- let rotation = 0;
4977
5292
  const calculateFitScale = () => {
4978
- const activeCard = pageCards[currentPage - 1] || wrapper;
4979
- const elW = activeCard.offsetWidth || 850;
4980
- const elH = activeCard.offsetHeight || 1e3;
5293
+ const elW = 816;
5294
+ const elH = 1056;
4981
5295
  const availW = Math.max(200, ctx.container.clientWidth - 48);
4982
5296
  const availH = Math.max(200, ctx.container.clientHeight - 80);
4983
5297
  return Math.min(1.1, Math.min(availW / elW, availH / elH));
4984
5298
  };
4985
- const applyTransform = () => {
4986
- wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
4987
- wrapper.style.transformOrigin = "top center";
4988
- };
4989
5299
  setTimeout(() => {
4990
5300
  scale = calculateFitScale();
4991
5301
  applyTransform();
@@ -5143,8 +5453,28 @@ var DocPlugin = class {
5143
5453
  }
5144
5454
  splitIntoPages(text) {
5145
5455
  if (!text) return [""];
5146
- const parts = text.split(/[\x0C\f]|\r?\n\s*[-=_]{3,}\s*(?:PAGE|Page|page break)[\s\d\w-]*[-=_]{3,}\s*\r?\n/i).map((p) => p.trim()).filter((p) => p.length > 0);
5147
- return parts.length > 0 ? parts : [text];
5456
+ 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);
5457
+ if (explicitParts.length === 0) explicitParts.push(text);
5458
+ const maxLinesPerPage = 48;
5459
+ const finalPages = [];
5460
+ for (const part of explicitParts) {
5461
+ const lines = part.split(/\r?\n/);
5462
+ let currentLines = [];
5463
+ let count = 0;
5464
+ for (const line of lines) {
5465
+ currentLines.push(line);
5466
+ count++;
5467
+ if (count >= maxLinesPerPage) {
5468
+ finalPages.push(currentLines.join("\n"));
5469
+ currentLines = [];
5470
+ count = 0;
5471
+ }
5472
+ }
5473
+ if (currentLines.length > 0) {
5474
+ finalPages.push(currentLines.join("\n"));
5475
+ }
5476
+ }
5477
+ return finalPages.length > 0 ? finalPages : [text];
5148
5478
  }
5149
5479
  /**
5150
5480
  * Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
@@ -5153,17 +5483,65 @@ var DocPlugin = class {
5153
5483
  const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
5154
5484
  let html = "";
5155
5485
  let inList = false;
5156
- for (const rawLine of lines) {
5157
- const line = rawLine.trim();
5486
+ let tableLines = [];
5487
+ const flushTable = () => {
5488
+ if (tableLines.length > 0) {
5489
+ html += '<table style="width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 12px;">';
5490
+ for (const tLine of tableLines) {
5491
+ html += "<tr>";
5492
+ const cols = tLine.split(" ");
5493
+ for (const col of cols) {
5494
+ html += `<td style="border: 1px solid #cbd5e1; padding: 6px 8px;">${DOMPurify6__default.default.sanitize(col.trim())}</td>`;
5495
+ }
5496
+ html += "</tr>";
5497
+ }
5498
+ html += "</table>";
5499
+ tableLines = [];
5500
+ }
5501
+ };
5502
+ let i = 0;
5503
+ while (i < lines.length) {
5504
+ let line = lines[i];
5505
+ let tabCount = (line.match(/\t/g) || []).length;
5506
+ if (tabCount > 0) {
5507
+ let consecutiveTableLines = 1;
5508
+ let j = i + 1;
5509
+ while (j < lines.length) {
5510
+ const nextTabCount = (lines[j].match(/\t/g) || []).length;
5511
+ if (nextTabCount === tabCount) {
5512
+ consecutiveTableLines++;
5513
+ j++;
5514
+ } else {
5515
+ break;
5516
+ }
5517
+ }
5518
+ if (consecutiveTableLines >= 3) {
5519
+ if (inList) {
5520
+ html += "</ul>";
5521
+ inList = false;
5522
+ }
5523
+ tableLines = lines.slice(i, j);
5524
+ flushTable();
5525
+ i = j;
5526
+ continue;
5527
+ }
5528
+ }
5529
+ line = line.trim();
5158
5530
  if (!line) {
5159
5531
  if (inList) {
5160
5532
  html += "</ul>";
5161
5533
  inList = false;
5162
5534
  }
5535
+ html += '<div style="height: 1.15em;"></div>';
5536
+ i++;
5537
+ continue;
5538
+ }
5539
+ if (/^[\x00-\x1F\x7F-\x9F]+$/.test(line)) {
5540
+ i++;
5163
5541
  continue;
5164
5542
  }
5165
- if (/^[\x00-\x1F\x7F-\x9F]+$/.test(line)) continue;
5166
- if (line.includes("Normal.dot") || line.includes("Microsoft Word") || line.includes("Times New Roman") && line.length < 30) {
5543
+ if ((line.includes("Normal.dot") || line.includes("Microsoft Word") || line.includes("Times New Roman")) && line.length < 30) {
5544
+ i++;
5167
5545
  continue;
5168
5546
  }
5169
5547
  if (line.length < 60 && !line.endsWith(".") && (/^[A-Z0-9\s:_-]+$/.test(line) || line.startsWith("#"))) {
@@ -5171,24 +5549,26 @@ var DocPlugin = class {
5171
5549
  html += "</ul>";
5172
5550
  inList = false;
5173
5551
  }
5174
- html += `<h2 style="font-size: 18px; font-weight: 700; color: #1e3a8a; margin: 20px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify2__default.default.sanitize(line)}</h2>`;
5552
+ html += `<h2 style="font-size: 16px; font-weight: 700; color: #1e3a8a; margin: 16px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify6__default.default.sanitize(line)}</h2>`;
5175
5553
  } else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
5176
5554
  if (!inList) {
5177
5555
  html += '<ul style="margin: 8px 0; padding-left: 24px;">';
5178
5556
  inList = true;
5179
5557
  }
5180
5558
  const bulletText = line.replace(/^[•\-\*]\s*/, "");
5181
- html += `<li style="margin: 4px 0; line-height: 1.6;">${DOMPurify2__default.default.sanitize(bulletText)}</li>`;
5559
+ html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6__default.default.sanitize(bulletText)}</li>`;
5182
5560
  } else {
5183
5561
  if (inList) {
5184
5562
  html += "</ul>";
5185
5563
  inList = false;
5186
5564
  }
5187
- html += `<p style="line-height: 1.7; margin: 10px 0; font-size: 14px; text-align: justify;">${DOMPurify2__default.default.sanitize(line)}</p>`;
5565
+ html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6__default.default.sanitize(line)}</p>`;
5188
5566
  }
5567
+ i++;
5189
5568
  }
5190
5569
  if (inList) html += "</ul>";
5191
- return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify2__default.default.sanitize(filename)})</p>`;
5570
+ flushTable();
5571
+ return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify6__default.default.sanitize(filename)})</p>`;
5192
5572
  }
5193
5573
  };
5194
5574
  function docPlugin() {
@@ -5366,7 +5746,7 @@ var PptPlugin = class {
5366
5746
  if (s.pictureUrl) {
5367
5747
  contentHtml = `
5368
5748
  <div style="flex: 1; display: flex; justify-content: center; align-items: center; padding: 12px; overflow: hidden;">
5369
- <img src="${s.pictureUrl}" alt="${DOMPurify2__default.default.sanitize(s.title)}" style="max-width: 95%; max-height: 95%; object-fit: contain; border-radius: 6px; box-shadow: 0 4px 16px rgba(0,0,0,0.1); background: #ffffff;" />
5749
+ <img src="${s.pictureUrl}" alt="${DOMPurify6__default.default.sanitize(s.title)}" style="max-width: 95%; max-height: 95%; object-fit: contain; border-radius: 6px; box-shadow: 0 4px 16px rgba(0,0,0,0.1); background: #ffffff;" />
5370
5750
  </div>
5371
5751
  `;
5372
5752
  } else if (s.tableColumns.length > 0) {
@@ -5376,7 +5756,7 @@ var PptPlugin = class {
5376
5756
  <table style="width: 100%; border-collapse: collapse; border: 1px solid #cbd5e1; border-radius: 6px; overflow: hidden; background: #ffffff;">
5377
5757
  <thead>
5378
5758
  <tr style="background: #e2e8f0; color: #1e293b; font-weight: 600; font-size: 14px;">
5379
- ${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify2__default.default.sanitize(c)}</th>`).join("")}
5759
+ ${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify6__default.default.sanitize(c)}</th>`).join("")}
5380
5760
  </tr>
5381
5761
  </thead>
5382
5762
  <tbody>
@@ -5392,7 +5772,7 @@ var PptPlugin = class {
5392
5772
  } else {
5393
5773
  const pTags = s.paragraphs.map((p) => {
5394
5774
  const lines = p.split(/[\r\n]+/).map((l) => l.trim()).filter(Boolean);
5395
- return lines.map((l) => `<p style="margin: 0 0 14px; font-size: 14px; line-height: 1.65; color: #334155; text-align: justify;">${DOMPurify2__default.default.sanitize(l)}</p>`).join("");
5775
+ return lines.map((l) => `<p style="margin: 0 0 14px; font-size: 14px; line-height: 1.65; color: #334155; text-align: justify;">${DOMPurify6__default.default.sanitize(l)}</p>`).join("");
5396
5776
  }).join("");
5397
5777
  contentHtml = `
5398
5778
  <div style="flex: 1; overflow: auto; padding: 4px 8px; display: flex; flex-direction: column; justify-content: flex-start;">
@@ -5405,11 +5785,11 @@ var PptPlugin = class {
5405
5785
  <!-- Header Banner matching PowerPoint design -->
5406
5786
  <div style="background: linear-gradient(90deg, #a3e635 0%, #84cc16 100%); padding: 12px 24px; border-radius: 4px; display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.08); flex-shrink: 0;">
5407
5787
  <h1 style="margin: 0; font-size: 26px; font-weight: 700; color: #1e293b; letter-spacing: -0.3px;">
5408
- ${DOMPurify2__default.default.sanitize(s.title)}
5788
+ ${DOMPurify6__default.default.sanitize(s.title)}
5409
5789
  </h1>
5410
5790
  ${s.subtitle ? `
5411
5791
  <span style="background: #38bdf8; color: #ffffff; padding: 4px 14px; border-radius: 4px; font-weight: 700; font-size: 13px; letter-spacing: 0.5px; box-shadow: 0 1px 4px rgba(0,0,0,0.15);">
5412
- ${DOMPurify2__default.default.sanitize(s.subtitle)}
5792
+ ${DOMPurify6__default.default.sanitize(s.subtitle)}
5413
5793
  </span>
5414
5794
  ` : `
5415
5795
  <span style="font-size: 12px; color: #365314; font-weight: 600;">