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