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

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