@files-preview-app/preview-file 1.3.3 → 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/angular.cjs CHANGED
@@ -5327,7 +5327,7 @@ function cleanRtfText(raw) {
5327
5327
  return String.fromCharCode(num);
5328
5328
  }).replace(/\\'([0-9a-fA-F]{2})/g, (_, hex) => {
5329
5329
  return String.fromCharCode(parseInt(hex, 16));
5330
- }).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();
5330
+ }).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();
5331
5331
  }
5332
5332
  function parseRtfTables(rtfText) {
5333
5333
  const rowSegments = rtfText.split(/\\row\b/);
@@ -5367,17 +5367,12 @@ function parseRtfTables(rtfText) {
5367
5367
  }
5368
5368
  const isNewTable = !currentTable || segmentStart - currentTable.lastEnd > 2500;
5369
5369
  if (isNewTable) {
5370
- const prevTextSlice = rtfText.slice(Math.max(0, segmentStart - 4e3), segmentStart);
5371
- const cleanPrev = cleanRtfText(prevTextSlice);
5372
- const anchorBefore = cleanPrev.slice(-80).trim();
5373
5370
  currentTable = {
5374
5371
  id: `RTF_TABLE_${rawTables.length}`,
5375
5372
  startPos: segmentStart,
5376
5373
  lastEnd: segmentEnd,
5377
5374
  rows: [],
5378
- columnWidths: cellWidths,
5379
- anchorBefore,
5380
- anchorAfter: ""
5375
+ columnWidths: cellWidths
5381
5376
  };
5382
5377
  rawTables.push(currentTable);
5383
5378
  }
@@ -5391,20 +5386,13 @@ function parseRtfTables(rtfText) {
5391
5386
  }
5392
5387
  charOffset += segment.length + 4;
5393
5388
  }
5394
- rawTables.forEach((tbl) => {
5395
- const afterSlice = rtfText.slice(tbl.lastEnd, Math.min(rtfText.length, tbl.lastEnd + 2e3));
5396
- const cleanAfter = cleanRtfText(afterSlice);
5397
- tbl.anchorAfter = cleanAfter.slice(0, 80).trim();
5398
- });
5399
5389
  return rawTables.map((tbl) => {
5400
5390
  const totalW = (tbl.columnWidths || []).reduce((a, b) => a + b, 0);
5401
5391
  const colPercents = totalW > 0 ? tbl.columnWidths.map((w) => Math.round(w / totalW * 100)) : [];
5402
5392
  return {
5403
5393
  id: tbl.id,
5404
5394
  rows: tbl.rows.map((r) => r.cells),
5405
- colPercents,
5406
- anchorBefore: tbl.anchorBefore,
5407
- anchorAfter: tbl.anchorAfter
5395
+ colPercents
5408
5396
  };
5409
5397
  });
5410
5398
  }
