@files-preview-app/preview-file 1.3.4 → 1.3.5

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
@@ -5280,7 +5280,7 @@ function cleanRtfText(raw) {
5280
5280
  return String.fromCharCode(num);
5281
5281
  }).replace(/\\'([0-9a-fA-F]{2})/g, (_, hex) => {
5282
5282
  return String.fromCharCode(parseInt(hex, 16));
5283
- }).replace(/\\tab\b/g, " ").replace(/\\emdash\b/g, "\u2014").replace(/\\endash\b/g, "\u2013").replace(/\\bullet\b/g, "\u2022").replace(/\\lquote\b/g, "\u2018").replace(/\\rquote\b/g, "\u2019").replace(/\\ldblquote\b/g, "\u201C").replace(/\\rdblquote\b/g, "\u201D").replace(/\\\w+(?:-?\d+)?\s?/g, " ").replace(/[{}\r\n]/g, " ").replace(/\s+/g, " ").trim();
5283
+ }).replace(/\\tab\b/g, " ").replace(/\\emdash\b/g, "\u2014").replace(/\\endash\b/g, "\u2013").replace(/\\bullet\b/g, "\u2022").replace(/\\lquote\b/g, "\u2018").replace(/\\rquote\b/g, "\u2019").replace(/\\ldblquote\b/g, "\u201C").replace(/\\rdblquote\b/g, "\u201D").replace(/\\[a-zA-Z]+-?\d*\s?/g, " ").replace(/[{}\r\n]/g, " ").replace(/\s+/g, " ").trim();
5284
5284
  }
5285
5285
  function parseRtfTables(rtfText) {
5286
5286
  const rowSegments = rtfText.split(/\\row\b/);
@@ -5320,17 +5320,12 @@ function parseRtfTables(rtfText) {
5320
5320
  }
5321
5321
  const isNewTable = !currentTable || segmentStart - currentTable.lastEnd > 2500;
5322
5322
  if (isNewTable) {
5323
- const prevTextSlice = rtfText.slice(Math.max(0, segmentStart - 4e3), segmentStart);
5324
- const cleanPrev = cleanRtfText(prevTextSlice);
5325
- const anchorBefore = cleanPrev.slice(-80).trim();
5326
5323
  currentTable = {
5327
5324
  id: `RTF_TABLE_${rawTables.length}`,
5328
5325
  startPos: segmentStart,
5329
5326
  lastEnd: segmentEnd,
5330
5327
  rows: [],
5331
- columnWidths: cellWidths,
5332
- anchorBefore,
5333
- anchorAfter: ""
5328
+ columnWidths: cellWidths
5334
5329
  };
5335
5330
  rawTables.push(currentTable);
5336
5331
  }
@@ -5344,20 +5339,13 @@ function parseRtfTables(rtfText) {
5344
5339
  }
5345
5340
  charOffset += segment.length + 4;
5346
5341
  }
5347
- rawTables.forEach((tbl) => {
5348
- const afterSlice = rtfText.slice(tbl.lastEnd, Math.min(rtfText.length, tbl.lastEnd + 2e3));
5349
- const cleanAfter = cleanRtfText(afterSlice);
5350
- tbl.anchorAfter = cleanAfter.slice(0, 80).trim();
5351
- });
5352
5342
  return rawTables.map((tbl) => {
5353
5343
  const totalW = (tbl.columnWidths || []).reduce((a, b) => a + b, 0);
5354
5344
  const colPercents = totalW > 0 ? tbl.columnWidths.map((w) => Math.round(w / totalW * 100)) : [];
5355
5345
  return {
5356
5346
  id: tbl.id,
5357
5347
  rows: tbl.rows.map((r) => r.cells),
5358
- colPercents,
5359
- anchorBefore: tbl.anchorBefore,
5360
- anchorAfter: tbl.anchorAfter
5348
+ colPercents
5361
5349
  };
5362
5350
  });
5363
5351
  }
