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