@@ -5417,8 +5405,6 @@ function renderRtfTableElement(table) {
5417
5405
  tableEl.style.fontSize = "10pt";
5418
5406
  tableEl.style.lineHeight = "1.5";
5419
5407
  tableEl.style.border = "1px solid #cbd5e1";
5420
- tableEl.style.borderRadius = "4px";
5421
- tableEl.style.boxSizing = "border-box";
5422
5408
  tableEl.style.backgroundColor = "#ffffff";
5423
5409
  const thead = document.createElement("thead");
5424
5410
  const tbody = document.createElement("tbody");
@@ -5427,27 +5413,17 @@ function renderRtfTableElement(table) {
5427
5413
  const isHeader = rIdx === 0;
5428
5414
  if (isHeader) {
5429
5415
  tr.style.backgroundColor = "#f8fafc";
5430
- tr.style.borderBottom = "2px solid #cbd5e1";
5431
- } else {
5432
- tr.style.borderBottom = "1px solid #e2e8f0";
5433
- if (rIdx % 2 === 0) {
5434
- tr.style.backgroundColor = "#fcfdfe";
5435
- }
5436
5416
  }
5437
5417
  rowCells.forEach((cellText, cIdx) => {
5438
5418
  const cellEl = document.createElement(isHeader ? "th" : "td");
5439
5419
  cellEl.style.padding = "8px 12px";
5440
5420
  cellEl.style.border = "1px solid #cbd5e1";
5441
5421
  cellEl.style.verticalAlign = "top";
5442
- cellEl.style.color = isHeader ? "#0f172a" : "#1e293b";
5443
- cellEl.style.fontWeight = isHeader ? "600" : "normal";
5444
5422
  if (table.colPercents && table.colPercents[cIdx]) {
5445
5423
  cellEl.style.width = `${table.colPercents[cIdx]}%`;
5446
5424
  }
5447
5425
  if (/^\d+$/.test(cellText.trim()) || cellText.trim() === "#") {
5448
5426
  cellEl.style.textAlign = "center";
5449
- } else {
5450
- cellEl.style.textAlign = "left";
5451
5427
  }
5452
5428
  cellEl.textContent = cellText;
5453
5429
  tr.appendChild(cellEl);
@@ -5462,6 +5438,20 @@ function renderRtfTableElement(table) {
5462
5438
  tableEl.appendChild(tbody);
5463
5439
  return tableEl;
5464
5440
  }
5441
+ function isHeadingElement(el) {
5442
+ if (["H1", "H2", "H3", "H4"].includes(el.tagName)) return true;
5443
+ const spans = el.querySelectorAll ? Array.from(el.querySelectorAll("span, b, strong, div")) : [];
5444
+ for (const s of spans) {
5445
+ const hEl = s;
5446
+ const fs = parseFloat(hEl.style.fontSize) || 0;
5447
+ const isBold = hEl.style.fontWeight === "bold" || parseInt(hEl.style.fontWeight, 10) >= 600 || ["B", "STRONG"].includes(hEl.tagName);
5448
+ if (isBold && fs >= 14) return true;
5449
+ }
5450
+ const elFs = parseFloat(el.style.fontSize) || 0;
5451
+ const elBold = el.style.fontWeight === "bold" || parseInt(el.style.fontWeight, 10) >= 600;
5452
+ if (elBold && elFs >= 14) return true;
5453
+ return false;
5454
+ }
5465
5455
  var RtfPlugin = class {
5466
5456
  id = "rtf";
5467
5457
  name = "Rich Text Format (RTF)";
@@ -5573,10 +5563,66 @@ var RtfPlugin = class {
5573
5563
  return actions;
5574
5564
  }
5575
5565
  async render(ctx) {
5566
+ const rawRtf = new TextDecoder("latin1").decode(ctx.buffer);
5567
+ const paperwMatch = rawRtf.match(/\\paperw(\d+)/);
5568
+ const paperhMatch = rawRtf.match(/\\paperh(\d+)/);
5569
+ const marglMatch = rawRtf.match(/\\margl(\d+)/);
5570
+ const margrMatch = rawRtf.match(/\\margr(\d+)/);
5571
+ const margtMatch = rawRtf.match(/\\margt(\d+)/);
5572
+ const margbMatch = rawRtf.match(/\\margb(\d+)/);
5573
+ const paperwTwips = paperwMatch ? parseInt(paperwMatch[1], 10) : 11906;
5574
+ const paperhTwips = paperhMatch ? parseInt(paperhMatch[1], 10) : 16838;
5575
+ const marglTwips = marglMatch ? parseInt(marglMatch[1], 10) : 1134;
5576
+ const margrTwips = margrMatch ? parseInt(margrMatch[1], 10) : 1134;
5577
+ const margtTwips = margtMatch ? parseInt(margtMatch[1], 10) : 1134;
5578
+ const margbTwips = margbMatch ? parseInt(margbMatch[1], 10) : 1134;
5579
+ const pageWidth = Math.round(paperwTwips / 15);
5580
+ const pageHeight = Math.round(paperhTwips / 15);
5581
+ const padLeft = Math.round(marglTwips / 15);
5582
+ const padRight = Math.round(margrTwips / 15);
5583
+ const padTop = Math.round(margtTwips / 15);
5584
+ const padBottom = Math.round(margbTwips / 15);
5585
+ const printableHeight = pageHeight - padTop - padBottom;
5586
+ const extractedImages = [];
5587
+ let p = 0;
5588
+ while ((p = rawRtf.indexOf("\\pict", p)) !== -1) {
5589
+ const startP = p;
5590
+ p += 5;
5591
+ const header = rawRtf.substring(startP, startP + 600);
5592
+ let mime = "";
5593
+ let magic = "";
5594
+ if (header.includes("\\pngblip")) {
5595
+ mime = "image/png";
5596
+ magic = "89504e47";
5597
+ } else if (header.includes("\\jpegblip")) {
5598
+ mime = "image/jpeg";
5599
+ magic = "ffd8ff";
5600
+ }
5601
+ if (!mime || !magic) continue;
5602
+ const magicPos = rawRtf.indexOf(magic, startP);
5603
+ if (magicPos === -1 || magicPos - startP > 3e3) continue;
5604
+ let endP = magicPos;
5605
+ while (endP < rawRtf.length && /[0-9a-fA-F\r\n\s]/.test(rawRtf[endP])) {
5606
+ endP++;
5607
+ }
5608
+ const cleanHex = rawRtf.substring(magicPos, endP).replace(/[\r\n\s]/g, "");
5609
+ if (cleanHex.length < 100) continue;
5610
+ const hexLen = cleanHex.length / 2;
5611
+ const u8 = new Uint8Array(hexLen);
5612
+ for (let k = 0; k < hexLen; k++) {
5613
+ u8[k] = parseInt(cleanHex.substr(k * 2, 2), 16);
5614
+ }
5615
+ let bStr = "";
5616
+ for (let k = 0; k < u8.length; k += 8192) {
5617
+ bStr += String.fromCharCode.apply(null, Array.from(u8.subarray(k, k + 8192)));
5618
+ }
5619
+ extractedImages.push({ mime, dataUrl: `data:${mime};base64,${btoa(bStr)}`, offset: startP });
5620
+ }
5621
+ const tables = parseRtfTables(rawRtf);
5576
5622
  const wrapper = document.createElement("div");
5577
5623
  wrapper.className = "fp-rtf-wrapper";
5578
5624
  wrapper.style.padding = "0";
5579
- wrapper.style.width = "816px";
5625
+ wrapper.style.width = `${pageWidth}px`;
5580
5626
  wrapper.style.margin = "0 auto";
5581
5627
  wrapper.style.boxSizing = "border-box";
5582
5628
  wrapper.style.display = "flex";
@@ -5596,9 +5642,8 @@ var RtfPlugin = class {
5596
5642
  let isUserZoomed = false;
5597
5643
  let fitMode = ctx?.options?.fitMode || "width";
5598
5644
  const calculateFitScale = (mode = fitMode) => {
5599
- const activeEl = pageElements[currentPage - 1] || wrapper;
5600
- const elW = 816;
5601
- const singlePageH = activeEl?.offsetHeight || 1056;
5645
+ const elW = pageWidth;
5646
+ const singlePageH = pageHeight;
5602
5647
  const availW = Math.max(280, ctx.container.clientWidth - 32);
5603
5648
  const availH = Math.max(280, ctx.container.clientHeight - 32);
5604
5649
  const sW = availW / elW;
@@ -5611,8 +5656,7 @@ var RtfPlugin = class {
5611
5656
  const applyTransform = () => {
5612
5657
  wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5613
5658
  wrapper.style.transformOrigin = "top center";
5614
- const activeEl = pageElements[currentPage - 1];
5615
- const baseH = activeEl?.offsetHeight || 1056;
5659
+ const baseH = pageHeight;
5616
5660
  const scaledH = baseH * scale;
5617
5661
  const extraH = Math.max(0, scaledH - baseH);
5618
5662
  wrapper.style.marginBottom = `${extraH + 32}px`;
@@ -5632,140 +5676,220 @@ var RtfPlugin = class {
5632
5676
  if (typeof RTFJS__namespace.loggingEnabled === "function") {
5633
5677
  RTFJS__namespace.loggingEnabled(false);
5634
5678
  }
5635
- const rawText = new TextDecoder("latin1").decode(ctx.buffer);
5636
- const tables = parseRtfTables(rawText);
5637
- const doc = new RTFJS__namespace.Document(ctx.buffer, {});
5638
- const htmlElements = await doc.render();
5639
- const contentNodes = [];
5640
- const extractBlocks = (nodes) => {
5641
- for (const item of nodes) {
5642
- if (!item || !(item instanceof HTMLElement)) continue;
5643
- const tag = item.tagName.toLowerCase();
5644
- const hasChildBlocks = Array.from(item.children).some((c) => {
5645
- const ct = c.tagName.toLowerCase();
5646
- return ["p", "div", "table", "h1", "h2", "h3", "h4", "h5", "h6", "section", "article", "ul", "ol"].includes(ct);
5647
- });
5648
- if (hasChildBlocks && !["table", "tr", "td", "th", "ul", "ol", "li"].includes(tag)) {
5649
- extractBlocks(Array.from(item.children));
5650
- } else {
5651
- const svgs = item.querySelectorAll("svg, img");
5652
- svgs.forEach((s) => {
5653
- const el = s;
5654
- el.style.maxWidth = "100%";
5655
- el.style.maxHeight = "360px";
5656
- el.style.display = "block";
5657
- el.style.margin = "12px auto";
5658
- if (s.tagName.toLowerCase() === "svg") {
5659
- s.removeAttribute("width");
5660
- s.removeAttribute("height");
5661
- el.style.width = "100%";
5662
- el.style.maxHeight = "360px";
5663
- }
5664
- });
5665
- if (tag === "p" || tag === "div") {
5666
- item.style.display = "block";
5667
- item.style.marginBottom = "12px";
5668
- item.style.lineHeight = "1.6";
5669
- }
5670
- contentNodes.push(item);
5671
- }
5679
+ const doc = new RTFJS__namespace.Document(ctx.buffer, {
5680
+ onPicture: (isLegacy, createPic) => {
5681
+ if (isLegacy === true) return null;
5682
+ return createPic();
5672
5683
  }
5673
- };
5674
- extractBlocks(htmlElements);
5675
- tables.forEach((table) => {
5676
- const tableEl = renderRtfTableElement(table);
5677
- let inserted = false;
5678
- if (table.anchorBefore && table.anchorBefore.length > 10) {
5679
- const keyword = table.anchorBefore.slice(-35).trim();
5680
- for (let i = 0; i < contentNodes.length; i++) {
5681
- if (contentNodes[i].textContent?.includes(keyword)) {
5682
- contentNodes.splice(i + 1, 0, tableEl);
5683
- inserted = true;
5684
- break;
5685
- }
5684
+ });
5685
+ const elements = await doc.render();
5686
+ let unsupportedIndex = 1;
5687
+ const usedTables = /* @__PURE__ */ new Set();
5688
+ for (let i = 0; i < elements.length; i++) {
5689
+ const el = elements[i];
5690
+ const text = el.textContent || "";
5691
+ if (text.includes("[Unsupported image format]")) {
5692
+ if (extractedImages[unsupportedIndex]) {
5693
+ const img = document.createElement("img");
5694
+ img.src = extractedImages[unsupportedIndex].dataUrl;
5695
+ img.style.width = "100%";
5696
+ img.style.height = "auto";
5697
+ img.style.maxHeight = "430px";
5698
+ img.style.objectFit = "contain";
5699
+ img.style.display = "block";
5700
+ img.style.margin = "12px auto";
5701
+ el.innerHTML = "";
5702
+ el.appendChild(img);
5703
+ unsupportedIndex++;
5686
5704
  }
5687
5705
  }
5688
- if (!inserted && table.anchorAfter && table.anchorAfter.length > 10) {
5689
- const keyword = table.anchorAfter.slice(0, 35).trim();
5690
- for (let i = 0; i < contentNodes.length; i++) {
5691
- if (contentNodes[i].textContent?.includes(keyword)) {
5692
- contentNodes.splice(i, 0, tableEl);
5693
- inserted = true;
5694
- break;
5706
+ if (tables.length > 0) {
5707
+ for (let t = 0; t < tables.length; t++) {
5708
+ if (usedTables.has(t)) continue;
5709
+ const tbl = tables[t];
5710
+ if (tbl.rows.length >= 2) {
5711
+ const sampleCell1 = tbl.rows[1]?.[1] || tbl.rows[0]?.[1] || "";
5712
+ const sampleCell2 = tbl.rows[2]?.[1] || tbl.rows[1]?.[0] || "";
5713
+ const match1 = sampleCell1 && text.includes(sampleCell1.slice(0, 15).trim());
5714
+ const match2 = sampleCell2 && text.includes(sampleCell2.slice(0, 15).trim());
5715
+ if (match1 && match2) {
5716
+ el.innerHTML = "";
5717
+ el.appendChild(renderRtfTableElement(tbl));
5718
+ usedTables.add(t);
5719
+ break;
5720
+ }
5695
5721
  }
5696
5722
  }
5697
5723
  }
5698
- if (!inserted) {
5699
- if (contentNodes.length > 2) {
5700
- contentNodes.splice(2, 0, tableEl);
5701
- } else {
5702
- contentNodes.push(tableEl);
5703
- }
5724
+ }
5725
+ elements.forEach((el) => {
5726
+ const svgs = el.querySelectorAll ? Array.from(el.querySelectorAll("svg")) : [];
5727
+ svgs.forEach((svg) => {
5728
+ svg.removeAttribute("width");
5729
+ svg.removeAttribute("height");
5730
+ svg.style.maxWidth = "100%";
5731
+ svg.style.maxHeight = "430px";
5732
+ svg.style.height = "auto";
5733
+ svg.style.display = "block";
5734
+ svg.style.margin = "12px auto";
5735
+ });
5736
+ const imgs = el.querySelectorAll ? Array.from(el.querySelectorAll("img")) : [];
5737
+ imgs.forEach((img) => {
5738
+ img.style.maxWidth = "100%";
5739
+ img.style.maxHeight = "430px";
5740
+ img.style.height = "auto";
5741
+ img.style.objectFit = "contain";
5742
+ img.style.display = "block";
5743
+ img.style.margin = "12px auto";
5744
+ });
5745
+ });
5746
+ const allImgs = Array.from(document.querySelectorAll("img")).concat(
5747
+ elements.flatMap((el) => Array.from(el.querySelectorAll ? el.querySelectorAll("img") : []))
5748
+ );
5749
+ await Promise.all(allImgs.map((img) => {
5750
+ if (img.complete && img.naturalHeight > 0) return Promise.resolve();
5751
+ if (img.decode) return img.decode().catch(() => {
5752
+ });
5753
+ return new Promise((r) => {
5754
+ img.onload = r;
5755
+ img.onerror = r;
5756
+ });
5757
+ }));
5758
+ elements.forEach((el) => {
5759
+ const text = el.textContent || "";
5760
+ if (text.includes("\uF0B7")) {
5761
+ const cleanText = text.replace(/^[\s\uf0b7\t]+/, "");
5762
+ el.style.display = "flex";
5763
+ el.style.alignItems = "flex-start";
5764
+ el.style.margin = "6px 0 6px 28px";
5765
+ el.style.fontSize = "11pt";
5766
+ el.style.lineHeight = "1.5";
5767
+ el.innerHTML = `<span style="margin-right:10px; user-select:none;">&#9633;</span><span>${cleanText}</span>`;
5704
5768
  }
5705
5769
  });
5706
- wrapper.innerHTML = "";
5707
- contentNodes.forEach((node) => wrapper.appendChild(node));
5708
- const childHeights = contentNodes.map((c) => {
5709
- const rectH = c.getBoundingClientRect ? c.getBoundingClientRect().height : 0;
5710
- const offH = c.offsetHeight || 0;
5711
- const realH = Math.max(rectH, offH);
5712
- if (realH > 0) return realH;
5713
- const textLen = c.textContent?.trim().length || 0;
5714
- return Math.max(24, Math.ceil(textLen / 95) * 22 + 12);
5770
+ elements.forEach((el) => {
5771
+ const text = (el.textContent || "").trim();
5772
+ const hasMedia = el.querySelector("img, svg, canvas, table") !== null || ["IMG", "SVG", "TABLE"].includes(el.tagName);
5773
+ if (isHeadingElement(el)) {
5774
+ el.style.marginTop = "20px";
5775
+ el.style.marginBottom = "10px";
5776
+ el.style.lineHeight = "1.25";
5777
+ } else if (text.length > 0 && !hasMedia) {
5778
+ el.style.marginBottom = "12px";
5779
+ el.style.lineHeight = "1.45";
5780
+ }
5715
5781
  });
5716
- wrapper.innerHTML = "";
5717
- const createRtfCard = () => {
5782
+ const measureCard = document.createElement("div");
5783
+ measureCard.style.width = `${pageWidth}px`;
5784
+ measureCard.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
5785
+ measureCard.style.boxSizing = "border-box";
5786
+ measureCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5787
+ measureCard.style.lineHeight = "1.45";
5788
+ measureCard.style.visibility = "hidden";
5789
+ measureCard.style.position = "absolute";
5790
+ measureCard.style.top = "-99999px";
5791
+ document.body.appendChild(measureCard);
5792
+ const createPageCard = (num) => {
5718
5793
  const card = document.createElement("div");
5719
5794
  card.className = "fp-rtf-page-card";
5795
+ card.setAttribute("data-page-number", String(num));
5720
5796
  card.style.backgroundColor = "#ffffff";
5721
- card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
5797
+ card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08), 0 1px 3px rgba(0,0,0,0.04)";
5722
5798
  card.style.borderRadius = "4px";
5723
- card.style.padding = "64px 56px";
5724
- card.style.width = "816px";
5725
- card.style.minHeight = "1056px";
5799
+ card.style.width = `${pageWidth}px`;
5800
+ card.style.height = `${pageHeight}px`;
5801
+ card.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
5726
5802
  card.style.boxSizing = "border-box";
5803
+ card.style.overflow = "hidden";
5727
5804
  card.style.marginBottom = "24px";
5728
- card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5729
- card.style.lineHeight = "1.6";
5730
5805
  card.style.color = "#1e293b";
5806
+ card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5807
+ card.style.lineHeight = "1.45";
5808
+ card.style.position = "relative";
5809
+ card.style.textAlign = "left";
5731
5810
  return card;
5732
5811
  };
5733
- let curCard = createRtfCard();
5734
- wrapper.appendChild(curCard);
5735
- pageElements = [curCard];
5736
- let curH = 0;
5737
- const maxH = 928;
5738
- for (let i = 0; i < contentNodes.length; i++) {
5739
- const child = contentNodes[i];
5740
- const chH = childHeights[i];
5741
- const isChildEmpty = (child.textContent || "").trim().length === 0 && !child.querySelector("table, img, svg, canvas");
5742
- if (curH === 0 && isChildEmpty) {
5812
+ const pages = [];
5813
+ let curCard = createPageCard(1);
5814
+ pages.push(curCard);
5815
+ let curHeight = 0;
5816
+ for (let i = 0; i < elements.length; i++) {
5817
+ const el = elements[i];
5818
+ if (!el || !(el instanceof HTMLElement)) continue;
5819
+ const text = (el.textContent || "").trim();
5820
+ const hasMedia = el.querySelector("img, svg, canvas, table") !== null || ["IMG", "SVG", "TABLE"].includes(el.tagName);
5821
+ const isEmptyPar = !hasMedia && text.length === 0;
5822
+ if (isEmptyPar) {
5823
+ const emptyH = 35;
5824
+ if (curHeight + emptyH > printableHeight) {
5825
+ if (curCard.childNodes.length > 0) {
5826
+ curCard = createPageCard(pages.length + 1);
5827
+ pages.push(curCard);
5828
+ curHeight = 0;
5829
+ }
5830
+ }
5831
+ const spacer = document.createElement("div");
5832
+ spacer.style.height = `${emptyH}px`;
5833
+ curCard.appendChild(spacer);
5834
+ curHeight += emptyH;
5743
5835
  continue;
5744
5836
  }
5745
- if (curH + chH > maxH && curCard.childNodes.length > 0) {
5746
- curCard = createRtfCard();
5747
- wrapper.appendChild(curCard);
5748
- pageElements.push(curCard);
5749
- curH = 0;
5837
+ measureCard.innerHTML = "";
5838
+ const clone = el.cloneNode(true);
5839
+ measureCard.appendChild(clone);
5840
+ const compStyle = window.getComputedStyle(clone);
5841
+ const mt = parseFloat(compStyle.marginTop) || 0;
5842
+ const mb = parseFloat(compStyle.marginBottom) || 0;
5843
+ const elH = clone.offsetHeight + mt + mb;
5844
+ const isHeading = isHeadingElement(el);
5845
+ let nextContentH = 0;
5846
+ if (isHeading || hasMedia) {
5847
+ for (let j = i + 1; j < elements.length; j++) {
5848
+ const nextEl = elements[j];
5849
+ if (nextEl && (nextEl.textContent || "").trim().length > 0) {
5850
+ measureCard.innerHTML = "";
5851
+ const nClone = nextEl.cloneNode(true);
5852
+ measureCard.appendChild(nClone);
5853
+ const nStyle = window.getComputedStyle(nClone);
5854
+ nextContentH = nClone.offsetHeight + (parseFloat(nStyle.marginTop) || 0) + (parseFloat(nStyle.marginBottom) || 0);
5855
+ break;
5856
+ }
5857
+ }
5750
5858
  }
5751
- curCard.appendChild(child);
5752
- curH += chH;
5753
- }
5754
- pageElements = pageElements.filter((card) => {
5859
+ const remainingSpace = printableHeight - curHeight;
5860
+ const isLargeMedia = hasMedia && elH > 300;
5861
+ const keepWithNextOverflow = isHeading && nextContentH > 0 && elH + nextContentH + 20 > remainingSpace;
5862
+ const largeMediaOverflow = isLargeMedia && curHeight > 0 && elH + 80 > remainingSpace;
5863
+ const shouldBreak = (curHeight + elH > printableHeight || keepWithNextOverflow || largeMediaOverflow) && curCard.childNodes.length > 0;
5864
+ if (shouldBreak) {
5865
+ curCard = createPageCard(pages.length + 1);
5866
+ pages.push(curCard);
5867
+ curHeight = 0;
5868
+ }
5869
+ curCard.appendChild(el);
5870
+ curHeight += elH;
5871
+ }
5872
+ measureCard.remove();
5873
+ pageElements = pages.filter((card) => {
5755
5874
  const hasText = (card.textContent || "").trim().length > 0;
5756
- const hasMedia = card.querySelector("table, img, svg, canvas") !== null;
5757
- return hasText || hasMedia;
5875
+ const hasCardMedia = card.querySelector("table, img, svg, canvas") !== null;
5876
+ return hasText || hasCardMedia;
5758
5877
  });
5759
5878
  if (pageElements.length === 0) {
5760
5879
  pageElements = [curCard];
5761
5880
  }
5881
+ wrapper.innerHTML = "";
5882
+ pageElements.forEach((card, idx) => {
5883
+ card.setAttribute("data-page-number", String(idx + 1));
5884
+ card.style.display = idx === 0 ? "block" : "none";
5885
+ wrapper.appendChild(card);
5886
+ });
5762
5887
  } catch (err) {
5763
5888
  console.warn("[RtfPlugin] RTF render error, fallback text:", err);
5764
- const text = new TextDecoder("latin1").decode(ctx.buffer);
5765
- const tables = parseRtfTables(text);
5889
+ const text = rawRtf;
5766
5890
  const rawPages = text.split(/\\page\b/).map((segment) => {
5767
5891
  return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
5768
- }).filter((p) => p.length > 0);
5892
+ }).filter((p2) => p2.length > 0);
5769
5893
  const pages = rawPages.length > 0 ? rawPages : [text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim()];
5770
5894
  for (let i = 0; i < pages.length; i++) {
5771
5895
  const pageCard = document.createElement("div");
@@ -5773,9 +5897,9 @@ var RtfPlugin = class {
5773
5897
  pageCard.style.backgroundColor = "#ffffff";
5774
5898
  pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
5775
5899
  pageCard.style.borderRadius = "4px";
5776
- pageCard.style.padding = "64px 56px";
5777
- pageCard.style.width = "816px";
5778
- pageCard.style.minHeight = "1056px";
5900
+ pageCard.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
5901
+ pageCard.style.width = `${pageWidth}px`;
5902
+ pageCard.style.minHeight = `${pageHeight}px`;
5779
5903
  pageCard.style.boxSizing = "border-box";
5780
5904
  pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5781
5905
  pageCard.style.fontSize = "12pt";
@@ -5795,11 +5919,9 @@ var RtfPlugin = class {
5795
5919
  let currentPage = 1;
5796
5920
  const showPage = (pageNum) => {
5797
5921
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
5798
- if (totalPages > 1) {
5799
- pageElements.forEach((el, idx) => {
5800
- el.style.display = idx + 1 === currentPage ? "block" : "none";
5801
- });
5802
- }
5922
+ pageElements.forEach((el, idx) => {
5923
+ el.style.display = idx + 1 === currentPage ? "block" : "none";
5924
+ });
5803
5925
  ctx.container.scrollTop = 0;
5804
5926
  ctx.emit("page-change", { page: currentPage, total: totalPages });
5805
5927
  };