@@ -5370,8 +5358,6 @@ function renderRtfTableElement(table) {
5370
5358
  tableEl.style.fontSize = "10pt";
5371
5359
  tableEl.style.lineHeight = "1.5";
5372
5360
  tableEl.style.border = "1px solid #cbd5e1";
5373
- tableEl.style.borderRadius = "4px";
5374
- tableEl.style.boxSizing = "border-box";
5375
5361
  tableEl.style.backgroundColor = "#ffffff";
5376
5362
  const thead = document.createElement("thead");
5377
5363
  const tbody = document.createElement("tbody");
@@ -5380,27 +5366,17 @@ function renderRtfTableElement(table) {
5380
5366
  const isHeader = rIdx === 0;
5381
5367
  if (isHeader) {
5382
5368
  tr.style.backgroundColor = "#f8fafc";
5383
- tr.style.borderBottom = "2px solid #cbd5e1";
5384
- } else {
5385
- tr.style.borderBottom = "1px solid #e2e8f0";
5386
- if (rIdx % 2 === 0) {
5387
- tr.style.backgroundColor = "#fcfdfe";
5388
- }
5389
5369
  }
5390
5370
  rowCells.forEach((cellText, cIdx) => {
5391
5371
  const cellEl = document.createElement(isHeader ? "th" : "td");
5392
5372
  cellEl.style.padding = "8px 12px";
5393
5373
  cellEl.style.border = "1px solid #cbd5e1";
5394
5374
  cellEl.style.verticalAlign = "top";
5395
- cellEl.style.color = isHeader ? "#0f172a" : "#1e293b";
5396
- cellEl.style.fontWeight = isHeader ? "600" : "normal";
5397
5375
  if (table.colPercents && table.colPercents[cIdx]) {
5398
5376
  cellEl.style.width = `${table.colPercents[cIdx]}%`;
5399
5377
  }
5400
5378
  if (/^\d+$/.test(cellText.trim()) || cellText.trim() === "#") {
5401
5379
  cellEl.style.textAlign = "center";
5402
- } else {
5403
- cellEl.style.textAlign = "left";
5404
5380
  }
5405
5381
  cellEl.textContent = cellText;
5406
5382
  tr.appendChild(cellEl);
@@ -5415,23 +5391,19 @@ function renderRtfTableElement(table) {
5415
5391
  tableEl.appendChild(tbody);
5416
5392
  return tableEl;
5417
5393
  }
5418
- function extractMediaFingerprint(el) {
5419
- const img = el.tagName.toLowerCase() === "img" ? el : el.querySelector("img");
5420
- if (img && img.src) {
5421
- const s = img.src;
5422
- return s.length > 300 ? `img_${s.slice(0, 80)}_${s.length}_${s.slice(-80)}` : `img_${s}`;
5423
- }
5424
- const innerImg = el.querySelector("image");
5425
- if (innerImg) {
5426
- const h = innerImg.getAttribute("xlink:href") || innerImg.getAttribute("href") || "";
5427
- if (h) return h.length > 300 ? `svgimg_${h.slice(0, 80)}_${h.length}_${h.slice(-80)}` : `svgimg_${h}`;
5428
- }
5429
- const svg = el.tagName.toLowerCase() === "svg" ? el : el.querySelector("svg");
5430
- if (svg) {
5431
- const vb = svg.getAttribute("viewBox") || "";
5432
- return `svg_${vb}_${svg.innerHTML.length}`;
5433
- }
5434
- return null;
5394
+ function isHeadingElement(el) {
5395
+ if (["H1", "H2", "H3", "H4"].includes(el.tagName)) return true;
5396
+ const spans = el.querySelectorAll ? Array.from(el.querySelectorAll("span, b, strong, div")) : [];
5397
+ for (const s of spans) {
5398
+ const hEl = s;
5399
+ const fs = parseFloat(hEl.style.fontSize) || 0;
5400
+ const isBold = hEl.style.fontWeight === "bold" || parseInt(hEl.style.fontWeight, 10) >= 600 || ["B", "STRONG"].includes(hEl.tagName);
5401
+ if (isBold && fs >= 14) return true;
5402
+ }
5403
+ const elFs = parseFloat(el.style.fontSize) || 0;
5404
+ const elBold = el.style.fontWeight === "bold" || parseInt(el.style.fontWeight, 10) >= 600;
5405
+ if (elBold && elFs >= 14) return true;
5406
+ return false;
5435
5407
  }
5436
5408
  var RtfPlugin = class {
5437
5409
  id = "rtf";
@@ -5544,10 +5516,66 @@ var RtfPlugin = class {
5544
5516
  return actions;
5545
5517
  }
5546
5518
  async render(ctx) {
5519
+ const rawRtf = new TextDecoder("latin1").decode(ctx.buffer);
5520
+ const paperwMatch = rawRtf.match(/\\paperw(\d+)/);
5521
+ const paperhMatch = rawRtf.match(/\\paperh(\d+)/);
5522
+ const marglMatch = rawRtf.match(/\\margl(\d+)/);
5523
+ const margrMatch = rawRtf.match(/\\margr(\d+)/);
5524
+ const margtMatch = rawRtf.match(/\\margt(\d+)/);
5525
+ const margbMatch = rawRtf.match(/\\margb(\d+)/);
5526
+ const paperwTwips = paperwMatch ? parseInt(paperwMatch[1], 10) : 11906;
5527
+ const paperhTwips = paperhMatch ? parseInt(paperhMatch[1], 10) : 16838;
5528
+ const marglTwips = marglMatch ? parseInt(marglMatch[1], 10) : 1134;
5529
+ const margrTwips = margrMatch ? parseInt(margrMatch[1], 10) : 1134;
5530
+ const margtTwips = margtMatch ? parseInt(margtMatch[1], 10) : 1134;
5531
+ const margbTwips = margbMatch ? parseInt(margbMatch[1], 10) : 1134;
5532
+ const pageWidth = Math.round(paperwTwips / 15);
5533
+ const pageHeight = Math.round(paperhTwips / 15);
5534
+ const padLeft = Math.round(marglTwips / 15);
5535
+ const padRight = Math.round(margrTwips / 15);
5536
+ const padTop = Math.round(margtTwips / 15);
5537
+ const padBottom = Math.round(margbTwips / 15);
5538
+ const printableHeight = pageHeight - padTop - padBottom;
5539
+ const extractedImages = [];
5540
+ let p = 0;
5541
+ while ((p = rawRtf.indexOf("\\pict", p)) !== -1) {
5542
+ const startP = p;
5543
+ p += 5;
5544
+ const header = rawRtf.substring(startP, startP + 600);
5545
+ let mime = "";
5546
+ let magic = "";
5547
+ if (header.includes("\\pngblip")) {
5548
+ mime = "image/png";
5549
+ magic = "89504e47";
5550
+ } else if (header.includes("\\jpegblip")) {
5551
+ mime = "image/jpeg";
5552
+ magic = "ffd8ff";
5553
+ }
5554
+ if (!mime || !magic) continue;
5555
+ const magicPos = rawRtf.indexOf(magic, startP);
5556
+ if (magicPos === -1 || magicPos - startP > 3e3) continue;
5557
+ let endP = magicPos;
5558
+ while (endP < rawRtf.length && /[0-9a-fA-F\r\n\s]/.test(rawRtf[endP])) {
5559
+ endP++;
5560
+ }
5561
+ const cleanHex = rawRtf.substring(magicPos, endP).replace(/[\r\n\s]/g, "");
5562
+ if (cleanHex.length < 100) continue;
5563
+ const hexLen = cleanHex.length / 2;
5564
+ const u8 = new Uint8Array(hexLen);
5565
+ for (let k = 0; k < hexLen; k++) {
5566
+ u8[k] = parseInt(cleanHex.substr(k * 2, 2), 16);
5567
+ }
5568
+ let bStr = "";
5569
+ for (let k = 0; k < u8.length; k += 8192) {
5570
+ bStr += String.fromCharCode.apply(null, Array.from(u8.subarray(k, k + 8192)));
5571
+ }
5572
+ extractedImages.push({ mime, dataUrl: `data:${mime};base64,${btoa(bStr)}`, offset: startP });
5573
+ }
5574
+ const tables = parseRtfTables(rawRtf);
5547
5575
  const wrapper = document.createElement("div");
5548
5576
  wrapper.className = "fp-rtf-wrapper";
5549
5577
  wrapper.style.padding = "0";
5550
- wrapper.style.width = "816px";
5578
+ wrapper.style.width = `${pageWidth}px`;
5551
5579
  wrapper.style.margin = "0 auto";
5552
5580
  wrapper.style.boxSizing = "border-box";
5553
5581
  wrapper.style.display = "flex";
@@ -5567,9 +5595,8 @@ var RtfPlugin = class {
5567
5595
  let isUserZoomed = false;
5568
5596
  let fitMode = ctx?.options?.fitMode || "width";
5569
5597
  const calculateFitScale = (mode = fitMode) => {
5570
- const activeEl = pageElements[currentPage - 1] || wrapper;
5571
- const elW = 816;
5572
- const singlePageH = activeEl?.offsetHeight || 1056;
5598
+ const elW = pageWidth;
5599
+ const singlePageH = pageHeight;
5573
5600
  const availW = Math.max(280, ctx.container.clientWidth - 32);
5574
5601
  const availH = Math.max(280, ctx.container.clientHeight - 32);
5575
5602
  const sW = availW / elW;
@@ -5582,8 +5609,7 @@ var RtfPlugin = class {
5582
5609
  const applyTransform = () => {
5583
5610
  wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5584
5611
  wrapper.style.transformOrigin = "top center";
5585
- const activeEl = pageElements[currentPage - 1];
5586
- const baseH = activeEl?.offsetHeight || 1056;
5612
+ const baseH = pageHeight;
5587
5613
  const scaledH = baseH * scale;
5588
5614
  const extraH = Math.max(0, scaledH - baseH);
5589
5615
  wrapper.style.marginBottom = `${extraH + 32}px`;
@@ -5603,193 +5629,220 @@ var RtfPlugin = class {
5603
5629
  if (typeof RTFJS__namespace.loggingEnabled === "function") {
5604
5630
  RTFJS__namespace.loggingEnabled(false);
5605
5631
  }
5606
- const rawText = new TextDecoder("latin1").decode(ctx.buffer);
5607
- const tables = parseRtfTables(rawText);
5608
- const seenMediaSignatures = /* @__PURE__ */ new Set();
5609
5632
  const doc = new RTFJS__namespace.Document(ctx.buffer, {
5610
5633
  onPicture: (isLegacy, createPic) => {
5611
- if (isLegacy === true) {
5612
- return null;
5613
- }
5614
- const pic = createPic();
5615
- if (!pic) return null;
5616
- const fp = extractMediaFingerprint(pic);
5617
- if (fp) {
5618
- if (seenMediaSignatures.has(fp)) {
5619
- return null;
5620
- }
5621
- seenMediaSignatures.add(fp);
5622
- }
5623
- return pic;
5634
+ if (isLegacy === true) return null;
5635
+ return createPic();
5624
5636
  }
5625
5637
  });
5626
- const htmlElements = await doc.render();
5627
- const contentNodes = [];
5628
- const seenInContentBlocks = /* @__PURE__ */ new Set();
5629
- const extractBlocks = (nodes) => {
5630
- for (const item of nodes) {
5631
- if (!item || !(item instanceof HTMLElement)) continue;
5632
- const tag = item.tagName.toLowerCase();
5633
- const hasChildBlocks = Array.from(item.children).some((c) => {
5634
- const ct = c.tagName.toLowerCase();
5635
- return ["p", "div", "table", "h1", "h2", "h3", "h4", "h5", "h6", "section", "article", "ul", "ol"].includes(ct);
5636
- });
5637
- if (hasChildBlocks && !["table", "tr", "td", "th", "ul", "ol", "li"].includes(tag)) {
5638
- extractBlocks(Array.from(item.children));
5639
- } else {
5640
- const fp = extractMediaFingerprint(item);
5641
- if (fp) {
5642
- if (seenInContentBlocks.has(fp)) {
5643
- continue;
5644
- }
5645
- seenInContentBlocks.add(fp);
5646
- }
5647
- const hasMedia = item.querySelector("img, svg, canvas, table") !== null || ["img", "svg", "table"].includes(tag);
5648
- const textContent = (item.textContent || "").trim();
5649
- if (!hasMedia && textContent.length === 0) {
5650
- continue;
5651
- }
5652
- const svgs = item.querySelectorAll("svg, img");
5653
- svgs.forEach((s) => {
5654
- const el = s;
5655
- el.style.maxWidth = "100%";
5656
- el.style.maxHeight = "360px";
5657
- el.style.display = "block";
5658
- el.style.margin = "12px auto";
5659
- if (s.tagName.toLowerCase() === "svg") {
5660
- s.removeAttribute("width");
5661
- s.removeAttribute("height");
5662
- el.style.width = "100%";
5663
- el.style.maxHeight = "360px";
5664
- }
5665
- });
5666
- if (tag === "p" || tag === "div") {
5667
- item.style.display = "block";
5668
- item.style.marginBottom = "12px";
5669
- item.style.lineHeight = "1.6";
5670
- }
5671
- contentNodes.push(item);
5638
+ const elements = await doc.render();
5639
+ let unsupportedIndex = 1;
5640
+ const usedTables = /* @__PURE__ */ new Set();
5641
+ for (let i = 0; i < elements.length; i++) {
5642
+ const el = elements[i];
5643
+ const text = el.textContent || "";
5644
+ if (text.includes("[Unsupported image format]")) {
5645
+ if (extractedImages[unsupportedIndex]) {
5646
+ const img = document.createElement("img");
5647
+ img.src = extractedImages[unsupportedIndex].dataUrl;
5648
+ img.style.width = "100%";
5649
+ img.style.height = "auto";
5650
+ img.style.maxHeight = "430px";
5651
+ img.style.objectFit = "contain";
5652
+ img.style.display = "block";
5653
+ img.style.margin = "12px auto";
5654
+ el.innerHTML = "";
5655
+ el.appendChild(img);
5656
+ unsupportedIndex++;
5672
5657
  }
5673
5658
  }
5674
- };
5675
- extractBlocks(htmlElements);
5676
- tables.forEach((table) => {
5677
- const tableEl = renderRtfTableElement(table);
5678
- let inserted = false;
5679
- if (table.anchorBefore && table.anchorBefore.length > 10) {
5680
- const keyword = table.anchorBefore.slice(-35).trim();
5681
- for (let i = 0; i < contentNodes.length; i++) {
5682
- if (contentNodes[i].textContent?.includes(keyword)) {
5683
- contentNodes.splice(i + 1, 0, tableEl);
5684
- inserted = true;
5685
- break;
5659
+ if (tables.length > 0) {
5660
+ for (let t = 0; t < tables.length; t++) {
5661
+ if (usedTables.has(t)) continue;
5662
+ const tbl = tables[t];
5663
+ if (tbl.rows.length >= 2) {
5664
+ const sampleCell1 = tbl.rows[1]?.[1] || tbl.rows[0]?.[1] || "";
5665
+ const sampleCell2 = tbl.rows[2]?.[1] || tbl.rows[1]?.[0] || "";
5666
+ const match1 = sampleCell1 && text.includes(sampleCell1.slice(0, 15).trim());
5667
+ const match2 = sampleCell2 && text.includes(sampleCell2.slice(0, 15).trim());
5668
+ if (match1 && match2) {
5669
+ el.innerHTML = "";
5670
+ el.appendChild(renderRtfTableElement(tbl));
5671
+ usedTables.add(t);
5672
+ break;
5673
+ }
5686
5674
  }
5687
5675
  }
5688
5676
  }
5689
- if (!inserted && table.anchorAfter && table.anchorAfter.length > 10) {
5690
- const keyword = table.anchorAfter.slice(0, 35).trim();
5691
- for (let i = 0; i < contentNodes.length; i++) {
5692
- if (contentNodes[i].textContent?.includes(keyword)) {
5693
- contentNodes.splice(i, 0, tableEl);
5694
- inserted = true;
5695
- break;
5696
- }
5697
- }
5677
+ }
5678
+ elements.forEach((el) => {
5679
+ const svgs = el.querySelectorAll ? Array.from(el.querySelectorAll("svg")) : [];
5680
+ svgs.forEach((svg) => {
5681
+ svg.removeAttribute("width");
5682
+ svg.removeAttribute("height");
5683
+ svg.style.maxWidth = "100%";
5684
+ svg.style.maxHeight = "430px";
5685
+ svg.style.height = "auto";
5686
+ svg.style.display = "block";
5687
+ svg.style.margin = "12px auto";
5688
+ });
5689
+ const imgs = el.querySelectorAll ? Array.from(el.querySelectorAll("img")) : [];
5690
+ imgs.forEach((img) => {
5691
+ img.style.maxWidth = "100%";
5692
+ img.style.maxHeight = "430px";
5693
+ img.style.height = "auto";
5694
+ img.style.objectFit = "contain";
5695
+ img.style.display = "block";
5696
+ img.style.margin = "12px auto";
5697
+ });
5698
+ });
5699
+ const allImgs = Array.from(document.querySelectorAll("img")).concat(
5700
+ elements.flatMap((el) => Array.from(el.querySelectorAll ? el.querySelectorAll("img") : []))
5701
+ );
5702
+ await Promise.all(allImgs.map((img) => {
5703
+ if (img.complete && img.naturalHeight > 0) return Promise.resolve();
5704
+ if (img.decode) return img.decode().catch(() => {
5705
+ });
5706
+ return new Promise((r) => {
5707
+ img.onload = r;
5708
+ img.onerror = r;
5709
+ });
5710
+ }));
5711
+ elements.forEach((el) => {
5712
+ const text = el.textContent || "";
5713
+ if (text.includes("\uF0B7")) {
5714
+ const cleanText = text.replace(/^[\s\uf0b7\t]+/, "");
5715
+ el.style.display = "flex";
5716
+ el.style.alignItems = "flex-start";
5717
+ el.style.margin = "6px 0 6px 28px";
5718
+ el.style.fontSize = "11pt";
5719
+ el.style.lineHeight = "1.5";
5720
+ el.innerHTML = `<span style="margin-right:10px; user-select:none;">&#9633;</span><span>${cleanText}</span>`;
5698
5721
  }
5699
- if (!inserted) {
5700
- if (contentNodes.length > 2) {
5701
- contentNodes.splice(2, 0, tableEl);
5702
- } else {
5703
- contentNodes.push(tableEl);
5704
- }
5722
+ });
5723
+ elements.forEach((el) => {
5724
+ const text = (el.textContent || "").trim();
5725
+ const hasMedia = el.querySelector("img, svg, canvas, table") !== null || ["IMG", "SVG", "TABLE"].includes(el.tagName);
5726
+ if (isHeadingElement(el)) {
5727
+ el.style.marginTop = "20px";
5728
+ el.style.marginBottom = "10px";
5729
+ el.style.lineHeight = "1.25";
5730
+ } else if (text.length > 0 && !hasMedia) {
5731
+ el.style.marginBottom = "12px";
5732
+ el.style.lineHeight = "1.45";
5705
5733
  }
5706
5734
  });
5707
- const createRtfCard = (pageNum) => {
5735
+ const measureCard = document.createElement("div");
5736
+ measureCard.style.width = `${pageWidth}px`;
5737
+ measureCard.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
5738
+ measureCard.style.boxSizing = "border-box";
5739
+ measureCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5740
+ measureCard.style.lineHeight = "1.45";
5741
+ measureCard.style.visibility = "hidden";
5742
+ measureCard.style.position = "absolute";
5743
+ measureCard.style.top = "-99999px";
5744
+ document.body.appendChild(measureCard);
5745
+ const createPageCard = (num) => {
5708
5746
  const card = document.createElement("div");
5709
5747
  card.className = "fp-rtf-page-card";
5710
- card.setAttribute("data-page-number", String(pageNum));
5748
+ card.setAttribute("data-page-number", String(num));
5711
5749
  card.style.backgroundColor = "#ffffff";
5712
5750
  card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08), 0 1px 3px rgba(0,0,0,0.04)";
5713
5751
  card.style.borderRadius = "4px";
5714
- card.style.padding = "64px 56px";
5715
- card.style.width = "816px";
5716
- card.style.minHeight = "1056px";
5717
- card.style.maxHeight = "1056px";
5718
- card.style.overflow = "hidden";
5752
+ card.style.width = `${pageWidth}px`;
5753
+ card.style.height = `${pageHeight}px`;
5754
+ card.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
5719
5755
  card.style.boxSizing = "border-box";
5756
+ card.style.overflow = "hidden";
5720
5757
  card.style.marginBottom = "24px";
5721
- card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5722
- card.style.lineHeight = "1.6";
5723
5758
  card.style.color = "#1e293b";
5759
+ card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5760
+ card.style.lineHeight = "1.45";
5724
5761
  card.style.position = "relative";
5762
+ card.style.textAlign = "left";
5725
5763
  return card;
5726
5764
  };
5727
- wrapper.innerHTML = "";
5728
- const measureCard = createRtfCard(0);
5729
- measureCard.style.maxHeight = "none";
5730
- measureCard.style.height = "auto";
5731
- wrapper.appendChild(measureCard);
5732
- contentNodes.forEach((node) => measureCard.appendChild(node));
5733
- const childHeights = contentNodes.map((c) => {
5734
- const rect = c.getBoundingClientRect ? c.getBoundingClientRect() : null;
5735
- const rectH = rect ? rect.height : 0;
5736
- const offH = c.offsetHeight || 0;
5737
- let realH = Math.max(rectH, offH);
5738
- try {
5739
- const cs = window.getComputedStyle(c);
5740
- realH += (parseFloat(cs.marginTop) || 0) + (parseFloat(cs.marginBottom) || 0);
5741
- } catch {
5742
- }
5743
- const hasMedia = c.querySelector("img, svg") !== null || ["img", "svg"].includes(c.tagName.toLowerCase());
5744
- const hasTable = c.querySelector("table") !== null || c.tagName.toLowerCase() === "table";
5745
- if (hasMedia) {
5746
- realH = Math.max(realH, 300);
5747
- } else if (hasTable) {
5748
- realH = Math.max(realH, 240);
5749
- }
5750
- if (realH > 0) return realH;
5751
- const textLen = c.textContent?.trim().length || 0;
5752
- return Math.max(28, Math.ceil(textLen / 75) * 26 + 16);
5753
- });
5754
- wrapper.innerHTML = "";
5755
- let curCard = createRtfCard(1);
5756
- wrapper.appendChild(curCard);
5757
- pageElements = [curCard];
5758
- let curH = 0;
5759
- const maxH = 860;
5760
- for (let i = 0; i < contentNodes.length; i++) {
5761
- const child = contentNodes[i];
5762
- const chH = childHeights[i];
5763
- const isChildEmpty = (child.textContent || "").trim().length === 0 && !child.querySelector("table, img, svg, canvas");
5764
- if (curH === 0 && isChildEmpty) {
5765
+ const pages = [];
5766
+ let curCard = createPageCard(1);
5767
+ pages.push(curCard);
5768
+ let curHeight = 0;
5769
+ for (let i = 0; i < elements.length; i++) {
5770
+ const el = elements[i];
5771
+ if (!el || !(el instanceof HTMLElement)) continue;
5772
+ const text = (el.textContent || "").trim();
5773
+ const hasMedia = el.querySelector("img, svg, canvas, table") !== null || ["IMG", "SVG", "TABLE"].includes(el.tagName);
5774
+ const isEmptyPar = !hasMedia && text.length === 0;
5775
+ if (isEmptyPar) {
5776
+ const emptyH = 35;
5777
+ if (curHeight + emptyH > printableHeight) {
5778
+ if (curCard.childNodes.length > 0) {
5779
+ curCard = createPageCard(pages.length + 1);
5780
+ pages.push(curCard);
5781
+ curHeight = 0;
5782
+ }
5783
+ }
5784
+ const spacer = document.createElement("div");
5785
+ spacer.style.height = `${emptyH}px`;
5786
+ curCard.appendChild(spacer);
5787
+ curHeight += emptyH;
5765
5788
  continue;
5766
5789
  }
5767
- const isTable = child.querySelector("table") !== null || child.tagName.toLowerCase() === "table";
5768
- const shouldBreakBeforeTable = isTable && curH > 400 && curCard.childNodes.length > 0;
5769
- if ((curH + chH > maxH || shouldBreakBeforeTable) && curCard.childNodes.length > 0) {
5770
- curCard = createRtfCard(pageElements.length + 1);
5771
- wrapper.appendChild(curCard);
5772
- pageElements.push(curCard);
5773
- curH = 0;
5790
+ measureCard.innerHTML = "";
5791
+ const clone = el.cloneNode(true);
5792
+ measureCard.appendChild(clone);
5793
+ const compStyle = window.getComputedStyle(clone);
5794
+ const mt = parseFloat(compStyle.marginTop) || 0;
5795
+ const mb = parseFloat(compStyle.marginBottom) || 0;
5796
+ const elH = clone.offsetHeight + mt + mb;
5797
+ const isHeading = isHeadingElement(el);
5798
+ let nextContentH = 0;
5799
+ if (isHeading || hasMedia) {
5800
+ for (let j = i + 1; j < elements.length; j++) {
5801
+ const nextEl = elements[j];
5802
+ if (nextEl && (nextEl.textContent || "").trim().length > 0) {
5803
+ measureCard.innerHTML = "";
5804
+ const nClone = nextEl.cloneNode(true);
5805
+ measureCard.appendChild(nClone);
5806
+ const nStyle = window.getComputedStyle(nClone);
5807
+ nextContentH = nClone.offsetHeight + (parseFloat(nStyle.marginTop) || 0) + (parseFloat(nStyle.marginBottom) || 0);
5808
+ break;
5809
+ }
5810
+ }
5774
5811
  }
5775
- curCard.appendChild(child);
5776
- curH += chH;
5777
- }
5778
- pageElements = pageElements.filter((card) => {
5812
+ const remainingSpace = printableHeight - curHeight;
5813
+ const isLargeMedia = hasMedia && elH > 300;
5814
+ const keepWithNextOverflow = isHeading && nextContentH > 0 && elH + nextContentH + 20 > remainingSpace;
5815
+ const largeMediaOverflow = isLargeMedia && curHeight > 0 && elH + 80 > remainingSpace;
5816
+ const shouldBreak = (curHeight + elH > printableHeight || keepWithNextOverflow || largeMediaOverflow) && curCard.childNodes.length > 0;
5817
+ if (shouldBreak) {
5818
+ curCard = createPageCard(pages.length + 1);
5819
+ pages.push(curCard);
5820
+ curHeight = 0;
5821
+ }
5822
+ curCard.appendChild(el);
5823
+ curHeight += elH;
5824
+ }
5825
+ measureCard.remove();
5826
+ pageElements = pages.filter((card) => {
5779
5827
  const hasText = (card.textContent || "").trim().length > 0;
5780
- const hasMedia = card.querySelector("table, img, svg, canvas") !== null;
5781
- return hasText || hasMedia;
5828
+ const hasCardMedia = card.querySelector("table, img, svg, canvas") !== null;
5829
+ return hasText || hasCardMedia;
5782
5830
  });
5783
5831
  if (pageElements.length === 0) {
5784
5832
  pageElements = [curCard];
5785
5833
  }
5834
+ wrapper.innerHTML = "";
5835
+ pageElements.forEach((card, idx) => {
5836
+ card.setAttribute("data-page-number", String(idx + 1));
5837
+ card.style.display = idx === 0 ? "block" : "none";
5838
+ wrapper.appendChild(card);
5839
+ });
5786
5840
  } catch (err) {
5787
5841
  console.warn("[RtfPlugin] RTF render error, fallback text:", err);
5788
- const text = new TextDecoder("latin1").decode(ctx.buffer);
5789
- const tables = parseRtfTables(text);
5842
+ const text = rawRtf;
5790
5843
  const rawPages = text.split(/\\page\b/).map((segment) => {
5791
5844
  return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
5792
- }).filter((p) => p.length > 0);
5845
+ }).filter((p2) => p2.length > 0);
5793
5846
  const pages = rawPages.length > 0 ? rawPages : [text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim()];
5794
5847
  for (let i = 0; i < pages.length; i++) {
5795
5848
  const pageCard = document.createElement("div");
@@ -5797,9 +5850,9 @@ var RtfPlugin = class {
5797
5850
  pageCard.style.backgroundColor = "#ffffff";
5798
5851
  pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
5799
5852
  pageCard.style.borderRadius = "4px";
5800
- pageCard.style.padding = "64px 56px";
5801
- pageCard.style.width = "816px";
5802
- pageCard.style.minHeight = "1056px";
5853
+ pageCard.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
5854
+ pageCard.style.width = `${pageWidth}px`;
5855
+ pageCard.style.minHeight = `${pageHeight}px`;
5803
5856
  pageCard.style.boxSizing = "border-box";
5804
5857
  pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5805
5858
  pageCard.style.fontSize = "12pt";
@@ -5819,11 +5872,9 @@ var RtfPlugin = class {
5819
5872
  let currentPage = 1;
5820
5873
  const showPage = (pageNum) => {
5821
5874
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
5822
- if (totalPages > 1) {
5823
- pageElements.forEach((el, idx) => {
5824
- el.style.display = idx + 1 === currentPage ? "block" : "none";
5825
- });
5826
- }
5875
+ pageElements.forEach((el, idx) => {
5876
+ el.style.display = idx + 1 === currentPage ? "block" : "none";
5877
+ });
5827
5878
  ctx.container.scrollTop = 0;
5828
5879
  ctx.emit("page-change", { page: currentPage, total: totalPages });
5829
5880
  };