@files-preview-app/preview-file 1.2.8 → 1.2.9

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.js CHANGED
@@ -1559,6 +1559,7 @@ var PdfPlugin = class {
1559
1559
  getPageCount: () => totalPages,
1560
1560
  getCurrentPage: () => currentPage,
1561
1561
  goToPage: (page) => {
1562
+ container.scrollTop = 0;
1562
1563
  renderPage(page);
1563
1564
  },
1564
1565
  download: () => {
@@ -2063,7 +2064,14 @@ var DocxPlugin = class {
2063
2064
  ignoreFonts: true,
2064
2065
  // Avoid crashes on embedded obfuscated fonts
2065
2066
  breakPages: true,
2066
- experimental: true
2067
+ experimental: true,
2068
+ ignoreLastRenderedPageBreak: false,
2069
+ // Honor Word's exact page breaks!
2070
+ renderHeaders: true,
2071
+ renderFooters: true,
2072
+ renderFootnotes: true,
2073
+ renderEndnotes: true,
2074
+ useBase64URL: true
2067
2075
  });
2068
2076
  if (!ctx.container.contains(wrapper)) {
2069
2077
  ctx.container.appendChild(wrapper);
@@ -2084,11 +2092,14 @@ var DocxPlugin = class {
2084
2092
  renderedSuccessfully = true;
2085
2093
  } catch (fallbackErr) {
2086
2094
  console.error("[DocxPlugin] Native fallback failed:", fallbackErr);
2095
+ const isCorrupt = fallbackErr?.message?.includes("invalid zip") || fallbackErr?.message?.includes("corrupted");
2087
2096
  wrapper.innerHTML = `
2088
- <div style="text-align:center; padding: 48px; background: #fff; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.06);">
2089
- <div style="font-size:48px; margin-bottom: 16px;">\u{1F4C4}</div>
2090
- <h3 style="margin: 0 0 8px; color: #1e293b;">${ctx.metadata.name || "Word Document"}</h3>
2091
- <p style="color: #64748b; margin: 0;">Could not parse document content</p>
2097
+ <div style="text-align:center; padding: 48px 32px; background: #fff; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.06); max-width: 600px; margin: 40px auto;">
2098
+ <div style="font-size:48px; margin-bottom: 16px;">${isCorrupt ? "\u26A0\uFE0F" : "\u{1F4C4}"}</div>
2099
+ <h3 style="margin: 0 0 8px; color: #1e293b; font-size: 18px;">${ctx.metadata.name || "Word Document"}</h3>
2100
+ <p style="color: #64748b; margin: 0 0 16px; font-size: 14px; line-height: 1.5;">
2101
+ ${isCorrupt ? "This document appears to be corrupted or contains invalid archive data and cannot be opened (matches Microsoft Word on Windows)." : "Could not render document content. The file structure may be damaged."}
2102
+ </p>
2092
2103
  </div>
2093
2104
  `;
2094
2105
  if (!ctx.container.contains(wrapper)) {
@@ -2100,47 +2111,61 @@ var DocxPlugin = class {
2100
2111
  const cards = Array.from(wrapper.querySelectorAll(".fp-docx-page-card"));
2101
2112
  if (sections.length === 1 && cards.length === 0) {
2102
2113
  const singleSec = sections[0];
2103
- const pageH = 1056;
2114
+ const contentContainer = singleSec.querySelector("article") || singleSec;
2115
+ const children = Array.from(contentContainer.children);
2116
+ const pageH = singleSec.offsetHeight > 1300 ? 1122 : Math.max(1056, singleSec.offsetHeight);
2104
2117
  const secH = singleSec.offsetHeight || singleSec.scrollHeight;
2105
- if (secH > pageH * 1.25) {
2106
- const children = Array.from(singleSec.children);
2107
- if (children.length > 1) {
2108
- const parent = singleSec.parentElement || wrapper;
2109
- const newSections = [singleSec];
2110
- singleSec.innerHTML = "";
2111
- singleSec.style.minHeight = `${pageH}px`;
2112
- singleSec.style.maxHeight = `${pageH}px`;
2113
- singleSec.style.overflow = "hidden";
2114
- singleSec.style.boxSizing = "border-box";
2115
- let curSec = singleSec;
2116
- let curH = 0;
2117
- const maxH = pageH - 96;
2118
- for (let i = 0; i < children.length; i++) {
2119
- const child = children[i];
2120
- curSec.appendChild(child);
2121
- const chH = child.offsetHeight || 28;
2122
- curH += chH;
2123
- if (curH >= maxH && i < children.length - 1) {
2124
- const nextSec = document.createElement("section");
2125
- nextSec.className = singleSec.className;
2126
- nextSec.style.cssText = singleSec.style.cssText;
2127
- nextSec.style.width = singleSec.style.width || "816px";
2128
- nextSec.style.minHeight = `${pageH}px`;
2129
- nextSec.style.maxHeight = `${pageH}px`;
2130
- nextSec.style.overflow = "hidden";
2131
- nextSec.style.boxSizing = "border-box";
2132
- nextSec.style.backgroundColor = "#ffffff";
2133
- nextSec.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
2134
- nextSec.style.borderRadius = "4px";
2135
- nextSec.style.marginBottom = "24px";
2136
- parent.appendChild(nextSec);
2137
- newSections.push(nextSec);
2138
- curSec = nextSec;
2139
- curH = 0;
2118
+ if (secH > pageH * 1.25 && children.length > 1) {
2119
+ const childHeights = children.map((c) => {
2120
+ const rectH = c.getBoundingClientRect().height;
2121
+ const offH = c.offsetHeight;
2122
+ const textLen = c.textContent?.trim().length || 0;
2123
+ const estH = Math.max(24, Math.ceil(textLen / 80) * 22 + 16);
2124
+ return Math.max(rectH, offH, estH);
2125
+ });
2126
+ const parent = singleSec.parentElement || wrapper;
2127
+ const newSections = [singleSec];
2128
+ const headerEl = singleSec.querySelector("header");
2129
+ const footerEl = singleSec.querySelector("footer");
2130
+ contentContainer.innerHTML = "";
2131
+ singleSec.style.minHeight = `${pageH}px`;
2132
+ singleSec.style.boxSizing = "border-box";
2133
+ let curContent = contentContainer;
2134
+ let curH = 0;
2135
+ const maxH = pageH - 140;
2136
+ for (let i = 0; i < children.length; i++) {
2137
+ const child = children[i];
2138
+ const chH = childHeights[i];
2139
+ curContent.appendChild(child);
2140
+ curH += chH;
2141
+ if (curH >= maxH && i < children.length - 1) {
2142
+ const nextSec = document.createElement("section");
2143
+ nextSec.className = singleSec.className;
2144
+ nextSec.style.cssText = singleSec.style.cssText;
2145
+ nextSec.style.minHeight = `${pageH}px`;
2146
+ nextSec.style.boxSizing = "border-box";
2147
+ nextSec.style.backgroundColor = "#ffffff";
2148
+ nextSec.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
2149
+ nextSec.style.borderRadius = "4px";
2150
+ nextSec.style.marginBottom = "24px";
2151
+ if (headerEl) {
2152
+ nextSec.appendChild(headerEl.cloneNode(true));
2153
+ }
2154
+ const nextArticle = document.createElement("article");
2155
+ if (contentContainer.tagName.toLowerCase() === "article") {
2156
+ nextArticle.style.cssText = contentContainer.style.cssText;
2140
2157
  }
2158
+ nextSec.appendChild(nextArticle);
2159
+ if (footerEl) {
2160
+ nextSec.appendChild(footerEl.cloneNode(true));
2161
+ }
2162
+ parent.appendChild(nextSec);
2163
+ newSections.push(nextSec);
2164
+ curContent = nextArticle;
2165
+ curH = 0;
2141
2166
  }
2142
- sections = newSections;
2143
2167
  }
2168
+ sections = newSections;
2144
2169
  }
2145
2170
  }
2146
2171
  const pageElements = sections.length > 0 ? sections : cards;
@@ -2179,6 +2204,7 @@ var DocxPlugin = class {
2179
2204
  if (indicator) {
2180
2205
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
2181
2206
  }
2207
+ ctx.container.scrollTop = 0;
2182
2208
  ctx.emit("page-change", { page: currentPage, total: totalPages });
2183
2209
  };
2184
2210
  if (totalPages > 1) {
@@ -3111,17 +3137,39 @@ var CodePlugin = class {
3111
3137
  let rawPages = [];
3112
3138
  if (isTxt) {
3113
3139
  const explicitPages = fullText.split(/(?:\f|\x0C)/);
3140
+ const charsPerLine = 85;
3141
+ const maxVisualLines = 45;
3142
+ const charsPerPage = charsPerLine * maxVisualLines;
3114
3143
  for (const ep of explicitPages) {
3115
3144
  const lines = ep.split(/\r?\n/);
3116
3145
  let currentChunk = [];
3146
+ let currentLines = 0;
3117
3147
  for (let i = 0; i < lines.length; i++) {
3118
- currentChunk.push(lines[i]);
3119
- if (currentChunk.length >= 46) {
3148
+ const line = lines[i];
3149
+ const vLines = Math.max(1, Math.ceil((line.length || 1) / charsPerLine));
3150
+ if (currentLines + vLines > maxVisualLines && currentChunk.length > 0) {
3120
3151
  rawPages.push(currentChunk.join("\n"));
3121
3152
  currentChunk = [];
3153
+ currentLines = 0;
3154
+ }
3155
+ if (vLines > maxVisualLines) {
3156
+ let remaining = line;
3157
+ while (remaining.length > charsPerPage) {
3158
+ let splitIdx = remaining.lastIndexOf(" ", charsPerPage);
3159
+ if (splitIdx < charsPerPage * 0.75) splitIdx = charsPerPage;
3160
+ rawPages.push(remaining.slice(0, splitIdx));
3161
+ remaining = remaining.slice(splitIdx).trimStart();
3162
+ }
3163
+ if (remaining.length > 0) {
3164
+ currentChunk.push(remaining);
3165
+ currentLines = Math.ceil(remaining.length / charsPerLine);
3166
+ }
3167
+ } else {
3168
+ currentChunk.push(line);
3169
+ currentLines += vLines;
3122
3170
  }
3123
3171
  }
3124
- if (currentChunk.length > 0 || lines.length === 0) {
3172
+ if (currentChunk.length > 0) {
3125
3173
  rawPages.push(currentChunk.join("\n"));
3126
3174
  }
3127
3175
  }
@@ -3231,6 +3279,7 @@ var CodePlugin = class {
3231
3279
  if (indicator) {
3232
3280
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
3233
3281
  }
3282
+ container.scrollTop = 0;
3234
3283
  ctx.emit("page-change", { page: currentPage, total: totalPages });
3235
3284
  };
3236
3285
  if (totalPages > 1) {
@@ -4295,11 +4344,60 @@ var RtfPlugin = class {
4295
4344
  }
4296
4345
  const doc = new RTFJS.Document(ctx.buffer, {});
4297
4346
  const htmlElements = await doc.render();
4298
- pageElements = htmlElements;
4299
- for (let i = 0; i < htmlElements.length; i++) {
4300
- const el = htmlElements[i];
4301
- el.style.display = i === 0 ? "block" : "none";
4302
- wrapper.appendChild(el);
4347
+ if (htmlElements.length === 1) {
4348
+ const singleEl = htmlElements[0];
4349
+ wrapper.appendChild(singleEl);
4350
+ const children = Array.from(singleEl.children);
4351
+ const secH = singleEl.offsetHeight || singleEl.scrollHeight;
4352
+ if (secH > 1300 && children.length > 1) {
4353
+ const childHeights = children.map((c) => {
4354
+ const rectH = c.getBoundingClientRect().height;
4355
+ const offH = c.offsetHeight;
4356
+ const textLen = c.textContent?.trim().length || 0;
4357
+ const estH = Math.max(24, Math.ceil(textLen / 80) * 22 + 16);
4358
+ return Math.max(rectH, offH, estH);
4359
+ });
4360
+ wrapper.innerHTML = "";
4361
+ const createRtfCard = () => {
4362
+ const card = document.createElement("div");
4363
+ card.className = "fp-rtf-page-card";
4364
+ card.style.backgroundColor = "#ffffff";
4365
+ card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
4366
+ card.style.borderRadius = "4px";
4367
+ card.style.padding = "72px 56px";
4368
+ card.style.width = "816px";
4369
+ card.style.minHeight = "1056px";
4370
+ card.style.boxSizing = "border-box";
4371
+ card.style.marginBottom = "24px";
4372
+ return card;
4373
+ };
4374
+ let curCard = createRtfCard();
4375
+ wrapper.appendChild(curCard);
4376
+ pageElements = [curCard];
4377
+ let curH = 0;
4378
+ const maxH = 920;
4379
+ for (let i = 0; i < children.length; i++) {
4380
+ const child = children[i];
4381
+ const chH = childHeights[i];
4382
+ curCard.appendChild(child);
4383
+ curH += chH;
4384
+ if (curH >= maxH && i < children.length - 1) {
4385
+ curCard = createRtfCard();
4386
+ wrapper.appendChild(curCard);
4387
+ pageElements.push(curCard);
4388
+ curH = 0;
4389
+ }
4390
+ }
4391
+ } else {
4392
+ pageElements = [singleEl];
4393
+ }
4394
+ } else {
4395
+ pageElements = htmlElements;
4396
+ for (let i = 0; i < htmlElements.length; i++) {
4397
+ const el = htmlElements[i];
4398
+ el.style.display = i === 0 ? "block" : "none";
4399
+ wrapper.appendChild(el);
4400
+ }
4303
4401
  }
4304
4402
  } catch (err) {
4305
4403
  console.warn("[RtfPlugin] RTF render error, fallback text:", err);
@@ -4365,6 +4463,7 @@ var RtfPlugin = class {
4365
4463
  if (indicator) {
4366
4464
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
4367
4465
  }
4466
+ ctx.container.scrollTop = 0;
4368
4467
  ctx.emit("page-change", { page: currentPage, total: totalPages });
4369
4468
  };
4370
4469
  if (totalPages > 1) {
@@ -4836,12 +4935,9 @@ var OpenDocumentPlugin = class {
4836
4935
  page.style.backgroundColor = "#ffffff";
4837
4936
  page.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
4838
4937
  page.style.borderRadius = "4px";
4839
- page.style.boxSizing = "border-box";
4840
4938
  page.style.display = idx === 0 ? "block" : "none";
4841
- page.style.position = "absolute";
4842
- page.style.top = "0";
4843
- page.style.left = "50%";
4844
- page.style.transform = "translateX(-50%)";
4939
+ page.style.margin = "0 auto 24px";
4940
+ page.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
4845
4941
  elements.forEach((el) => page.appendChild(el));
4846
4942
  wrapper.appendChild(page);
4847
4943
  slides.push(page);
@@ -4879,6 +4975,7 @@ var OpenDocumentPlugin = class {
4879
4975
  if (indicator) {
4880
4976
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
4881
4977
  }
4978
+ container.scrollTop = 0;
4882
4979
  ctx.emit("page-change", { page: currentPage, total: totalPages });
4883
4980
  };
4884
4981
  return {
@@ -5371,6 +5468,7 @@ var DocPlugin = class {
5371
5468
  if (indicator) {
5372
5469
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
5373
5470
  }
5471
+ container.scrollTop = 0;
5374
5472
  ctx.emit("page-change", { page: currentPage, total: totalPages });
5375
5473
  };
5376
5474
  if (totalPages > 1) {
@@ -5548,45 +5646,50 @@ var DocPlugin = class {
5548
5646
  }
5549
5647
  splitIntoPages(text) {
5550
5648
  if (!text) return [""];
5551
- 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);
5552
- if (explicitParts.length === 0) explicitParts.push(text);
5553
- const maxLinesPerPage = 48;
5649
+ const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").replace(/\x07\n/g, "\n").replace(/\x07/g, " ");
5650
+ const explicitParts = normalized.split(/[\x0C\f]|\n\s*[-=_]{3,}\s*(?:PAGE|Page|page break)[\s\d\w-]*[-=_]{3,}\s*\n/i).map((p) => p.trim()).filter((p) => p.length > 0);
5651
+ if (explicitParts.length === 0) explicitParts.push(normalized);
5652
+ const maxLinesPerPage = 32;
5653
+ const charsPerLine = 80;
5554
5654
  const finalPages = [];
5555
5655
  for (const part of explicitParts) {
5556
- const lines = part.split(/\r?\n/);
5656
+ const lines = part.split("\n");
5557
5657
  let currentLines = [];
5558
5658
  let count = 0;
5559
5659
  for (const line of lines) {
5560
- currentLines.push(line);
5561
- count++;
5562
- if (count >= maxLinesPerPage) {
5660
+ const vLines = Math.max(1, Math.ceil((line.length || 1) / charsPerLine));
5661
+ if (count + vLines > maxLinesPerPage && currentLines.length > 0) {
5563
5662
  finalPages.push(currentLines.join("\n"));
5564
5663
  currentLines = [];
5565
5664
  count = 0;
5566
5665
  }
5666
+ currentLines.push(line);
5667
+ count += vLines;
5567
5668
  }
5568
5669
  if (currentLines.length > 0) {
5569
5670
  finalPages.push(currentLines.join("\n"));
5570
5671
  }
5571
5672
  }
5572
- return finalPages.length > 0 ? finalPages : [text];
5673
+ return finalPages.length > 0 ? finalPages : [normalized];
5573
5674
  }
5574
5675
  /**
5575
5676
  * Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
5576
5677
  */
5577
5678
  formatDocToHtml(text, filename) {
5578
- const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
5679
+ const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").replace(/\x07\n/g, "\n").replace(/\x07/g, " ").split("\n");
5579
5680
  let html = "";
5580
5681
  let inList = false;
5581
5682
  let tableLines = [];
5582
5683
  const flushTable = () => {
5583
5684
  if (tableLines.length > 0) {
5584
- html += '<table style="width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 12px;">';
5585
- for (const tLine of tableLines) {
5586
- html += "<tr>";
5587
- const cols = tLine.split(" ");
5685
+ html += '<table style="width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 13px; font-family: Calibri, sans-serif;">';
5686
+ for (let rIdx = 0; rIdx < tableLines.length; rIdx++) {
5687
+ const tLine = tableLines[rIdx];
5688
+ const isHeader = rIdx === 0;
5689
+ html += `<tr style="${isHeader ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
5690
+ const cols = tLine.split(" ").filter((c) => c.trim().length > 0);
5588
5691
  for (const col of cols) {
5589
- html += `<td style="border: 1px solid #cbd5e1; padding: 6px 8px;">${DOMPurify6.sanitize(col.trim())}</td>`;
5692
+ html += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px;">${DOMPurify6.sanitize(col.trim())}</td>`;
5590
5693
  }
5591
5694
  html += "</tr>";
5592
5695
  }
@@ -5599,27 +5702,18 @@ var DocPlugin = class {
5599
5702
  let line = lines[i];
5600
5703
  let tabCount = (line.match(/\t/g) || []).length;
5601
5704
  if (tabCount > 0) {
5602
- let consecutiveTableLines = 1;
5603
- let j = i + 1;
5604
- while (j < lines.length) {
5605
- const nextTabCount = (lines[j].match(/\t/g) || []).length;
5606
- if (nextTabCount === tabCount) {
5607
- consecutiveTableLines++;
5608
- j++;
5609
- } else {
5610
- break;
5611
- }
5705
+ let j = i;
5706
+ while (j < lines.length && (lines[j].match(/\t/g) || []).length > 0) {
5707
+ j++;
5612
5708
  }
5613
- if (consecutiveTableLines >= 3) {
5614
- if (inList) {
5615
- html += "</ul>";
5616
- inList = false;
5617
- }
5618
- tableLines = lines.slice(i, j);
5619
- flushTable();
5620
- i = j;
5621
- continue;
5709
+ if (inList) {
5710
+ html += "</ul>";
5711
+ inList = false;
5622
5712
  }
5713
+ tableLines = lines.slice(i, j);
5714
+ flushTable();
5715
+ i = j;
5716
+ continue;
5623
5717
  }
5624
5718
  line = line.trim();
5625
5719
  if (!line) {