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