@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/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var DOMPurify2 = require('dompurify');
3
+ var DOMPurify6 = require('dompurify');
4
4
  var pdfjsLib = require('pdfjs-dist');
5
5
  var docx = require('docx-preview');
6
6
  var fflate = require('fflate');
@@ -34,7 +34,7 @@ function _interopNamespace(e) {
34
34
  return Object.freeze(n);
35
35
  }
36
36
 
37
- var DOMPurify2__default = /*#__PURE__*/_interopDefault(DOMPurify2);
37
+ var DOMPurify6__default = /*#__PURE__*/_interopDefault(DOMPurify6);
38
38
  var pdfjsLib__namespace = /*#__PURE__*/_interopNamespace(pdfjsLib);
39
39
  var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
40
40
  var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
@@ -386,7 +386,7 @@ async function sourceToArrayBuffer(source, signal) {
386
386
  if (magicMime === "application/zip") {
387
387
  const ooxmlMime = detectOoxmlType(buffer);
388
388
  if (ooxmlMime && ooxmlMime !== "application/zip") {
389
- metadata.mimeType = ooxmlMime;
389
+ metadata.mimeType = metadata.mimeType ?? ooxmlMime;
390
390
  if (ooxmlMime.includes("wordprocessing")) metadata.extension = metadata.extension ?? ".docx";
391
391
  else if (ooxmlMime.includes("spreadsheet")) metadata.extension = metadata.extension ?? ".xlsx";
392
392
  else if (ooxmlMime.includes("presentation")) metadata.extension = metadata.extension ?? ".pptx";
@@ -415,12 +415,12 @@ async function sourceToArrayBuffer(source, signal) {
415
415
  return { buffer, metadata };
416
416
  }
417
417
  function sanitizeHTML(html) {
418
- return DOMPurify2__default.default.sanitize(html, {
418
+ return DOMPurify6__default.default.sanitize(html, {
419
419
  USE_PROFILES: { html: true }
420
420
  });
421
421
  }
422
422
  function sanitizeSVG(svg) {
423
- return DOMPurify2__default.default.sanitize(svg, {
423
+ return DOMPurify6__default.default.sanitize(svg, {
424
424
  USE_PROFILES: { svg: true, svgFilters: true }
425
425
  });
426
426
  }
@@ -1521,7 +1521,19 @@ var PdfPlugin = class {
1521
1521
  }
1522
1522
  };
1523
1523
  await renderPage(1);
1524
+ let resizeTimer = null;
1525
+ const resizeObserver = new ResizeObserver(() => {
1526
+ if (resizeTimer) clearTimeout(resizeTimer);
1527
+ resizeTimer = setTimeout(() => {
1528
+ if (Math.abs(zoomScale - 1) < 0.05) {
1529
+ renderPage(currentPage);
1530
+ }
1531
+ }, 150);
1532
+ });
1533
+ resizeObserver.observe(container);
1524
1534
  const cleanup = () => {
1535
+ resizeObserver.disconnect();
1536
+ if (resizeTimer) clearTimeout(resizeTimer);
1525
1537
  if (currentRenderTask) {
1526
1538
  try {
1527
1539
  currentRenderTask.cancel();
@@ -2269,90 +2281,149 @@ var DocxPlugin = class {
2269
2281
  console.warn("[DocxPlugin] Error parsing relationships:", relsErr);
2270
2282
  }
2271
2283
  }
2272
- const card = document.createElement("div");
2273
- card.className = "fp-docx-page-card";
2274
- card.style.backgroundColor = "#ffffff";
2275
- card.style.borderRadius = "6px";
2276
- card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
2277
- card.style.padding = "48px 56px";
2278
- card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
2279
- card.style.color = "#1e293b";
2280
- card.style.lineHeight = "1.6";
2284
+ const sectPrs = Array.from(doc.getElementsByTagNameNS("*", "sectPr"));
2285
+ const lastSectPr = sectPrs[sectPrs.length - 1];
2286
+ let defaultW = 12240;
2287
+ let defaultH = 15840;
2288
+ let margins = { top: 1440, right: 1440, bottom: 1440, left: 1440 };
2289
+ if (lastSectPr) {
2290
+ const pgSz = lastSectPr.getElementsByTagNameNS("*", "pgSz")[0];
2291
+ if (pgSz) {
2292
+ defaultW = parseInt(pgSz.getAttribute("w:w") || pgSz.getAttribute("w") || "12240", 10);
2293
+ defaultH = parseInt(pgSz.getAttribute("w:h") || pgSz.getAttribute("h") || "15840", 10);
2294
+ }
2295
+ const pgMar = lastSectPr.getElementsByTagNameNS("*", "pgMar")[0];
2296
+ if (pgMar) {
2297
+ margins.top = parseInt(pgMar.getAttribute("w:top") || pgMar.getAttribute("top") || "1440", 10);
2298
+ margins.bottom = parseInt(pgMar.getAttribute("w:bottom") || pgMar.getAttribute("bottom") || "1440", 10);
2299
+ margins.left = parseInt(pgMar.getAttribute("w:left") || pgMar.getAttribute("left") || "1440", 10);
2300
+ margins.right = parseInt(pgMar.getAttribute("w:right") || pgMar.getAttribute("right") || "1440", 10);
2301
+ }
2302
+ }
2303
+ const createPageCard = () => {
2304
+ const card = document.createElement("div");
2305
+ card.className = "fp-docx-page-card";
2306
+ card.style.backgroundColor = "#ffffff";
2307
+ card.style.borderRadius = "4px";
2308
+ card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
2309
+ card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
2310
+ card.style.color = "#1e293b";
2311
+ card.style.lineHeight = "1.6";
2312
+ card.style.boxSizing = "border-box";
2313
+ card.style.overflow = "hidden";
2314
+ card.style.position = "relative";
2315
+ card.style.marginBottom = "24px";
2316
+ card.style.width = `${defaultW / 15}px`;
2317
+ card.style.height = `${defaultH / 15}px`;
2318
+ card.style.padding = `${margins.top / 15}px ${margins.right / 15}px ${margins.bottom / 15}px ${margins.left / 15}px`;
2319
+ return card;
2320
+ };
2321
+ let currentCard = createPageCard();
2322
+ let currentHtml = "";
2323
+ const pages = [{ card: currentCard, html: "" }];
2324
+ const flushHtml = () => {
2325
+ pages[pages.length - 1].html += currentHtml;
2326
+ currentHtml = "";
2327
+ };
2328
+ const newPage = () => {
2329
+ flushHtml();
2330
+ currentCard = createPageCard();
2331
+ pages.push({ card: currentCard, html: "" });
2332
+ };
2281
2333
  const body = doc.getElementsByTagNameNS("*", "body")[0] || doc.documentElement;
2282
- let html = "";
2283
2334
  for (const child of Array.from(body.children)) {
2284
2335
  const tag = child.localName || child.nodeName.split(":").pop();
2285
2336
  if (tag === "p") {
2286
2337
  const pStyle = child.getElementsByTagNameNS("*", "pStyle")[0];
2287
2338
  const styleVal = pStyle?.getAttribute("w:val") || pStyle?.getAttribute("val") || "";
2288
2339
  const numPr = child.getElementsByTagNameNS("*", "numPr")[0];
2289
- const textContent = this.extractParagraphHtml(child, imageMap);
2290
- if (!textContent.trim()) {
2291
- html += '<div style="height: 10px;"></div>';
2292
- continue;
2293
- }
2294
- const lowerStyle = styleVal.toLowerCase();
2295
- if (lowerStyle.includes("title")) {
2296
- 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>`;
2297
- } else if (lowerStyle.includes("heading1") || styleVal === "1") {
2298
- html += `<h2 style="font-size: 22px; font-weight: 700; color: #1e40af; margin: 20px 0 10px;">${textContent}</h2>`;
2299
- } else if (lowerStyle.includes("heading2") || styleVal === "2") {
2300
- html += `<h3 style="font-size: 18px; font-weight: 600; color: #2563eb; margin: 16px 0 8px;">${textContent}</h3>`;
2301
- } else if (lowerStyle.includes("heading3") || styleVal === "3") {
2302
- html += `<h4 style="font-size: 15px; font-weight: 600; color: #334155; margin: 12px 0 6px;">${textContent}</h4>`;
2303
- } else if (numPr) {
2304
- 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>`;
2305
- } else {
2306
- html += `<p style="margin: 8px 0; font-size: 14px;">${textContent}</p>`;
2340
+ const chunks = this.extractParagraphChunks(child, imageMap);
2341
+ for (let i = 0; i < chunks.length; i++) {
2342
+ if (i > 0) {
2343
+ newPage();
2344
+ }
2345
+ const textContent = chunks[i];
2346
+ if (!textContent.trim() && !textContent.includes("<img")) {
2347
+ currentHtml += '<div style="height: 10px;"></div>';
2348
+ continue;
2349
+ }
2350
+ const lowerStyle = styleVal.toLowerCase();
2351
+ if (lowerStyle.includes("title")) {
2352
+ 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>`;
2353
+ } else if (lowerStyle.includes("heading1") || styleVal === "1") {
2354
+ currentHtml += `<h2 style="font-size: 22px; font-weight: 700; color: #1e40af; margin: 20px 0 10px;">${textContent}</h2>`;
2355
+ } else if (lowerStyle.includes("heading2") || styleVal === "2") {
2356
+ currentHtml += `<h3 style="font-size: 18px; font-weight: 600; color: #2563eb; margin: 16px 0 8px;">${textContent}</h3>`;
2357
+ } else if (lowerStyle.includes("heading3") || styleVal === "3") {
2358
+ currentHtml += `<h4 style="font-size: 15px; font-weight: 600; color: #334155; margin: 12px 0 6px;">${textContent}</h4>`;
2359
+ } else if (numPr) {
2360
+ 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>`;
2361
+ } else {
2362
+ currentHtml += `<p style="margin: 8px 0; font-size: 14px;">${textContent}</p>`;
2363
+ }
2307
2364
  }
2308
2365
  } else if (tag === "tbl") {
2309
- html += '<table style="width: 100%; border-collapse: collapse; margin: 20px 0; border: 1px solid #cbd5e1;">';
2366
+ currentHtml += '<table style="width: 100%; border-collapse: collapse; margin: 20px 0; border: 1px solid #cbd5e1;">';
2310
2367
  const rows = Array.from(child.getElementsByTagNameNS("*", "tr"));
2311
2368
  rows.forEach((tr, rIdx) => {
2312
- html += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
2369
+ currentHtml += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
2313
2370
  const cells = Array.from(tr.getElementsByTagNameNS("*", "tc"));
2314
2371
  cells.forEach((tc) => {
2315
2372
  const cellText = this.extractParagraphHtml(tc, imageMap);
2316
- html += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || "&nbsp;"}</td>`;
2373
+ currentHtml += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || "&nbsp;"}</td>`;
2317
2374
  });
2318
- html += "</tr>";
2375
+ currentHtml += "</tr>";
2319
2376
  });
2320
- html += "</table>";
2377
+ currentHtml += "</table>";
2321
2378
  }
2322
2379
  }
2323
- card.innerHTML = DOMPurify2__default.default.sanitize(html, {
2324
- ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "s", "strike", "img", "div", "br"],
2325
- ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
2326
- });
2327
- wrapper.appendChild(card);
2380
+ flushHtml();
2381
+ for (const page of pages) {
2382
+ page.card.innerHTML = DOMPurify6__default.default.sanitize(page.html, {
2383
+ ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "s", "strike", "img", "div", "br"],
2384
+ ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
2385
+ });
2386
+ wrapper.appendChild(page.card);
2387
+ }
2328
2388
  }
2329
2389
  extractParagraphHtml(pElement, imageMap = {}) {
2330
- let result = "";
2390
+ return this.extractParagraphChunks(pElement, imageMap).join("<br/>");
2391
+ }
2392
+ extractParagraphChunks(pElement, imageMap = {}) {
2393
+ const chunks = [""];
2394
+ let currentChunkIndex = 0;
2331
2395
  const drawings = Array.from(pElement.getElementsByTagNameNS("*", "drawing"));
2332
2396
  for (const drawing of drawings) {
2333
2397
  const blip = drawing.getElementsByTagNameNS("*", "blip")[0];
2334
2398
  const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
2335
2399
  if (rId && imageMap[rId]) {
2336
- result += `<div style="text-align:center; margin: 12px 0;"><img src="${imageMap[rId]}" style="max-width: 100%; height: auto; border-radius: 4px;" /></div>`;
2400
+ chunks[currentChunkIndex] += `<div style="text-align:center; margin: 12px 0;"><img src="${imageMap[rId]}" style="max-width: 100%; height: auto; border-radius: 4px;" /></div>`;
2337
2401
  }
2338
2402
  }
2339
2403
  const runs = Array.from(pElement.getElementsByTagNameNS("*", "r"));
2340
- if (runs.length === 0 && !result) {
2341
- return DOMPurify2__default.default.sanitize(pElement.textContent || "");
2404
+ if (runs.length === 0 && !chunks[currentChunkIndex]) {
2405
+ chunks[currentChunkIndex] = DOMPurify6__default.default.sanitize(pElement.textContent || "");
2406
+ return chunks;
2342
2407
  }
2343
2408
  for (const r of runs) {
2344
2409
  const blip = r.getElementsByTagNameNS("*", "blip")[0] || r.getElementsByTagNameNS("*", "imagedata")[0];
2345
2410
  const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
2346
2411
  if (rId && imageMap[rId]) {
2347
- result += `<img src="${imageMap[rId]}" style="max-width: 100%; height: auto; display: inline-block; margin: 4px;" />`;
2412
+ chunks[currentChunkIndex] += `<img src="${imageMap[rId]}" style="max-width: 100%; height: auto; display: inline-block; margin: 4px;" />`;
2348
2413
  }
2349
- const brs = r.getElementsByTagNameNS("*", "br");
2350
- for (let i = 0; i < brs.length; i++) {
2351
- result += "<br/>";
2414
+ const brs = Array.from(r.getElementsByTagNameNS("*", "br"));
2415
+ for (const br of brs) {
2416
+ const type = br.getAttribute("w:type") || br.getAttribute("type");
2417
+ if (type === "page") {
2418
+ chunks.push("");
2419
+ currentChunkIndex++;
2420
+ } else {
2421
+ chunks[currentChunkIndex] += "<br/>";
2422
+ }
2352
2423
  }
2353
2424
  const tabs = r.getElementsByTagNameNS("*", "tab");
2354
2425
  if (tabs.length > 0) {
2355
- result += "&emsp;";
2426
+ chunks[currentChunkIndex] += "&emsp;";
2356
2427
  }
2357
2428
  const rPr = r.getElementsByTagNameNS("*", "rPr")[0];
2358
2429
  const isBold = !!rPr?.getElementsByTagNameNS("*", "b")[0];
@@ -2366,7 +2437,7 @@ var DocxPlugin = class {
2366
2437
  const texts = Array.from(r.getElementsByTagNameNS("*", "t"));
2367
2438
  let text = texts.map((t) => t.textContent || "").join("");
2368
2439
  if (!text) continue;
2369
- text = DOMPurify2__default.default.sanitize(text);
2440
+ text = DOMPurify6__default.default.sanitize(text);
2370
2441
  let styles = "";
2371
2442
  if (isBold) styles += "font-weight: bold; ";
2372
2443
  if (isItalic) styles += "font-style: italic; ";
@@ -2378,12 +2449,12 @@ var DocxPlugin = class {
2378
2449
  if (!isNaN(pt) && pt > 0) styles += `font-size: ${pt}pt; `;
2379
2450
  }
2380
2451
  if (styles) {
2381
- result += `<span style="${styles}">${text}</span>`;
2452
+ chunks[currentChunkIndex] += `<span style="${styles}">${text}</span>`;
2382
2453
  } else {
2383
- result += text;
2454
+ chunks[currentChunkIndex] += text;
2384
2455
  }
2385
2456
  }
2386
- return result;
2457
+ return chunks;
2387
2458
  }
2388
2459
  renderBinaryDocFallback(ctx, wrapper) {
2389
2460
  const card = document.createElement("div");
@@ -2400,14 +2471,14 @@ var DocxPlugin = class {
2400
2471
  const wordDocStream = cfbf.readStream("WordDocument");
2401
2472
  if (wordDocStream && wordDocStream.length >= 512) {
2402
2473
  const text2 = this.extractReadableStrings(wordDocStream);
2403
- card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify2__default.default.sanitize(text2)}</div>`;
2474
+ card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6__default.default.sanitize(text2)}</div>`;
2404
2475
  wrapper.appendChild(card);
2405
2476
  return;
2406
2477
  }
2407
2478
  } catch {
2408
2479
  }
2409
2480
  const text = this.extractReadableStrings(new Uint8Array(ctx.buffer));
2410
- card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify2__default.default.sanitize(text)}</div>`;
2481
+ card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6__default.default.sanitize(text)}</div>`;
2411
2482
  wrapper.appendChild(card);
2412
2483
  }
2413
2484
  extractReadableStrings(bytes) {
@@ -3006,41 +3077,94 @@ var CodePlugin = class {
3006
3077
  async render(ctx) {
3007
3078
  const decoder = new TextDecoder("utf-8");
3008
3079
  const fullText = decoder.decode(ctx.buffer);
3009
- const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
3010
- const rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
3080
+ const extRaw = ctx.metadata.extension?.toLowerCase();
3081
+ const mimeRaw = ctx.metadata.mimeType?.toLowerCase();
3082
+ const isTxt = extRaw === ".txt" || mimeRaw === "text/plain" && (!extRaw || !this.extensions.filter((e) => e !== ".txt").includes(extRaw));
3083
+ let rawPages = [];
3084
+ if (isTxt) {
3085
+ const explicitPages = fullText.split(/(?:\f|\x0C)/);
3086
+ for (const ep of explicitPages) {
3087
+ const lines = ep.split(/\r?\n/);
3088
+ let currentChunk = [];
3089
+ for (let i = 0; i < lines.length; i++) {
3090
+ currentChunk.push(lines[i]);
3091
+ if (currentChunk.length >= 46) {
3092
+ rawPages.push(currentChunk.join("\n"));
3093
+ currentChunk = [];
3094
+ }
3095
+ }
3096
+ if (currentChunk.length > 0 || lines.length === 0) {
3097
+ rawPages.push(currentChunk.join("\n"));
3098
+ }
3099
+ }
3100
+ if (rawPages.length === 0) rawPages = [""];
3101
+ } else {
3102
+ const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
3103
+ rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
3104
+ }
3011
3105
  const totalPages = Math.max(1, rawPages.length);
3012
3106
  let currentPage = 1;
3013
3107
  const container = document.createElement("div");
3014
3108
  container.style.width = "100%";
3015
3109
  container.style.height = "100%";
3016
3110
  container.style.overflow = "auto";
3017
- container.style.backgroundColor = "#1e1e1e";
3018
- container.style.color = "#d4d4d4";
3019
- container.style.padding = "16px";
3020
- container.style.boxSizing = "border-box";
3021
3111
  let fontSize = 13;
3022
3112
  let rotation = 0;
3113
+ let zoomLevel = 1;
3023
3114
  const pre = document.createElement("pre");
3024
- pre.style.margin = "0";
3025
- pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
3026
- pre.style.fontSize = `${fontSize}px`;
3027
- pre.style.lineHeight = "1.5";
3028
- pre.style.whiteSpace = "pre-wrap";
3029
- pre.style.wordBreak = "break-all";
3030
3115
  const code = document.createElement("code");
3116
+ if (isTxt) {
3117
+ container.style.backgroundColor = "#f1f5f9";
3118
+ container.style.padding = "32px";
3119
+ container.style.boxSizing = "border-box";
3120
+ container.style.display = "flex";
3121
+ container.style.flexDirection = "column";
3122
+ container.style.alignItems = "center";
3123
+ pre.style.margin = "0";
3124
+ pre.style.fontFamily = "Consolas, 'Courier New', monospace";
3125
+ pre.style.fontSize = "13px";
3126
+ pre.style.color = "#1e293b";
3127
+ pre.style.lineHeight = "1.5";
3128
+ pre.style.whiteSpace = "pre-wrap";
3129
+ pre.style.wordBreak = "break-word";
3130
+ pre.style.backgroundColor = "#ffffff";
3131
+ pre.style.width = "816px";
3132
+ pre.style.minHeight = "1056px";
3133
+ pre.style.padding = "72px 56px";
3134
+ pre.style.boxSizing = "border-box";
3135
+ pre.style.boxShadow = "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)";
3136
+ pre.style.borderRadius = "4px";
3137
+ pre.style.transformOrigin = "top center";
3138
+ } else {
3139
+ container.style.backgroundColor = "#1e1e1e";
3140
+ container.style.color = "#d4d4d4";
3141
+ container.style.padding = "16px";
3142
+ container.style.boxSizing = "border-box";
3143
+ pre.style.margin = "0";
3144
+ pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
3145
+ pre.style.fontSize = `${fontSize}px`;
3146
+ pre.style.lineHeight = "1.5";
3147
+ pre.style.whiteSpace = "pre-wrap";
3148
+ pre.style.wordBreak = "break-all";
3149
+ pre.style.transformOrigin = "top left";
3150
+ }
3031
3151
  const ext = (ctx.metadata.extension || "").replace(".", "");
3032
3152
  const renderCodePage = (text) => {
3033
- try {
3034
- if (ext && hljs__default.default.getLanguage(ext)) {
3035
- code.innerHTML = hljs__default.default.highlight(text, { language: ext }).value;
3036
- } else {
3037
- code.innerHTML = hljs__default.default.highlightAuto(text).value;
3038
- }
3039
- } catch {
3153
+ if (isTxt) {
3040
3154
  code.textContent = text;
3155
+ } else {
3156
+ try {
3157
+ if (ext && hljs__default.default.getLanguage(ext)) {
3158
+ code.innerHTML = hljs__default.default.highlight(text, { language: ext }).value;
3159
+ } else {
3160
+ code.innerHTML = hljs__default.default.highlightAuto(text).value;
3161
+ }
3162
+ } catch {
3163
+ code.textContent = text;
3164
+ }
3041
3165
  }
3042
3166
  };
3043
- renderCodePage(rawPages[0] || fullText);
3167
+ renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
3044
3168
  pre.appendChild(code);
3045
3169
  container.appendChild(pre);
3046
3170
  let indicator = null;
@@ -3049,15 +3173,22 @@ var CodePlugin = class {
3049
3173
  indicator.className = "fp-code-page-indicator";
3050
3174
  indicator.style.position = "sticky";
3051
3175
  indicator.style.bottom = "16px";
3052
- indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
3053
- indicator.style.backdropFilter = "blur(8px)";
3054
- indicator.style.color = "#f8fafc";
3176
+ if (isTxt) {
3177
+ indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
3178
+ indicator.style.color = "#334155";
3179
+ indicator.style.border = "1px solid #e2e8f0";
3180
+ indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
3181
+ } else {
3182
+ indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
3183
+ indicator.style.color = "#f8fafc";
3184
+ indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
3185
+ indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
3186
+ indicator.style.backdropFilter = "blur(8px)";
3187
+ }
3055
3188
  indicator.style.fontSize = "12px";
3056
3189
  indicator.style.fontWeight = "600";
3057
3190
  indicator.style.padding = "5px 14px";
3058
3191
  indicator.style.borderRadius = "20px";
3059
- indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
3060
- indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
3061
3192
  indicator.style.zIndex = "10";
3062
3193
  indicator.style.userSelect = "none";
3063
3194
  indicator.style.pointerEvents = "none";
@@ -3068,7 +3199,7 @@ var CodePlugin = class {
3068
3199
  }
3069
3200
  const showPage = (pageNum) => {
3070
3201
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
3071
- renderCodePage(rawPages[currentPage - 1] || fullText);
3202
+ renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
3072
3203
  if (indicator) {
3073
3204
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
3074
3205
  }
@@ -3084,39 +3215,57 @@ var CodePlugin = class {
3084
3215
  ctx.container.innerHTML = "";
3085
3216
  };
3086
3217
  ctx.signal.addEventListener("abort", cleanup);
3218
+ const updateTransform = () => {
3219
+ if (isTxt) {
3220
+ pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
3221
+ } else {
3222
+ pre.style.transform = `rotate(${rotation}deg)`;
3223
+ pre.style.fontSize = `${fontSize}px`;
3224
+ }
3225
+ };
3087
3226
  return {
3088
3227
  destroy: cleanup,
3089
3228
  getPageCount: () => totalPages,
3090
3229
  getCurrentPage: () => currentPage,
3091
3230
  goToPage: (page) => showPage(page),
3092
3231
  zoomIn: () => {
3093
- fontSize = Math.min(32, fontSize + 2);
3094
- pre.style.fontSize = `${fontSize}px`;
3232
+ if (isTxt) {
3233
+ zoomLevel = Math.min(3, zoomLevel + 0.1);
3234
+ } else {
3235
+ fontSize = Math.min(32, fontSize + 2);
3236
+ }
3237
+ updateTransform();
3095
3238
  },
3096
3239
  zoomOut: () => {
3097
- fontSize = Math.max(8, fontSize - 2);
3098
- pre.style.fontSize = `${fontSize}px`;
3240
+ if (isTxt) {
3241
+ zoomLevel = Math.max(0.1, zoomLevel - 0.1);
3242
+ } else {
3243
+ fontSize = Math.max(8, fontSize - 2);
3244
+ }
3245
+ updateTransform();
3099
3246
  },
3100
- getZoom: () => fontSize / 13,
3247
+ getZoom: () => isTxt ? zoomLevel : fontSize / 13,
3101
3248
  setZoom: (level) => {
3102
- fontSize = Math.round(13 * level);
3103
- pre.style.fontSize = `${fontSize}px`;
3249
+ if (isTxt) {
3250
+ zoomLevel = level;
3251
+ } else {
3252
+ fontSize = Math.round(13 * level);
3253
+ }
3254
+ updateTransform();
3104
3255
  },
3105
3256
  fitToPage: () => {
3106
3257
  fontSize = 13;
3107
3258
  rotation = 0;
3108
- pre.style.fontSize = "13px";
3109
- pre.style.transform = "none";
3259
+ zoomLevel = 1;
3260
+ updateTransform();
3110
3261
  },
3111
3262
  rotateCW: () => {
3112
3263
  rotation = (rotation + 90) % 360;
3113
- pre.style.transform = `rotate(${rotation}deg)`;
3114
- pre.style.transformOrigin = "top left";
3264
+ updateTransform();
3115
3265
  },
3116
3266
  rotateCCW: () => {
3117
3267
  rotation = (rotation - 90 + 360) % 360;
3118
- pre.style.transform = `rotate(${rotation}deg)`;
3119
- pre.style.transformOrigin = "top left";
3268
+ updateTransform();
3120
3269
  },
3121
3270
  download: () => {
3122
3271
  const mimeType = ctx.metadata.mimeType || "text/plain";
@@ -3415,7 +3564,7 @@ var MarkdownPlugin = class {
3415
3564
  gfm: true,
3416
3565
  breaks: true
3417
3566
  });
3418
- const cleanHtml = DOMPurify2__default.default.sanitize(rawHtml, {
3567
+ const cleanHtml = DOMPurify6__default.default.sanitize(rawHtml, {
3419
3568
  USE_PROFILES: { html: true }
3420
3569
  });
3421
3570
  const wrapper = document.createElement("div");
@@ -4051,6 +4200,14 @@ var RtfPlugin = class {
4051
4200
  group: "actions",
4052
4201
  execute: () => instance.download?.()
4053
4202
  },
4203
+ {
4204
+ id: "copy",
4205
+ icon: "copy",
4206
+ label: "Copy Text",
4207
+ type: "button",
4208
+ group: "actions",
4209
+ execute: () => instance.copy?.()
4210
+ },
4054
4211
  {
4055
4212
  id: "print",
4056
4213
  icon: "print",
@@ -4112,14 +4269,31 @@ var RtfPlugin = class {
4112
4269
  } catch (err) {
4113
4270
  console.warn("[RtfPlugin] RTF render error, fallback text:", err);
4114
4271
  const text = new TextDecoder("latin1").decode(ctx.buffer);
4115
- const clean = text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "");
4116
- const pre = document.createElement("pre");
4117
- pre.style.whiteSpace = "pre-wrap";
4118
- pre.style.fontFamily = "serif";
4119
- pre.style.color = "#333";
4120
- pre.textContent = clean;
4121
- wrapper.appendChild(pre);
4122
- pageElements = [pre];
4272
+ const rawPages = text.split(/\\page\b/).map((segment) => {
4273
+ return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
4274
+ }).filter((p) => p.length > 0);
4275
+ const pages = rawPages.length > 0 ? rawPages : [text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim()];
4276
+ for (let i = 0; i < pages.length; i++) {
4277
+ const pageCard = document.createElement("div");
4278
+ pageCard.className = "fp-rtf-page-card";
4279
+ pageCard.style.backgroundColor = "#ffffff";
4280
+ pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
4281
+ pageCard.style.borderRadius = "4px";
4282
+ pageCard.style.padding = "72px 56px";
4283
+ pageCard.style.width = "816px";
4284
+ pageCard.style.minHeight = "1056px";
4285
+ pageCard.style.maxWidth = "100%";
4286
+ pageCard.style.boxSizing = "border-box";
4287
+ pageCard.style.fontFamily = "serif";
4288
+ pageCard.style.fontSize = "12pt";
4289
+ pageCard.style.lineHeight = "1.6";
4290
+ pageCard.style.color = "#1e293b";
4291
+ pageCard.style.whiteSpace = "pre-wrap";
4292
+ pageCard.style.display = i === 0 ? "block" : "none";
4293
+ pageCard.textContent = pages[i];
4294
+ wrapper.appendChild(pageCard);
4295
+ pageElements.push(pageCard);
4296
+ }
4123
4297
  }
4124
4298
  const totalPages = Math.max(1, pageElements.length);
4125
4299
  let currentPage = 1;
@@ -4207,6 +4381,10 @@ var RtfPlugin = class {
4207
4381
  a.click();
4208
4382
  URL.revokeObjectURL(url);
4209
4383
  },
4384
+ copy: () => {
4385
+ const text = wrapper.textContent || "";
4386
+ navigator.clipboard?.writeText(text);
4387
+ },
4210
4388
  print: () => {
4211
4389
  window.print();
4212
4390
  }
@@ -4281,7 +4459,7 @@ var HtmlPreviewPlugin = class {
4281
4459
  }
4282
4460
  async render(ctx) {
4283
4461
  const rawHtml = new TextDecoder("utf-8").decode(ctx.buffer);
4284
- const sanitized = DOMPurify2__default.default.sanitize(rawHtml, {
4462
+ const sanitized = DOMPurify6__default.default.sanitize(rawHtml, {
4285
4463
  WHOLE_DOCUMENT: true,
4286
4464
  ADD_TAGS: ["style", "link"],
4287
4465
  ADD_ATTR: ["target", "rel"]
@@ -4547,14 +4725,97 @@ var OpenDocumentPlugin = class {
4547
4725
  wrapper.textContent = contentDoc.documentElement.textContent || "Formula content";
4548
4726
  }
4549
4727
  } else {
4550
- wrapper.style.maxWidth = "850px";
4551
- wrapper.style.padding = "48px";
4728
+ wrapper.style.maxWidth = "none";
4729
+ wrapper.style.padding = "0";
4552
4730
  wrapper.style.minHeight = "100%";
4731
+ wrapper.style.backgroundColor = "transparent";
4732
+ wrapper.style.boxShadow = "none";
4733
+ wrapper.style.position = "relative";
4734
+ const dims = this.getPageDimensions(stylesDoc, contentDoc);
4553
4735
  const bodyHtml = this.renderOdfBody(contentDoc, styleMap, imageUrls);
4554
- wrapper.innerHTML = DOMPurify2__default.default.sanitize(bodyHtml, {
4555
- ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub"],
4736
+ const tempDiv = document.createElement("div");
4737
+ tempDiv.style.width = `${dims.width - dims.marginLeft - dims.marginRight}px`;
4738
+ tempDiv.style.position = "absolute";
4739
+ tempDiv.style.visibility = "hidden";
4740
+ tempDiv.innerHTML = DOMPurify6__default.default.sanitize(bodyHtml, {
4741
+ ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub", "hr"],
4556
4742
  ADD_ATTR: ["style", "colspan", "rowspan"]
4557
4743
  });
4744
+ document.body.appendChild(tempDiv);
4745
+ const contentHeight = dims.height - dims.marginTop - dims.marginBottom;
4746
+ const pageElements = [[]];
4747
+ let currentHeight = 0;
4748
+ let currentPageIdx = 0;
4749
+ Array.from(tempDiv.children).forEach((child) => {
4750
+ const el = child;
4751
+ const style = el.getAttribute("style") || "";
4752
+ const isBreakBefore = style.includes("page-break-before: always");
4753
+ const isBreakAfter = style.includes("page-break-after: always");
4754
+ const isSoftBreak = el.classList.contains("odf-page-break");
4755
+ if (isBreakBefore) {
4756
+ if (pageElements[currentPageIdx].length > 0) {
4757
+ currentPageIdx++;
4758
+ pageElements.push([]);
4759
+ currentHeight = 0;
4760
+ }
4761
+ }
4762
+ const h = el.offsetHeight || 0;
4763
+ if (currentHeight + h > contentHeight && pageElements[currentPageIdx].length > 0 && !isSoftBreak) {
4764
+ currentPageIdx++;
4765
+ pageElements.push([]);
4766
+ currentHeight = 0;
4767
+ }
4768
+ if (!isSoftBreak) {
4769
+ pageElements[currentPageIdx].push(el.cloneNode(true));
4770
+ currentHeight += h;
4771
+ }
4772
+ if (isBreakAfter || isSoftBreak) {
4773
+ currentPageIdx++;
4774
+ pageElements.push([]);
4775
+ currentHeight = 0;
4776
+ }
4777
+ });
4778
+ document.body.removeChild(tempDiv);
4779
+ if (pageElements.length > 1 && pageElements[pageElements.length - 1].length === 0) {
4780
+ pageElements.pop();
4781
+ }
4782
+ totalPages = Math.max(1, pageElements.length);
4783
+ pageElements.forEach((elements, idx) => {
4784
+ const page = document.createElement("div");
4785
+ page.className = `fp-odt-page fp-odt-page-${idx + 1}`;
4786
+ page.style.width = `${dims.width}px`;
4787
+ page.style.minHeight = `${dims.height}px`;
4788
+ page.style.padding = `${dims.marginTop}px ${dims.marginRight}px ${dims.marginBottom}px ${dims.marginLeft}px`;
4789
+ page.style.margin = "0 auto";
4790
+ page.style.backgroundColor = "#ffffff";
4791
+ page.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
4792
+ page.style.borderRadius = "4px";
4793
+ page.style.boxSizing = "border-box";
4794
+ page.style.display = idx === 0 ? "block" : "none";
4795
+ page.style.position = "absolute";
4796
+ page.style.top = "0";
4797
+ page.style.left = "50%";
4798
+ page.style.transform = "translateX(-50%)";
4799
+ elements.forEach((el) => page.appendChild(el));
4800
+ wrapper.appendChild(page);
4801
+ slides.push(page);
4802
+ });
4803
+ const pageIndicator = document.createElement("div");
4804
+ pageIndicator.className = "fp-odt-page-indicator";
4805
+ pageIndicator.style.position = "sticky";
4806
+ pageIndicator.style.bottom = "16px";
4807
+ pageIndicator.style.left = "50%";
4808
+ pageIndicator.style.transform = "translateX(-50%)";
4809
+ pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
4810
+ pageIndicator.style.color = "#fff";
4811
+ pageIndicator.style.padding = "6px 12px";
4812
+ pageIndicator.style.borderRadius = "16px";
4813
+ pageIndicator.style.fontSize = "12px";
4814
+ pageIndicator.style.zIndex = "100";
4815
+ pageIndicator.style.display = "inline-block";
4816
+ pageIndicator.style.width = "fit-content";
4817
+ pageIndicator.textContent = `Page 1 of ${totalPages}`;
4818
+ container.appendChild(pageIndicator);
4558
4819
  }
4559
4820
  const cleanup = () => {
4560
4821
  imageUrls.forEach((url) => URL.revokeObjectURL(url));
@@ -4563,11 +4824,15 @@ var OpenDocumentPlugin = class {
4563
4824
  };
4564
4825
  ctx.signal.addEventListener("abort", cleanup);
4565
4826
  const goToPage = (page) => {
4566
- if (!isPresentation || page < 1 || page > totalPages) return;
4827
+ if (page < 1 || page > totalPages) return;
4567
4828
  currentPage = page;
4568
4829
  slides.forEach((s, idx) => {
4569
4830
  s.style.display = idx === page - 1 ? "block" : "none";
4570
4831
  });
4832
+ const indicator = container.querySelector(".fp-odt-page-indicator");
4833
+ if (indicator) {
4834
+ indicator.textContent = `Page ${currentPage} of ${totalPages}`;
4835
+ }
4571
4836
  ctx.emit("page-change", { page: currentPage, total: totalPages });
4572
4837
  };
4573
4838
  return {
@@ -4636,6 +4901,43 @@ var OpenDocumentPlugin = class {
4636
4901
  }
4637
4902
  };
4638
4903
  }
4904
+ getPageDimensions(stylesDoc, contentDoc) {
4905
+ let width = 850;
4906
+ let height = 1123;
4907
+ let marginTop = 48;
4908
+ let marginBottom = 48;
4909
+ let marginLeft = 48;
4910
+ let marginRight = 48;
4911
+ const parseUnit = (val) => {
4912
+ if (!val) return null;
4913
+ if (val.endsWith("cm")) return parseFloat(val) * 37.8;
4914
+ if (val.endsWith("mm")) return parseFloat(val) * 3.78;
4915
+ if (val.endsWith("in")) return parseFloat(val) * 96;
4916
+ if (val.endsWith("pt")) return parseFloat(val) * 1.33;
4917
+ if (val.endsWith("px")) return parseFloat(val);
4918
+ return parseFloat(val);
4919
+ };
4920
+ const docs = [stylesDoc, contentDoc].filter(Boolean);
4921
+ for (const doc of docs) {
4922
+ const pageLayout = doc.querySelector("page-layout-properties, [page-width]");
4923
+ if (pageLayout) {
4924
+ const w = parseUnit(pageLayout.getAttribute("fo:page-width") || pageLayout.getAttribute("page-width"));
4925
+ const h = parseUnit(pageLayout.getAttribute("fo:page-height") || pageLayout.getAttribute("page-height"));
4926
+ const mt = parseUnit(pageLayout.getAttribute("fo:margin-top") || pageLayout.getAttribute("margin-top"));
4927
+ const mb = parseUnit(pageLayout.getAttribute("fo:margin-bottom") || pageLayout.getAttribute("margin-bottom"));
4928
+ const ml = parseUnit(pageLayout.getAttribute("fo:margin-left") || pageLayout.getAttribute("margin-left"));
4929
+ const mr = parseUnit(pageLayout.getAttribute("fo:margin-right") || pageLayout.getAttribute("margin-right"));
4930
+ if (w !== null) width = w;
4931
+ if (h !== null) height = h;
4932
+ if (mt !== null) marginTop = mt;
4933
+ if (mb !== null) marginBottom = mb;
4934
+ if (ml !== null) marginLeft = ml;
4935
+ if (mr !== null) marginRight = mr;
4936
+ break;
4937
+ }
4938
+ }
4939
+ return { width, height, marginTop, marginBottom, marginLeft, marginRight };
4940
+ }
4639
4941
  extractStyles(stylesDoc, contentDoc) {
4640
4942
  const map = /* @__PURE__ */ new Map();
4641
4943
  const styleNodes = [];
@@ -4658,14 +4960,21 @@ var OpenDocumentPlugin = class {
4658
4960
  if (color) css += `color: ${color}; `;
4659
4961
  if (size) css += `font-size: ${size}; `;
4660
4962
  }
4661
- const paraProp = node.querySelector("paragraph-properties, [text-align]");
4963
+ let paraProp = node.querySelector("paragraph-properties, [text-align]");
4964
+ if (!paraProp) {
4965
+ paraProp = Array.from(node.children).find((c) => c.tagName.includes("paragraph-properties")) || null;
4966
+ }
4662
4967
  if (paraProp) {
4663
4968
  const align = paraProp.getAttribute("fo:text-align") || paraProp.getAttribute("text-align");
4664
4969
  const mt = paraProp.getAttribute("fo:margin-top") || paraProp.getAttribute("margin-top");
4665
4970
  const mb = paraProp.getAttribute("fo:margin-bottom") || paraProp.getAttribute("margin-bottom");
4971
+ const breakBefore = paraProp.getAttribute("fo:break-before") || paraProp.getAttribute("break-before");
4972
+ const breakAfter = paraProp.getAttribute("fo:break-after") || paraProp.getAttribute("break-after");
4666
4973
  if (align) css += `text-align: ${align}; `;
4667
4974
  if (mt) css += `margin-top: ${mt}; `;
4668
4975
  if (mb) css += `margin-bottom: ${mb}; `;
4976
+ if (breakBefore === "page") css += "page-break-before: always; ";
4977
+ if (breakAfter === "page") css += "page-break-after: always; ";
4669
4978
  }
4670
4979
  if (css) map.set(name, css);
4671
4980
  }
@@ -4750,6 +5059,8 @@ var OpenDocumentPlugin = class {
4750
5059
  result += "&emsp;";
4751
5060
  } else if (tag === "line-break") {
4752
5061
  result += "<br/>";
5062
+ } else if (tag === "soft-page-break") {
5063
+ result += '<hr class="odf-page-break" style="page-break-after: always; border: none; margin: 0; padding: 0; height: 0;" />';
4753
5064
  } else {
4754
5065
  result += el.textContent || "";
4755
5066
  }
@@ -4910,20 +5221,9 @@ var DocPlugin = class {
4910
5221
  container.style.overflow = "auto";
4911
5222
  container.style.padding = "32px 16px";
4912
5223
  container.style.backgroundColor = "#f1f5f9";
4913
- const wrapper = document.createElement("div");
4914
- wrapper.className = "fp-doc-wrapper";
4915
- wrapper.style.maxWidth = "850px";
4916
- wrapper.style.margin = "0 auto";
4917
- wrapper.style.backgroundColor = "#ffffff";
4918
- wrapper.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
4919
- wrapper.style.borderRadius = "4px";
4920
- wrapper.style.padding = "56px 48px";
4921
- wrapper.style.minHeight = "100%";
4922
- wrapper.style.transformOrigin = "top center";
4923
- wrapper.style.transition = "transform 0.2s ease";
4924
- wrapper.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
4925
- wrapper.style.color = "#1e293b";
4926
- container.appendChild(wrapper);
5224
+ container.style.display = "flex";
5225
+ container.style.justifyContent = "center";
5226
+ container.style.alignItems = "flex-start";
4927
5227
  ctx.container.appendChild(container);
4928
5228
  let scale = 1;
4929
5229
  let extractedRawText = "";
@@ -4950,21 +5250,27 @@ var DocPlugin = class {
4950
5250
  const rawPages = this.splitIntoPages(extractedRawText);
4951
5251
  const totalPages = Math.max(1, rawPages.length);
4952
5252
  let currentPage = 1;
4953
- wrapper.innerHTML = "";
4954
5253
  const pageCards = [];
4955
5254
  for (let i = 0; i < totalPages; i++) {
4956
5255
  const pageCard = document.createElement("div");
4957
5256
  pageCard.className = "fp-doc-page-card";
5257
+ pageCard.style.width = "816px";
5258
+ pageCard.style.height = "1056px";
4958
5259
  pageCard.style.backgroundColor = "#ffffff";
4959
5260
  pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
4960
5261
  pageCard.style.borderRadius = "4px";
4961
- pageCard.style.padding = "56px 48px";
4962
- pageCard.style.minHeight = "100%";
5262
+ pageCard.style.padding = "96px 72px";
5263
+ pageCard.style.boxSizing = "border-box";
5264
+ pageCard.style.overflow = "hidden";
4963
5265
  pageCard.style.display = i === 0 ? "block" : "none";
5266
+ pageCard.style.transformOrigin = "top center";
5267
+ pageCard.style.transition = "transform 0.2s ease";
5268
+ pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5269
+ pageCard.style.color = "#1e293b";
4964
5270
  if (isFallback && i === 0) {
4965
5271
  pageCard.innerHTML = `
4966
5272
  <div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
4967
- <h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify2__default.default.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
5273
+ <h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify6__default.default.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
4968
5274
  <span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
4969
5275
  </div>
4970
5276
  ${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
@@ -4972,15 +5278,17 @@ var DocPlugin = class {
4972
5278
  } else {
4973
5279
  pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
4974
5280
  }
4975
- wrapper.appendChild(pageCard);
5281
+ container.appendChild(pageCard);
4976
5282
  pageCards.push(pageCard);
4977
5283
  }
4978
5284
  let indicator = null;
4979
5285
  if (totalPages > 1) {
4980
5286
  indicator = document.createElement("div");
4981
5287
  indicator.className = "fp-doc-page-indicator";
4982
- indicator.style.position = "sticky";
5288
+ indicator.style.position = "fixed";
4983
5289
  indicator.style.bottom = "16px";
5290
+ indicator.style.left = "50%";
5291
+ indicator.style.transform = "translateX(-50%)";
4984
5292
  indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
4985
5293
  indicator.style.backdropFilter = "blur(8px)";
4986
5294
  indicator.style.color = "#f8fafc";
@@ -4994,17 +5302,25 @@ var DocPlugin = class {
4994
5302
  indicator.style.userSelect = "none";
4995
5303
  indicator.style.pointerEvents = "none";
4996
5304
  indicator.style.textAlign = "center";
4997
- indicator.style.width = "fit-content";
4998
- indicator.style.margin = "16px auto 0";
4999
5305
  container.appendChild(indicator);
5000
5306
  }
5307
+ let rotation = 0;
5308
+ const applyTransform = () => {
5309
+ const activeCard = pageCards[currentPage - 1];
5310
+ if (activeCard) {
5311
+ activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5312
+ }
5313
+ };
5001
5314
  const showPage = (pageNum) => {
5002
5315
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
5003
- if (totalPages > 1) {
5004
- pageCards.forEach((card, idx) => {
5005
- card.style.display = idx + 1 === currentPage ? "block" : "none";
5006
- });
5007
- }
5316
+ pageCards.forEach((card, idx) => {
5317
+ if (idx + 1 === currentPage) {
5318
+ card.style.display = "block";
5319
+ card.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5320
+ } else {
5321
+ card.style.display = "none";
5322
+ }
5323
+ });
5008
5324
  if (indicator) {
5009
5325
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
5010
5326
  }
@@ -5013,19 +5329,13 @@ var DocPlugin = class {
5013
5329
  if (totalPages > 1) {
5014
5330
  showPage(1);
5015
5331
  }
5016
- let rotation = 0;
5017
5332
  const calculateFitScale = () => {
5018
- const activeCard = pageCards[currentPage - 1] || wrapper;
5019
- const elW = activeCard.offsetWidth || 850;
5020
- const elH = activeCard.offsetHeight || 1e3;
5333
+ const elW = 816;
5334
+ const elH = 1056;
5021
5335
  const availW = Math.max(200, ctx.container.clientWidth - 48);
5022
5336
  const availH = Math.max(200, ctx.container.clientHeight - 80);
5023
5337
  return Math.min(1.1, Math.min(availW / elW, availH / elH));
5024
5338
  };
5025
- const applyTransform = () => {
5026
- wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5027
- wrapper.style.transformOrigin = "top center";
5028
- };
5029
5339
  setTimeout(() => {
5030
5340
  scale = calculateFitScale();
5031
5341
  applyTransform();
@@ -5183,8 +5493,28 @@ var DocPlugin = class {
5183
5493
  }
5184
5494
  splitIntoPages(text) {
5185
5495
  if (!text) return [""];
5186
- 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);
5187
- return parts.length > 0 ? parts : [text];
5496
+ 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);
5497
+ if (explicitParts.length === 0) explicitParts.push(text);
5498
+ const maxLinesPerPage = 48;
5499
+ const finalPages = [];
5500
+ for (const part of explicitParts) {
5501
+ const lines = part.split(/\r?\n/);
5502
+ let currentLines = [];
5503
+ let count = 0;
5504
+ for (const line of lines) {
5505
+ currentLines.push(line);
5506
+ count++;
5507
+ if (count >= maxLinesPerPage) {
5508
+ finalPages.push(currentLines.join("\n"));
5509
+ currentLines = [];
5510
+ count = 0;
5511
+ }
5512
+ }
5513
+ if (currentLines.length > 0) {
5514
+ finalPages.push(currentLines.join("\n"));
5515
+ }
5516
+ }
5517
+ return finalPages.length > 0 ? finalPages : [text];
5188
5518
  }
5189
5519
  /**
5190
5520
  * Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
@@ -5193,17 +5523,65 @@ var DocPlugin = class {
5193
5523
  const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
5194
5524
  let html = "";
5195
5525
  let inList = false;
5196
- for (const rawLine of lines) {
5197
- const line = rawLine.trim();
5526
+ let tableLines = [];
5527
+ const flushTable = () => {
5528
+ if (tableLines.length > 0) {
5529
+ html += '<table style="width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 12px;">';
5530
+ for (const tLine of tableLines) {
5531
+ html += "<tr>";
5532
+ const cols = tLine.split(" ");
5533
+ for (const col of cols) {
5534
+ html += `<td style="border: 1px solid #cbd5e1; padding: 6px 8px;">${DOMPurify6__default.default.sanitize(col.trim())}</td>`;
5535
+ }
5536
+ html += "</tr>";
5537
+ }
5538
+ html += "</table>";
5539
+ tableLines = [];
5540
+ }
5541
+ };
5542
+ let i = 0;
5543
+ while (i < lines.length) {
5544
+ let line = lines[i];
5545
+ let tabCount = (line.match(/\t/g) || []).length;
5546
+ if (tabCount > 0) {
5547
+ let consecutiveTableLines = 1;
5548
+ let j = i + 1;
5549
+ while (j < lines.length) {
5550
+ const nextTabCount = (lines[j].match(/\t/g) || []).length;
5551
+ if (nextTabCount === tabCount) {
5552
+ consecutiveTableLines++;
5553
+ j++;
5554
+ } else {
5555
+ break;
5556
+ }
5557
+ }
5558
+ if (consecutiveTableLines >= 3) {
5559
+ if (inList) {
5560
+ html += "</ul>";
5561
+ inList = false;
5562
+ }
5563
+ tableLines = lines.slice(i, j);
5564
+ flushTable();
5565
+ i = j;
5566
+ continue;
5567
+ }
5568
+ }
5569
+ line = line.trim();
5198
5570
  if (!line) {
5199
5571
  if (inList) {
5200
5572
  html += "</ul>";
5201
5573
  inList = false;
5202
5574
  }
5575
+ html += '<div style="height: 1.15em;"></div>';
5576
+ i++;
5577
+ continue;
5578
+ }
5579
+ if (/^[\x00-\x1F\x7F-\x9F]+$/.test(line)) {
5580
+ i++;
5203
5581
  continue;
5204
5582
  }
5205
- if (/^[\x00-\x1F\x7F-\x9F]+$/.test(line)) continue;
5206
- if (line.includes("Normal.dot") || line.includes("Microsoft Word") || line.includes("Times New Roman") && line.length < 30) {
5583
+ if ((line.includes("Normal.dot") || line.includes("Microsoft Word") || line.includes("Times New Roman")) && line.length < 30) {
5584
+ i++;
5207
5585
  continue;
5208
5586
  }
5209
5587
  if (line.length < 60 && !line.endsWith(".") && (/^[A-Z0-9\s:_-]+$/.test(line) || line.startsWith("#"))) {
@@ -5211,24 +5589,26 @@ var DocPlugin = class {
5211
5589
  html += "</ul>";
5212
5590
  inList = false;
5213
5591
  }
5214
- 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>`;
5592
+ 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>`;
5215
5593
  } else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
5216
5594
  if (!inList) {
5217
5595
  html += '<ul style="margin: 8px 0; padding-left: 24px;">';
5218
5596
  inList = true;
5219
5597
  }
5220
5598
  const bulletText = line.replace(/^[•\-\*]\s*/, "");
5221
- html += `<li style="margin: 4px 0; line-height: 1.6;">${DOMPurify2__default.default.sanitize(bulletText)}</li>`;
5599
+ html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6__default.default.sanitize(bulletText)}</li>`;
5222
5600
  } else {
5223
5601
  if (inList) {
5224
5602
  html += "</ul>";
5225
5603
  inList = false;
5226
5604
  }
5227
- html += `<p style="line-height: 1.7; margin: 10px 0; font-size: 14px; text-align: justify;">${DOMPurify2__default.default.sanitize(line)}</p>`;
5605
+ html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6__default.default.sanitize(line)}</p>`;
5228
5606
  }
5607
+ i++;
5229
5608
  }
5230
5609
  if (inList) html += "</ul>";
5231
- return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify2__default.default.sanitize(filename)})</p>`;
5610
+ flushTable();
5611
+ return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify6__default.default.sanitize(filename)})</p>`;
5232
5612
  }
5233
5613
  };
5234
5614
  function docPlugin() {
@@ -5406,7 +5786,7 @@ var PptPlugin = class {
5406
5786
  if (s.pictureUrl) {
5407
5787
  contentHtml = `
5408
5788
  <div style="flex: 1; display: flex; justify-content: center; align-items: center; padding: 12px; overflow: hidden;">
5409
- <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;" />
5789
+ <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;" />
5410
5790
  </div>
5411
5791
  `;
5412
5792
  } else if (s.tableColumns.length > 0) {
@@ -5416,7 +5796,7 @@ var PptPlugin = class {
5416
5796
  <table style="width: 100%; border-collapse: collapse; border: 1px solid #cbd5e1; border-radius: 6px; overflow: hidden; background: #ffffff;">
5417
5797
  <thead>
5418
5798
  <tr style="background: #e2e8f0; color: #1e293b; font-weight: 600; font-size: 14px;">
5419
- ${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify2__default.default.sanitize(c)}</th>`).join("")}
5799
+ ${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify6__default.default.sanitize(c)}</th>`).join("")}
5420
5800
  </tr>
5421
5801
  </thead>
5422
5802
  <tbody>
@@ -5432,7 +5812,7 @@ var PptPlugin = class {
5432
5812
  } else {
5433
5813
  const pTags = s.paragraphs.map((p) => {
5434
5814
  const lines = p.split(/[\r\n]+/).map((l) => l.trim()).filter(Boolean);
5435
- 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("");
5815
+ 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("");
5436
5816
  }).join("");
5437
5817
  contentHtml = `
5438
5818
  <div style="flex: 1; overflow: auto; padding: 4px 8px; display: flex; flex-direction: column; justify-content: flex-start;">
@@ -5445,11 +5825,11 @@ var PptPlugin = class {
5445
5825
  <!-- Header Banner matching PowerPoint design -->
5446
5826
  <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;">
5447
5827
  <h1 style="margin: 0; font-size: 26px; font-weight: 700; color: #1e293b; letter-spacing: -0.3px;">
5448
- ${DOMPurify2__default.default.sanitize(s.title)}
5828
+ ${DOMPurify6__default.default.sanitize(s.title)}
5449
5829
  </h1>
5450
5830
  ${s.subtitle ? `
5451
5831
  <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);">
5452
- ${DOMPurify2__default.default.sanitize(s.subtitle)}
5832
+ ${DOMPurify6__default.default.sanitize(s.subtitle)}
5453
5833
  </span>
5454
5834
  ` : `
5455
5835
  <span style="font-size: 12px; color: #365314; font-weight: 600;">