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

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/index.cjs CHANGED
@@ -610,6 +610,7 @@ var ICON_COPY = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" str
610
610
  var ICON_FAST_FORWARD = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 19 22 12 13 5 13 19"></polygon><polygon points="2 19 11 12 2 5 2 19"></polygon></svg>`;
611
611
  var ICON_REWIND = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="11 19 2 12 11 5 11 19"></polygon><polygon points="22 19 13 12 22 5 22 19"></polygon></svg>`;
612
612
  var ICON_EXTERNAL_WINDOW = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"></rect><line x1="3" y1="8" x2="21" y2="8"></line><circle cx="6" cy="5.5" r="0.75" fill="currentColor"></circle><circle cx="8.5" cy="5.5" r="0.75" fill="currentColor"></circle><polyline points="14 13 18 13 18 17"></polyline><line x1="11" y1="20" x2="18" y2="13"></line></svg>`;
613
+ var ICON_RESET_ZOOM = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line><path d="M13 11a3 3 0 1 0-3 3"></path><path d="M10 11v3h3"></path></svg>`;
613
614
  var ICON_MAP = {
614
615
  "zoom-in": ICON_ZOOM_IN,
615
616
  "zoom-out": ICON_ZOOM_OUT,
@@ -639,7 +640,10 @@ var ICON_MAP = {
639
640
  "open-window": ICON_EXTERNAL_WINDOW,
640
641
  "external-window": ICON_EXTERNAL_WINDOW,
641
642
  "openWindow": ICON_EXTERNAL_WINDOW,
642
- "openSeparateWindow": ICON_EXTERNAL_WINDOW
643
+ "openSeparateWindow": ICON_EXTERNAL_WINDOW,
644
+ "reset-zoom": ICON_RESET_ZOOM,
645
+ "zoom-reset": ICON_RESET_ZOOM,
646
+ "resetZoom": ICON_RESET_ZOOM
643
647
  };
644
648
  var ToolbarController = class {
645
649
  el;
@@ -672,6 +676,10 @@ var ToolbarController = class {
672
676
  this.config.fitToPage = false;
673
677
  this.config.fitWidth = false;
674
678
  }
679
+ if (actionId === "reset-zoom" || actionId === "zoom-reset" || actionId === "resetZoom") {
680
+ this.config.resetZoom = false;
681
+ this.config.zoomReset = false;
682
+ }
675
683
  if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = false;
676
684
  if (actionId === "fullscreen") this.config.fullscreen = false;
677
685
  if (actionId === "download") this.config.download = false;
@@ -696,6 +704,10 @@ var ToolbarController = class {
696
704
  this.config.fitToPage = true;
697
705
  this.config.fitWidth = true;
698
706
  }
707
+ if (actionId === "reset-zoom" || actionId === "zoom-reset" || actionId === "resetZoom") {
708
+ this.config.resetZoom = true;
709
+ this.config.zoomReset = true;
710
+ }
699
711
  if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = true;
700
712
  if (actionId === "fullscreen") this.config.fullscreen = true;
701
713
  if (actionId === "download") this.config.download = true;
@@ -715,6 +727,7 @@ var ToolbarController = class {
715
727
  if (actionId === "zoomIn") return "zoom-in";
716
728
  if (actionId === "zoomOut") return "zoom-out";
717
729
  if (actionId === "fitPage" || actionId === "fitToPage" || actionId === "fitWidth") return "fit-page";
730
+ if (actionId === "resetZoom" || actionId === "zoomReset") return "reset-zoom";
718
731
  if (actionId === "rotateCW") return "rotate-cw";
719
732
  if (actionId === "rotateCCW") return "rotate-ccw";
720
733
  if (actionId === "openWindow" || actionId === "openSeparateWindow") return "open-window";
@@ -757,6 +770,9 @@ var ToolbarController = class {
757
770
  if ((id === "fit-page" || id === "fit-width" || id === "fit-slide") && (c.fitPage === false || c.fitToPage === false || c.fitWidth === false || c["fit-page"] === false || c["fit-width"] === false)) {
758
771
  return false;
759
772
  }
773
+ if ((id === "reset-zoom" || id === "zoom-reset") && (c.resetZoom === false || c.zoomReset === false || c["reset-zoom"] === false || c["zoom-reset"] === false)) {
774
+ return false;
775
+ }
760
776
  if ((id === "rotate-cw" || id === "rotate-ccw" || id === "rotate") && (c.rotate === false || c.rotateCW === false || c.rotateCCW === false || c["rotate-cw"] === false)) {
761
777
  return false;
762
778
  }
@@ -1203,6 +1219,9 @@ var FilePreviewViewer = class _FilePreviewViewer {
1203
1219
  this.activeInstance = instance;
1204
1220
  instance.openInSeparateWindow = () => this.openInSeparateWindow();
1205
1221
  instance.toggleThumbnails = () => this.toggleThumbnails();
1222
+ if (!instance.resetZoom && instance.fitToPage) {
1223
+ instance.resetZoom = () => instance.fitToPage?.();
1224
+ }
1206
1225
  this.hideLoading();
1207
1226
  this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
1208
1227
  const isToolbarVisible = options.showToolbar !== false && options.toolbar !== false;
@@ -1486,6 +1505,16 @@ var FilePreviewViewer = class _FilePreviewViewer {
1486
1505
  fitToPage() {
1487
1506
  this.activeInstance?.fitToPage?.();
1488
1507
  }
1508
+ /**
1509
+ * Reset zoom level to initial/default fit state.
1510
+ */
1511
+ resetZoom() {
1512
+ if (this.activeInstance?.resetZoom) {
1513
+ this.activeInstance.resetZoom();
1514
+ } else if (this.activeInstance?.fitToPage) {
1515
+ this.activeInstance.fitToPage();
1516
+ }
1517
+ }
1489
1518
  /**
1490
1519
  * Zoom in.
1491
1520
  */
@@ -2107,6 +2136,14 @@ var PdfPlugin = class {
2107
2136
  group: "zoom",
2108
2137
  execute: () => instance.fitToPage?.()
2109
2138
  },
2139
+ {
2140
+ id: "reset-zoom",
2141
+ icon: "reset-zoom",
2142
+ label: "Reset Zoom",
2143
+ type: "button",
2144
+ group: "zoom",
2145
+ execute: () => instance.resetZoom?.()
2146
+ },
2110
2147
  {
2111
2148
  id: "fit-width",
2112
2149
  icon: "fit-width",
@@ -2369,6 +2406,14 @@ var PdfPlugin = class {
2369
2406
  zoomScale = 1;
2370
2407
  renderPage(currentPage);
2371
2408
  },
2409
+ resetZoom: () => {
2410
+ fitMode = "page";
2411
+ zoomScale = 1;
2412
+ rotation = 0;
2413
+ container.scrollTop = 0;
2414
+ container.scrollLeft = 0;
2415
+ renderPage(currentPage);
2416
+ },
2372
2417
  fitToWidth: () => {
2373
2418
  fitMode = "width";
2374
2419
  zoomScale = 1;
@@ -2536,6 +2581,16 @@ var MediaPlugin = class {
2536
2581
  instance.fitToPage?.();
2537
2582
  }
2538
2583
  },
2584
+ {
2585
+ id: "reset-zoom",
2586
+ icon: "reset-zoom",
2587
+ label: "Reset Zoom",
2588
+ type: "button",
2589
+ group: "zoom",
2590
+ execute: () => {
2591
+ instance.resetZoom?.();
2592
+ }
2593
+ },
2539
2594
  {
2540
2595
  id: "rotate-cw",
2541
2596
  icon: "rotate-cw",
@@ -2709,6 +2764,13 @@ var MediaPlugin = class {
2709
2764
  rotation = 0;
2710
2765
  applyTransform();
2711
2766
  } : void 0,
2767
+ resetZoom: isImage ? () => {
2768
+ currentZoom = 1;
2769
+ rotation = 0;
2770
+ ctx.container.scrollTop = 0;
2771
+ ctx.container.scrollLeft = 0;
2772
+ applyTransform();
2773
+ } : void 0,
2712
2774
  rotateCW: isImage || isVideo ? () => {
2713
2775
  rotation = (rotation + 90) % 360;
2714
2776
  applyTransform();
@@ -2825,6 +2887,14 @@ var DocxPlugin = class {
2825
2887
  group: "zoom",
2826
2888
  execute: () => instance.fitToPage?.()
2827
2889
  },
2890
+ {
2891
+ id: "reset-zoom",
2892
+ icon: "reset-zoom",
2893
+ label: "Reset Zoom",
2894
+ type: "button",
2895
+ group: "zoom",
2896
+ execute: () => instance.resetZoom?.()
2897
+ },
2828
2898
  {
2829
2899
  id: "rotate-cw",
2830
2900
  icon: "rotate-cw",
@@ -3141,6 +3211,14 @@ var DocxPlugin = class {
3141
3211
  rotation = 0;
3142
3212
  applyTransform();
3143
3213
  },
3214
+ resetZoom: () => {
3215
+ isUserZoomed = false;
3216
+ scale = calculateFitScale("page");
3217
+ rotation = 0;
3218
+ ctx.container.scrollTop = 0;
3219
+ ctx.container.scrollLeft = 0;
3220
+ applyTransform();
3221
+ },
3144
3222
  rotateCW: () => {
3145
3223
  rotation = (rotation + 90) % 360;
3146
3224
  applyTransform();
@@ -3590,6 +3668,16 @@ var ExcelPlugin = class {
3590
3668
  instance.zoomIn?.();
3591
3669
  }
3592
3670
  },
3671
+ {
3672
+ id: "reset-zoom",
3673
+ icon: "reset-zoom",
3674
+ label: "Reset Zoom",
3675
+ type: "button",
3676
+ group: "zoom",
3677
+ execute: () => {
3678
+ instance.resetZoom?.();
3679
+ }
3680
+ },
3593
3681
  {
3594
3682
  id: "download",
3595
3683
  icon: "download",
@@ -3777,6 +3865,12 @@ var ExcelPlugin = class {
3777
3865
  scale = calculateFitScale();
3778
3866
  applyTransform();
3779
3867
  },
3868
+ resetZoom: () => {
3869
+ scale = calculateFitScale();
3870
+ contentArea.scrollTop = 0;
3871
+ contentArea.scrollLeft = 0;
3872
+ applyTransform();
3873
+ },
3780
3874
  rotateCW: () => {
3781
3875
  },
3782
3876
  rotateCCW: () => {
@@ -3907,6 +4001,16 @@ var CsvPlugin = class {
3907
4001
  instance.zoomIn?.();
3908
4002
  }
3909
4003
  },
4004
+ {
4005
+ id: "reset-zoom",
4006
+ icon: "reset-zoom",
4007
+ label: "Reset Zoom",
4008
+ type: "button",
4009
+ group: "zoom",
4010
+ execute: () => {
4011
+ instance.resetZoom?.();
4012
+ }
4013
+ },
3910
4014
  {
3911
4015
  id: "download",
3912
4016
  icon: "download",
@@ -4096,6 +4200,12 @@ var CsvPlugin = class {
4096
4200
  scale = calculateFitScale();
4097
4201
  applyScale();
4098
4202
  },
4203
+ resetZoom: () => {
4204
+ scale = calculateFitScale();
4205
+ container.scrollTop = 0;
4206
+ container.scrollLeft = 0;
4207
+ applyScale();
4208
+ },
4099
4209
  rotateCW: () => {
4100
4210
  },
4101
4211
  rotateCCW: () => {
@@ -4211,6 +4321,16 @@ var CodePlugin = class {
4211
4321
  instance.zoomIn?.();
4212
4322
  }
4213
4323
  },
4324
+ {
4325
+ id: "reset-zoom",
4326
+ icon: "reset-zoom",
4327
+ label: "Reset Zoom",
4328
+ type: "button",
4329
+ group: "zoom",
4330
+ execute: () => {
4331
+ instance.resetZoom?.();
4332
+ }
4333
+ },
4214
4334
  {
4215
4335
  id: "copy",
4216
4336
  icon: "copy",
@@ -4490,6 +4610,15 @@ var CodePlugin = class {
4490
4610
  zoomLevel = isTxt ? calculateTxtFit() : 1;
4491
4611
  updateTransform();
4492
4612
  },
4613
+ resetZoom: () => {
4614
+ isUserZoomed = false;
4615
+ fontSize = 13;
4616
+ rotation = 0;
4617
+ zoomLevel = isTxt ? calculateTxtFit() : 1;
4618
+ container.scrollTop = 0;
4619
+ container.scrollLeft = 0;
4620
+ updateTransform();
4621
+ },
4493
4622
  rotateCW: () => {
4494
4623
  rotation = (rotation + 90) % 360;
4495
4624
  updateTransform();
@@ -4552,11 +4681,19 @@ var ArchivePlugin = class {
4552
4681
  {
4553
4682
  id: "fit-page",
4554
4683
  icon: "fit-page",
4555
- label: "Reset Zoom",
4684
+ label: "Fit to Page",
4556
4685
  type: "button",
4557
4686
  group: "zoom",
4558
4687
  execute: () => instance.fitToPage?.()
4559
4688
  },
4689
+ {
4690
+ id: "reset-zoom",
4691
+ icon: "reset-zoom",
4692
+ label: "Reset Zoom",
4693
+ type: "button",
4694
+ group: "zoom",
4695
+ execute: () => instance.resetZoom?.()
4696
+ },
4560
4697
  {
4561
4698
  id: "download",
4562
4699
  icon: "download",
@@ -4711,7 +4848,13 @@ var ArchivePlugin = class {
4711
4848
  },
4712
4849
  fitToPage: () => {
4713
4850
  scale = 1;
4714
- wrapper.style.transform = `scale(1)`;
4851
+ wrapper.style.transform = "scale(1)";
4852
+ },
4853
+ resetZoom: () => {
4854
+ scale = 1;
4855
+ wrapper.style.transform = "scale(1)";
4856
+ ctx.container.scrollTop = 0;
4857
+ ctx.container.scrollLeft = 0;
4715
4858
  },
4716
4859
  download: () => {
4717
4860
  downloadFile(ctx.buffer, ctx.metadata.name || "archive.zip", "application/zip");
@@ -4763,6 +4906,14 @@ var MarkdownPlugin = class {
4763
4906
  group: "zoom",
4764
4907
  execute: () => instance.fitToPage?.()
4765
4908
  },
4909
+ {
4910
+ id: "reset-zoom",
4911
+ icon: "reset-zoom",
4912
+ label: "Reset Zoom",
4913
+ type: "button",
4914
+ group: "zoom",
4915
+ execute: () => instance.resetZoom?.()
4916
+ },
4766
4917
  {
4767
4918
  id: "copy",
4768
4919
  icon: "copy",
@@ -4916,6 +5067,12 @@ var MarkdownPlugin = class {
4916
5067
  fontSize = 15;
4917
5068
  wrapper.style.fontSize = "15px";
4918
5069
  },
5070
+ resetZoom: () => {
5071
+ fontSize = 15;
5072
+ wrapper.style.fontSize = "15px";
5073
+ ctx.container.scrollTop = 0;
5074
+ ctx.container.scrollLeft = 0;
5075
+ },
4919
5076
  download: () => {
4920
5077
  downloadFile(ctx.buffer, ctx.metadata.name || "document.md", "text/markdown");
4921
5078
  },
@@ -5009,6 +5166,14 @@ var PptxPlugin = class {
5009
5166
  group: "zoom",
5010
5167
  execute: () => instance.fitToPage?.()
5011
5168
  },
5169
+ {
5170
+ id: "reset-zoom",
5171
+ icon: "reset-zoom",
5172
+ label: "Reset Zoom",
5173
+ type: "button",
5174
+ group: "zoom",
5175
+ execute: () => instance.resetZoom?.()
5176
+ },
5012
5177
  {
5013
5178
  id: "rotate-cw",
5014
5179
  icon: "rotate-cw",
@@ -5128,6 +5293,13 @@ var PptxPlugin = class {
5128
5293
  rotation = 0;
5129
5294
  applyTransform();
5130
5295
  },
5296
+ resetZoom: () => {
5297
+ scale = calculateFitScale();
5298
+ rotation = 0;
5299
+ wrapper.scrollTop = 0;
5300
+ wrapper.scrollLeft = 0;
5301
+ applyTransform();
5302
+ },
5131
5303
  rotateCW: () => {
5132
5304
  rotation = (rotation + 90) % 360;
5133
5305
  applyTransform();
@@ -5203,6 +5375,14 @@ var ThreeDPlugin = class {
5203
5375
  group: "zoom",
5204
5376
  execute: () => instance.fitToPage?.()
5205
5377
  },
5378
+ {
5379
+ id: "reset-zoom",
5380
+ icon: "reset-zoom",
5381
+ label: "Reset Zoom",
5382
+ type: "button",
5383
+ group: "zoom",
5384
+ execute: () => instance.resetZoom?.()
5385
+ },
5206
5386
  {
5207
5387
  id: "rotate-cw",
5208
5388
  icon: "rotate-cw",
@@ -5339,6 +5519,7 @@ var ThreeDPlugin = class {
5339
5519
  controls.update();
5340
5520
  },
5341
5521
  fitToPage: fitCamera,
5522
+ resetZoom: fitCamera,
5342
5523
  rotateCW: () => {
5343
5524
  isWireframe = !isWireframe;
5344
5525
  materials.forEach((m) => {
@@ -5361,7 +5542,7 @@ function cleanRtfText(raw) {
5361
5542
  return String.fromCharCode(num);
5362
5543
  }).replace(/\\'([0-9a-fA-F]{2})/g, (_, hex) => {
5363
5544
  return String.fromCharCode(parseInt(hex, 16));
5364
- }).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();
5545
+ }).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();
5365
5546
  }
5366
5547
  function parseRtfTables(rtfText) {
5367
5548
  const rowSegments = rtfText.split(/\\row\b/);
@@ -5401,17 +5582,12 @@ function parseRtfTables(rtfText) {
5401
5582
  }
5402
5583
  const isNewTable = !currentTable || segmentStart - currentTable.lastEnd > 2500;
5403
5584
  if (isNewTable) {
5404
- const prevTextSlice = rtfText.slice(Math.max(0, segmentStart - 4e3), segmentStart);
5405
- const cleanPrev = cleanRtfText(prevTextSlice);
5406
- const anchorBefore = cleanPrev.slice(-80).trim();
5407
5585
  currentTable = {
5408
5586
  id: `RTF_TABLE_${rawTables.length}`,
5409
5587
  startPos: segmentStart,
5410
5588
  lastEnd: segmentEnd,
5411
5589
  rows: [],
5412
- columnWidths: cellWidths,
5413
- anchorBefore,
5414
- anchorAfter: ""
5590
+ columnWidths: cellWidths
5415
5591
  };
5416
5592
  rawTables.push(currentTable);
5417
5593
  }
@@ -5425,20 +5601,13 @@ function parseRtfTables(rtfText) {
5425
5601
  }
5426
5602
  charOffset += segment.length + 4;
5427
5603
  }
5428
- rawTables.forEach((tbl) => {
5429
- const afterSlice = rtfText.slice(tbl.lastEnd, Math.min(rtfText.length, tbl.lastEnd + 2e3));
5430
- const cleanAfter = cleanRtfText(afterSlice);
5431
- tbl.anchorAfter = cleanAfter.slice(0, 80).trim();
5432
- });
5433
5604
  return rawTables.map((tbl) => {
5434
5605
  const totalW = (tbl.columnWidths || []).reduce((a, b) => a + b, 0);
5435
5606
  const colPercents = totalW > 0 ? tbl.columnWidths.map((w) => Math.round(w / totalW * 100)) : [];
5436
5607
  return {
5437
5608
  id: tbl.id,
5438
5609
  rows: tbl.rows.map((r) => r.cells),
5439
- colPercents,
5440
- anchorBefore: tbl.anchorBefore,
5441
- anchorAfter: tbl.anchorAfter
5610
+ colPercents
5442
5611
  };
5443
5612
  });
5444
5613
  }
@@ -5451,8 +5620,6 @@ function renderRtfTableElement(table) {
5451
5620
  tableEl.style.fontSize = "10pt";
5452
5621
  tableEl.style.lineHeight = "1.5";
5453
5622
  tableEl.style.border = "1px solid #cbd5e1";
5454
- tableEl.style.borderRadius = "4px";
5455
- tableEl.style.boxSizing = "border-box";
5456
5623
  tableEl.style.backgroundColor = "#ffffff";
5457
5624
  const thead = document.createElement("thead");
5458
5625
  const tbody = document.createElement("tbody");
@@ -5461,27 +5628,17 @@ function renderRtfTableElement(table) {
5461
5628
  const isHeader = rIdx === 0;
5462
5629
  if (isHeader) {
5463
5630
  tr.style.backgroundColor = "#f8fafc";
5464
- tr.style.borderBottom = "2px solid #cbd5e1";
5465
- } else {
5466
- tr.style.borderBottom = "1px solid #e2e8f0";
5467
- if (rIdx % 2 === 0) {
5468
- tr.style.backgroundColor = "#fcfdfe";
5469
- }
5470
5631
  }
5471
5632
  rowCells.forEach((cellText, cIdx) => {
5472
5633
  const cellEl = document.createElement(isHeader ? "th" : "td");
5473
5634
  cellEl.style.padding = "8px 12px";
5474
5635
  cellEl.style.border = "1px solid #cbd5e1";
5475
5636
  cellEl.style.verticalAlign = "top";
5476
- cellEl.style.color = isHeader ? "#0f172a" : "#1e293b";
5477
- cellEl.style.fontWeight = isHeader ? "600" : "normal";
5478
5637
  if (table.colPercents && table.colPercents[cIdx]) {
5479
5638
  cellEl.style.width = `${table.colPercents[cIdx]}%`;
5480
5639
  }
5481
5640
  if (/^\d+$/.test(cellText.trim()) || cellText.trim() === "#") {
5482
5641
  cellEl.style.textAlign = "center";
5483
- } else {
5484
- cellEl.style.textAlign = "left";
5485
5642
  }
5486
5643
  cellEl.textContent = cellText;
5487
5644
  tr.appendChild(cellEl);
@@ -5496,23 +5653,19 @@ function renderRtfTableElement(table) {
5496
5653
  tableEl.appendChild(tbody);
5497
5654
  return tableEl;
5498
5655
  }
5499
- function extractMediaFingerprint(el) {
5500
- const img = el.tagName.toLowerCase() === "img" ? el : el.querySelector("img");
5501
- if (img && img.src) {
5502
- const s = img.src;
5503
- return s.length > 300 ? `img_${s.slice(0, 80)}_${s.length}_${s.slice(-80)}` : `img_${s}`;
5504
- }
5505
- const innerImg = el.querySelector("image");
5506
- if (innerImg) {
5507
- const h = innerImg.getAttribute("xlink:href") || innerImg.getAttribute("href") || "";
5508
- if (h) return h.length > 300 ? `svgimg_${h.slice(0, 80)}_${h.length}_${h.slice(-80)}` : `svgimg_${h}`;
5509
- }
5510
- const svg = el.tagName.toLowerCase() === "svg" ? el : el.querySelector("svg");
5511
- if (svg) {
5512
- const vb = svg.getAttribute("viewBox") || "";
5513
- return `svg_${vb}_${svg.innerHTML.length}`;
5514
- }
5515
- return null;
5656
+ function isHeadingElement(el) {
5657
+ if (["H1", "H2", "H3", "H4"].includes(el.tagName)) return true;
5658
+ const spans = el.querySelectorAll ? Array.from(el.querySelectorAll("span, b, strong, div")) : [];
5659
+ for (const s of spans) {
5660
+ const hEl = s;
5661
+ const fs = parseFloat(hEl.style.fontSize) || 0;
5662
+ const isBold = hEl.style.fontWeight === "bold" || parseInt(hEl.style.fontWeight, 10) >= 600 || ["B", "STRONG"].includes(hEl.tagName);
5663
+ if (isBold && fs >= 14) return true;
5664
+ }
5665
+ const elFs = parseFloat(el.style.fontSize) || 0;
5666
+ const elBold = el.style.fontWeight === "bold" || parseInt(el.style.fontWeight, 10) >= 600;
5667
+ if (elBold && elFs >= 14) return true;
5668
+ return false;
5516
5669
  }
5517
5670
  var RtfPlugin = class {
5518
5671
  id = "rtf";
@@ -5581,6 +5734,14 @@ var RtfPlugin = class {
5581
5734
  group: "zoom",
5582
5735
  execute: () => instance.fitToPage?.()
5583
5736
  },
5737
+ {
5738
+ id: "reset-zoom",
5739
+ icon: "reset-zoom",
5740
+ label: "Reset Zoom",
5741
+ type: "button",
5742
+ group: "zoom",
5743
+ execute: () => instance.resetZoom?.()
5744
+ },
5584
5745
  {
5585
5746
  id: "rotate-cw",
5586
5747
  icon: "rotate-cw",
@@ -5625,10 +5786,66 @@ var RtfPlugin = class {
5625
5786
  return actions;
5626
5787
  }
5627
5788
  async render(ctx) {
5789
+ const rawRtf = new TextDecoder("latin1").decode(ctx.buffer);
5790
+ const paperwMatch = rawRtf.match(/\\paperw(\d+)/);
5791
+ const paperhMatch = rawRtf.match(/\\paperh(\d+)/);
5792
+ const marglMatch = rawRtf.match(/\\margl(\d+)/);
5793
+ const margrMatch = rawRtf.match(/\\margr(\d+)/);
5794
+ const margtMatch = rawRtf.match(/\\margt(\d+)/);
5795
+ const margbMatch = rawRtf.match(/\\margb(\d+)/);
5796
+ const paperwTwips = paperwMatch ? parseInt(paperwMatch[1], 10) : 11906;
5797
+ const paperhTwips = paperhMatch ? parseInt(paperhMatch[1], 10) : 16838;
5798
+ const marglTwips = marglMatch ? parseInt(marglMatch[1], 10) : 1134;
5799
+ const margrTwips = margrMatch ? parseInt(margrMatch[1], 10) : 1134;
5800
+ const margtTwips = margtMatch ? parseInt(margtMatch[1], 10) : 1134;
5801
+ const margbTwips = margbMatch ? parseInt(margbMatch[1], 10) : 1134;
5802
+ const pageWidth = Math.round(paperwTwips / 15);
5803
+ const pageHeight = Math.round(paperhTwips / 15);
5804
+ const padLeft = Math.round(marglTwips / 15);
5805
+ const padRight = Math.round(margrTwips / 15);
5806
+ const padTop = Math.round(margtTwips / 15);
5807
+ const padBottom = Math.round(margbTwips / 15);
5808
+ const printableHeight = pageHeight - padTop - padBottom;
5809
+ const extractedImages = [];
5810
+ let p = 0;
5811
+ while ((p = rawRtf.indexOf("\\pict", p)) !== -1) {
5812
+ const startP = p;
5813
+ p += 5;
5814
+ const header = rawRtf.substring(startP, startP + 600);
5815
+ let mime = "";
5816
+ let magic = "";
5817
+ if (header.includes("\\pngblip")) {
5818
+ mime = "image/png";
5819
+ magic = "89504e47";
5820
+ } else if (header.includes("\\jpegblip")) {
5821
+ mime = "image/jpeg";
5822
+ magic = "ffd8ff";
5823
+ }
5824
+ if (!mime || !magic) continue;
5825
+ const magicPos = rawRtf.indexOf(magic, startP);
5826
+ if (magicPos === -1 || magicPos - startP > 3e3) continue;
5827
+ let endP = magicPos;
5828
+ while (endP < rawRtf.length && /[0-9a-fA-F\r\n\s]/.test(rawRtf[endP])) {
5829
+ endP++;
5830
+ }
5831
+ const cleanHex = rawRtf.substring(magicPos, endP).replace(/[\r\n\s]/g, "");
5832
+ if (cleanHex.length < 100) continue;
5833
+ const hexLen = cleanHex.length / 2;
5834
+ const u8 = new Uint8Array(hexLen);
5835
+ for (let k = 0; k < hexLen; k++) {
5836
+ u8[k] = parseInt(cleanHex.substr(k * 2, 2), 16);
5837
+ }
5838
+ let bStr = "";
5839
+ for (let k = 0; k < u8.length; k += 8192) {
5840
+ bStr += String.fromCharCode.apply(null, Array.from(u8.subarray(k, k + 8192)));
5841
+ }
5842
+ extractedImages.push({ mime, dataUrl: `data:${mime};base64,${btoa(bStr)}`, offset: startP });
5843
+ }
5844
+ const tables = parseRtfTables(rawRtf);
5628
5845
  const wrapper = document.createElement("div");
5629
5846
  wrapper.className = "fp-rtf-wrapper";
5630
5847
  wrapper.style.padding = "0";
5631
- wrapper.style.width = "816px";
5848
+ wrapper.style.width = `${pageWidth}px`;
5632
5849
  wrapper.style.margin = "0 auto";
5633
5850
  wrapper.style.boxSizing = "border-box";
5634
5851
  wrapper.style.display = "flex";
@@ -5648,9 +5865,8 @@ var RtfPlugin = class {
5648
5865
  let isUserZoomed = false;
5649
5866
  let fitMode = ctx?.options?.fitMode || "width";
5650
5867
  const calculateFitScale = (mode = fitMode) => {
5651
- const activeEl = pageElements[currentPage - 1] || wrapper;
5652
- const elW = 816;
5653
- const singlePageH = activeEl?.offsetHeight || 1056;
5868
+ const elW = pageWidth;
5869
+ const singlePageH = pageHeight;
5654
5870
  const availW = Math.max(280, ctx.container.clientWidth - 32);
5655
5871
  const availH = Math.max(280, ctx.container.clientHeight - 32);
5656
5872
  const sW = availW / elW;
@@ -5663,8 +5879,7 @@ var RtfPlugin = class {
5663
5879
  const applyTransform = () => {
5664
5880
  wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5665
5881
  wrapper.style.transformOrigin = "top center";
5666
- const activeEl = pageElements[currentPage - 1];
5667
- const baseH = activeEl?.offsetHeight || 1056;
5882
+ const baseH = pageHeight;
5668
5883
  const scaledH = baseH * scale;
5669
5884
  const extraH = Math.max(0, scaledH - baseH);
5670
5885
  wrapper.style.marginBottom = `${extraH + 32}px`;
@@ -5684,193 +5899,220 @@ var RtfPlugin = class {
5684
5899
  if (typeof RTFJS__namespace.loggingEnabled === "function") {
5685
5900
  RTFJS__namespace.loggingEnabled(false);
5686
5901
  }
5687
- const rawText = new TextDecoder("latin1").decode(ctx.buffer);
5688
- const tables = parseRtfTables(rawText);
5689
- const seenMediaSignatures = /* @__PURE__ */ new Set();
5690
5902
  const doc = new RTFJS__namespace.Document(ctx.buffer, {
5691
5903
  onPicture: (isLegacy, createPic) => {
5692
- if (isLegacy === true) {
5693
- return null;
5694
- }
5695
- const pic = createPic();
5696
- if (!pic) return null;
5697
- const fp = extractMediaFingerprint(pic);
5698
- if (fp) {
5699
- if (seenMediaSignatures.has(fp)) {
5700
- return null;
5701
- }
5702
- seenMediaSignatures.add(fp);
5703
- }
5704
- return pic;
5904
+ if (isLegacy === true) return null;
5905
+ return createPic();
5705
5906
  }
5706
5907
  });
5707
- const htmlElements = await doc.render();
5708
- const contentNodes = [];
5709
- const seenInContentBlocks = /* @__PURE__ */ new Set();
5710
- const extractBlocks = (nodes) => {
5711
- for (const item of nodes) {
5712
- if (!item || !(item instanceof HTMLElement)) continue;
5713
- const tag = item.tagName.toLowerCase();
5714
- const hasChildBlocks = Array.from(item.children).some((c) => {
5715
- const ct = c.tagName.toLowerCase();
5716
- return ["p", "div", "table", "h1", "h2", "h3", "h4", "h5", "h6", "section", "article", "ul", "ol"].includes(ct);
5717
- });
5718
- if (hasChildBlocks && !["table", "tr", "td", "th", "ul", "ol", "li"].includes(tag)) {
5719
- extractBlocks(Array.from(item.children));
5720
- } else {
5721
- const fp = extractMediaFingerprint(item);
5722
- if (fp) {
5723
- if (seenInContentBlocks.has(fp)) {
5724
- continue;
5725
- }
5726
- seenInContentBlocks.add(fp);
5727
- }
5728
- const hasMedia = item.querySelector("img, svg, canvas, table") !== null || ["img", "svg", "table"].includes(tag);
5729
- const textContent = (item.textContent || "").trim();
5730
- if (!hasMedia && textContent.length === 0) {
5731
- continue;
5732
- }
5733
- const svgs = item.querySelectorAll("svg, img");
5734
- svgs.forEach((s) => {
5735
- const el = s;
5736
- el.style.maxWidth = "100%";
5737
- el.style.maxHeight = "360px";
5738
- el.style.display = "block";
5739
- el.style.margin = "12px auto";
5740
- if (s.tagName.toLowerCase() === "svg") {
5741
- s.removeAttribute("width");
5742
- s.removeAttribute("height");
5743
- el.style.width = "100%";
5744
- el.style.maxHeight = "360px";
5745
- }
5746
- });
5747
- if (tag === "p" || tag === "div") {
5748
- item.style.display = "block";
5749
- item.style.marginBottom = "12px";
5750
- item.style.lineHeight = "1.6";
5751
- }
5752
- contentNodes.push(item);
5908
+ const elements = await doc.render();
5909
+ let unsupportedIndex = 1;
5910
+ const usedTables = /* @__PURE__ */ new Set();
5911
+ for (let i = 0; i < elements.length; i++) {
5912
+ const el = elements[i];
5913
+ const text = el.textContent || "";
5914
+ if (text.includes("[Unsupported image format]")) {
5915
+ if (extractedImages[unsupportedIndex]) {
5916
+ const img = document.createElement("img");
5917
+ img.src = extractedImages[unsupportedIndex].dataUrl;
5918
+ img.style.width = "100%";
5919
+ img.style.height = "auto";
5920
+ img.style.maxHeight = "430px";
5921
+ img.style.objectFit = "contain";
5922
+ img.style.display = "block";
5923
+ img.style.margin = "12px auto";
5924
+ el.innerHTML = "";
5925
+ el.appendChild(img);
5926
+ unsupportedIndex++;
5753
5927
  }
5754
5928
  }
5755
- };
5756
- extractBlocks(htmlElements);
5757
- tables.forEach((table) => {
5758
- const tableEl = renderRtfTableElement(table);
5759
- let inserted = false;
5760
- if (table.anchorBefore && table.anchorBefore.length > 10) {
5761
- const keyword = table.anchorBefore.slice(-35).trim();
5762
- for (let i = 0; i < contentNodes.length; i++) {
5763
- if (contentNodes[i].textContent?.includes(keyword)) {
5764
- contentNodes.splice(i + 1, 0, tableEl);
5765
- inserted = true;
5766
- break;
5929
+ if (tables.length > 0) {
5930
+ for (let t = 0; t < tables.length; t++) {
5931
+ if (usedTables.has(t)) continue;
5932
+ const tbl = tables[t];
5933
+ if (tbl.rows.length >= 2) {
5934
+ const sampleCell1 = tbl.rows[1]?.[1] || tbl.rows[0]?.[1] || "";
5935
+ const sampleCell2 = tbl.rows[2]?.[1] || tbl.rows[1]?.[0] || "";
5936
+ const match1 = sampleCell1 && text.includes(sampleCell1.slice(0, 15).trim());
5937
+ const match2 = sampleCell2 && text.includes(sampleCell2.slice(0, 15).trim());
5938
+ if (match1 && match2) {
5939
+ el.innerHTML = "";
5940
+ el.appendChild(renderRtfTableElement(tbl));
5941
+ usedTables.add(t);
5942
+ break;
5943
+ }
5767
5944
  }
5768
5945
  }
5769
5946
  }
5770
- if (!inserted && table.anchorAfter && table.anchorAfter.length > 10) {
5771
- const keyword = table.anchorAfter.slice(0, 35).trim();
5772
- for (let i = 0; i < contentNodes.length; i++) {
5773
- if (contentNodes[i].textContent?.includes(keyword)) {
5774
- contentNodes.splice(i, 0, tableEl);
5775
- inserted = true;
5776
- break;
5777
- }
5778
- }
5947
+ }
5948
+ elements.forEach((el) => {
5949
+ const svgs = el.querySelectorAll ? Array.from(el.querySelectorAll("svg")) : [];
5950
+ svgs.forEach((svg) => {
5951
+ svg.removeAttribute("width");
5952
+ svg.removeAttribute("height");
5953
+ svg.style.maxWidth = "100%";
5954
+ svg.style.maxHeight = "430px";
5955
+ svg.style.height = "auto";
5956
+ svg.style.display = "block";
5957
+ svg.style.margin = "12px auto";
5958
+ });
5959
+ const imgs = el.querySelectorAll ? Array.from(el.querySelectorAll("img")) : [];
5960
+ imgs.forEach((img) => {
5961
+ img.style.maxWidth = "100%";
5962
+ img.style.maxHeight = "430px";
5963
+ img.style.height = "auto";
5964
+ img.style.objectFit = "contain";
5965
+ img.style.display = "block";
5966
+ img.style.margin = "12px auto";
5967
+ });
5968
+ });
5969
+ const allImgs = Array.from(document.querySelectorAll("img")).concat(
5970
+ elements.flatMap((el) => Array.from(el.querySelectorAll ? el.querySelectorAll("img") : []))
5971
+ );
5972
+ await Promise.all(allImgs.map((img) => {
5973
+ if (img.complete && img.naturalHeight > 0) return Promise.resolve();
5974
+ if (img.decode) return img.decode().catch(() => {
5975
+ });
5976
+ return new Promise((r) => {
5977
+ img.onload = r;
5978
+ img.onerror = r;
5979
+ });
5980
+ }));
5981
+ elements.forEach((el) => {
5982
+ const text = el.textContent || "";
5983
+ if (text.includes("\uF0B7")) {
5984
+ const cleanText = text.replace(/^[\s\uf0b7\t]+/, "");
5985
+ el.style.display = "flex";
5986
+ el.style.alignItems = "flex-start";
5987
+ el.style.margin = "6px 0 6px 28px";
5988
+ el.style.fontSize = "11pt";
5989
+ el.style.lineHeight = "1.5";
5990
+ el.innerHTML = `<span style="margin-right:10px; user-select:none;">&#9633;</span><span>${cleanText}</span>`;
5779
5991
  }
5780
- if (!inserted) {
5781
- if (contentNodes.length > 2) {
5782
- contentNodes.splice(2, 0, tableEl);
5783
- } else {
5784
- contentNodes.push(tableEl);
5785
- }
5992
+ });
5993
+ elements.forEach((el) => {
5994
+ const text = (el.textContent || "").trim();
5995
+ const hasMedia = el.querySelector("img, svg, canvas, table") !== null || ["IMG", "SVG", "TABLE"].includes(el.tagName);
5996
+ if (isHeadingElement(el)) {
5997
+ el.style.marginTop = "20px";
5998
+ el.style.marginBottom = "10px";
5999
+ el.style.lineHeight = "1.25";
6000
+ } else if (text.length > 0 && !hasMedia) {
6001
+ el.style.marginBottom = "12px";
6002
+ el.style.lineHeight = "1.45";
5786
6003
  }
5787
6004
  });
5788
- const createRtfCard = (pageNum) => {
6005
+ const measureCard = document.createElement("div");
6006
+ measureCard.style.width = `${pageWidth}px`;
6007
+ measureCard.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
6008
+ measureCard.style.boxSizing = "border-box";
6009
+ measureCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
6010
+ measureCard.style.lineHeight = "1.45";
6011
+ measureCard.style.visibility = "hidden";
6012
+ measureCard.style.position = "absolute";
6013
+ measureCard.style.top = "-99999px";
6014
+ document.body.appendChild(measureCard);
6015
+ const createPageCard = (num) => {
5789
6016
  const card = document.createElement("div");
5790
6017
  card.className = "fp-rtf-page-card";
5791
- card.setAttribute("data-page-number", String(pageNum));
6018
+ card.setAttribute("data-page-number", String(num));
5792
6019
  card.style.backgroundColor = "#ffffff";
5793
6020
  card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08), 0 1px 3px rgba(0,0,0,0.04)";
5794
6021
  card.style.borderRadius = "4px";
5795
- card.style.padding = "64px 56px";
5796
- card.style.width = "816px";
5797
- card.style.minHeight = "1056px";
5798
- card.style.maxHeight = "1056px";
5799
- card.style.overflow = "hidden";
6022
+ card.style.width = `${pageWidth}px`;
6023
+ card.style.height = `${pageHeight}px`;
6024
+ card.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
5800
6025
  card.style.boxSizing = "border-box";
6026
+ card.style.overflow = "hidden";
5801
6027
  card.style.marginBottom = "24px";
5802
- card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5803
- card.style.lineHeight = "1.6";
5804
6028
  card.style.color = "#1e293b";
6029
+ card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
6030
+ card.style.lineHeight = "1.45";
5805
6031
  card.style.position = "relative";
6032
+ card.style.textAlign = "left";
5806
6033
  return card;
5807
6034
  };
5808
- wrapper.innerHTML = "";
5809
- const measureCard = createRtfCard(0);
5810
- measureCard.style.maxHeight = "none";
5811
- measureCard.style.height = "auto";
5812
- wrapper.appendChild(measureCard);
5813
- contentNodes.forEach((node) => measureCard.appendChild(node));
5814
- const childHeights = contentNodes.map((c) => {
5815
- const rect = c.getBoundingClientRect ? c.getBoundingClientRect() : null;
5816
- const rectH = rect ? rect.height : 0;
5817
- const offH = c.offsetHeight || 0;
5818
- let realH = Math.max(rectH, offH);
5819
- try {
5820
- const cs = window.getComputedStyle(c);
5821
- realH += (parseFloat(cs.marginTop) || 0) + (parseFloat(cs.marginBottom) || 0);
5822
- } catch {
5823
- }
5824
- const hasMedia = c.querySelector("img, svg") !== null || ["img", "svg"].includes(c.tagName.toLowerCase());
5825
- const hasTable = c.querySelector("table") !== null || c.tagName.toLowerCase() === "table";
5826
- if (hasMedia) {
5827
- realH = Math.max(realH, 300);
5828
- } else if (hasTable) {
5829
- realH = Math.max(realH, 240);
5830
- }
5831
- if (realH > 0) return realH;
5832
- const textLen = c.textContent?.trim().length || 0;
5833
- return Math.max(28, Math.ceil(textLen / 75) * 26 + 16);
5834
- });
5835
- wrapper.innerHTML = "";
5836
- let curCard = createRtfCard(1);
5837
- wrapper.appendChild(curCard);
5838
- pageElements = [curCard];
5839
- let curH = 0;
5840
- const maxH = 860;
5841
- for (let i = 0; i < contentNodes.length; i++) {
5842
- const child = contentNodes[i];
5843
- const chH = childHeights[i];
5844
- const isChildEmpty = (child.textContent || "").trim().length === 0 && !child.querySelector("table, img, svg, canvas");
5845
- if (curH === 0 && isChildEmpty) {
6035
+ const pages = [];
6036
+ let curCard = createPageCard(1);
6037
+ pages.push(curCard);
6038
+ let curHeight = 0;
6039
+ for (let i = 0; i < elements.length; i++) {
6040
+ const el = elements[i];
6041
+ if (!el || !(el instanceof HTMLElement)) continue;
6042
+ const text = (el.textContent || "").trim();
6043
+ const hasMedia = el.querySelector("img, svg, canvas, table") !== null || ["IMG", "SVG", "TABLE"].includes(el.tagName);
6044
+ const isEmptyPar = !hasMedia && text.length === 0;
6045
+ if (isEmptyPar) {
6046
+ const emptyH = 35;
6047
+ if (curHeight + emptyH > printableHeight) {
6048
+ if (curCard.childNodes.length > 0) {
6049
+ curCard = createPageCard(pages.length + 1);
6050
+ pages.push(curCard);
6051
+ curHeight = 0;
6052
+ }
6053
+ }
6054
+ const spacer = document.createElement("div");
6055
+ spacer.style.height = `${emptyH}px`;
6056
+ curCard.appendChild(spacer);
6057
+ curHeight += emptyH;
5846
6058
  continue;
5847
6059
  }
5848
- const isTable = child.querySelector("table") !== null || child.tagName.toLowerCase() === "table";
5849
- const shouldBreakBeforeTable = isTable && curH > 400 && curCard.childNodes.length > 0;
5850
- if ((curH + chH > maxH || shouldBreakBeforeTable) && curCard.childNodes.length > 0) {
5851
- curCard = createRtfCard(pageElements.length + 1);
5852
- wrapper.appendChild(curCard);
5853
- pageElements.push(curCard);
5854
- curH = 0;
6060
+ measureCard.innerHTML = "";
6061
+ const clone = el.cloneNode(true);
6062
+ measureCard.appendChild(clone);
6063
+ const compStyle = window.getComputedStyle(clone);
6064
+ const mt = parseFloat(compStyle.marginTop) || 0;
6065
+ const mb = parseFloat(compStyle.marginBottom) || 0;
6066
+ const elH = clone.offsetHeight + mt + mb;
6067
+ const isHeading = isHeadingElement(el);
6068
+ let nextContentH = 0;
6069
+ if (isHeading || hasMedia) {
6070
+ for (let j = i + 1; j < elements.length; j++) {
6071
+ const nextEl = elements[j];
6072
+ if (nextEl && (nextEl.textContent || "").trim().length > 0) {
6073
+ measureCard.innerHTML = "";
6074
+ const nClone = nextEl.cloneNode(true);
6075
+ measureCard.appendChild(nClone);
6076
+ const nStyle = window.getComputedStyle(nClone);
6077
+ nextContentH = nClone.offsetHeight + (parseFloat(nStyle.marginTop) || 0) + (parseFloat(nStyle.marginBottom) || 0);
6078
+ break;
6079
+ }
6080
+ }
5855
6081
  }
5856
- curCard.appendChild(child);
5857
- curH += chH;
5858
- }
5859
- pageElements = pageElements.filter((card) => {
6082
+ const remainingSpace = printableHeight - curHeight;
6083
+ const isLargeMedia = hasMedia && elH > 300;
6084
+ const keepWithNextOverflow = isHeading && nextContentH > 0 && elH + nextContentH + 20 > remainingSpace;
6085
+ const largeMediaOverflow = isLargeMedia && curHeight > 0 && elH + 80 > remainingSpace;
6086
+ const shouldBreak = (curHeight + elH > printableHeight || keepWithNextOverflow || largeMediaOverflow) && curCard.childNodes.length > 0;
6087
+ if (shouldBreak) {
6088
+ curCard = createPageCard(pages.length + 1);
6089
+ pages.push(curCard);
6090
+ curHeight = 0;
6091
+ }
6092
+ curCard.appendChild(el);
6093
+ curHeight += elH;
6094
+ }
6095
+ measureCard.remove();
6096
+ pageElements = pages.filter((card) => {
5860
6097
  const hasText = (card.textContent || "").trim().length > 0;
5861
- const hasMedia = card.querySelector("table, img, svg, canvas") !== null;
5862
- return hasText || hasMedia;
6098
+ const hasCardMedia = card.querySelector("table, img, svg, canvas") !== null;
6099
+ return hasText || hasCardMedia;
5863
6100
  });
5864
6101
  if (pageElements.length === 0) {
5865
6102
  pageElements = [curCard];
5866
6103
  }
6104
+ wrapper.innerHTML = "";
6105
+ pageElements.forEach((card, idx) => {
6106
+ card.setAttribute("data-page-number", String(idx + 1));
6107
+ card.style.display = idx === 0 ? "block" : "none";
6108
+ wrapper.appendChild(card);
6109
+ });
5867
6110
  } catch (err) {
5868
6111
  console.warn("[RtfPlugin] RTF render error, fallback text:", err);
5869
- const text = new TextDecoder("latin1").decode(ctx.buffer);
5870
- const tables = parseRtfTables(text);
6112
+ const text = rawRtf;
5871
6113
  const rawPages = text.split(/\\page\b/).map((segment) => {
5872
6114
  return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
5873
- }).filter((p) => p.length > 0);
6115
+ }).filter((p2) => p2.length > 0);
5874
6116
  const pages = rawPages.length > 0 ? rawPages : [text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim()];
5875
6117
  for (let i = 0; i < pages.length; i++) {
5876
6118
  const pageCard = document.createElement("div");
@@ -5878,9 +6120,9 @@ var RtfPlugin = class {
5878
6120
  pageCard.style.backgroundColor = "#ffffff";
5879
6121
  pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
5880
6122
  pageCard.style.borderRadius = "4px";
5881
- pageCard.style.padding = "64px 56px";
5882
- pageCard.style.width = "816px";
5883
- pageCard.style.minHeight = "1056px";
6123
+ pageCard.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
6124
+ pageCard.style.width = `${pageWidth}px`;
6125
+ pageCard.style.minHeight = `${pageHeight}px`;
5884
6126
  pageCard.style.boxSizing = "border-box";
5885
6127
  pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5886
6128
  pageCard.style.fontSize = "12pt";
@@ -5900,11 +6142,9 @@ var RtfPlugin = class {
5900
6142
  let currentPage = 1;
5901
6143
  const showPage = (pageNum) => {
5902
6144
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
5903
- if (totalPages > 1) {
5904
- pageElements.forEach((el, idx) => {
5905
- el.style.display = idx + 1 === currentPage ? "block" : "none";
5906
- });
5907
- }
6145
+ pageElements.forEach((el, idx) => {
6146
+ el.style.display = idx + 1 === currentPage ? "block" : "none";
6147
+ });
5908
6148
  ctx.container.scrollTop = 0;
5909
6149
  ctx.emit("page-change", { page: currentPage, total: totalPages });
5910
6150
  };
@@ -5971,6 +6211,15 @@ var RtfPlugin = class {
5971
6211
  rotation = 0;
5972
6212
  applyTransform();
5973
6213
  },
6214
+ resetZoom: () => {
6215
+ isUserZoomed = false;
6216
+ fitMode = "width";
6217
+ scale = calculateFitScale("width");
6218
+ rotation = 0;
6219
+ ctx.container.scrollTop = 0;
6220
+ ctx.container.scrollLeft = 0;
6221
+ applyTransform();
6222
+ },
5974
6223
  rotateCW: () => {
5975
6224
  rotation = (rotation + 90) % 360;
5976
6225
  applyTransform();
@@ -6038,6 +6287,14 @@ var HtmlPreviewPlugin = class {
6038
6287
  group: "zoom",
6039
6288
  execute: () => instance.fitToPage?.()
6040
6289
  },
6290
+ {
6291
+ id: "reset-zoom",
6292
+ icon: "reset-zoom",
6293
+ label: "Reset Zoom",
6294
+ type: "button",
6295
+ group: "zoom",
6296
+ execute: () => instance.resetZoom?.()
6297
+ },
6041
6298
  {
6042
6299
  id: "copy",
6043
6300
  icon: "copy",
@@ -6110,6 +6367,12 @@ var HtmlPreviewPlugin = class {
6110
6367
  scale = 1;
6111
6368
  iframe.style.transform = "scale(1)";
6112
6369
  },
6370
+ resetZoom: () => {
6371
+ scale = 1;
6372
+ iframe.style.transform = "scale(1)";
6373
+ ctx.container.scrollTop = 0;
6374
+ ctx.container.scrollLeft = 0;
6375
+ },
6113
6376
  copy: () => {
6114
6377
  navigator.clipboard.writeText(rawHtml);
6115
6378
  },
@@ -6210,6 +6473,14 @@ var OpenDocumentPlugin = class {
6210
6473
  group: "zoom",
6211
6474
  execute: () => instance.fitToPage?.()
6212
6475
  },
6476
+ {
6477
+ id: "reset-zoom",
6478
+ icon: "reset-zoom",
6479
+ label: "Reset Zoom",
6480
+ type: "button",
6481
+ group: "zoom",
6482
+ execute: () => instance.resetZoom?.()
6483
+ },
6213
6484
  {
6214
6485
  id: "rotate-cw",
6215
6486
  icon: "rotate-cw",
@@ -6477,6 +6748,15 @@ var OpenDocumentPlugin = class {
6477
6748
  rotation = 0;
6478
6749
  applyTransform();
6479
6750
  },
6751
+ resetZoom: () => {
6752
+ isUserZoomed = false;
6753
+ fitMode = "width";
6754
+ scale = calculateFitScale("width");
6755
+ rotation = 0;
6756
+ container.scrollTop = 0;
6757
+ container.scrollLeft = 0;
6758
+ applyTransform();
6759
+ },
6480
6760
  rotateCW: () => {
6481
6761
  rotation = (rotation + 90) % 360;
6482
6762
  applyTransform();
@@ -6820,6 +7100,14 @@ var DocPlugin = class {
6820
7100
  group: "zoom",
6821
7101
  execute: () => instance.fitToPage?.()
6822
7102
  },
7103
+ {
7104
+ id: "reset-zoom",
7105
+ icon: "reset-zoom",
7106
+ label: "Reset Zoom",
7107
+ type: "button",
7108
+ group: "zoom",
7109
+ execute: () => instance.resetZoom?.()
7110
+ },
6823
7111
  {
6824
7112
  id: "rotate-cw",
6825
7113
  icon: "rotate-cw",
@@ -7026,6 +7314,15 @@ var DocPlugin = class {
7026
7314
  rotation = 0;
7027
7315
  applyTransform();
7028
7316
  },
7317
+ resetZoom: () => {
7318
+ isUserZoomed = false;
7319
+ fitMode = "width";
7320
+ scale = calculateFitScale("width");
7321
+ rotation = 0;
7322
+ ctx.container.scrollTop = 0;
7323
+ ctx.container.scrollLeft = 0;
7324
+ applyTransform();
7325
+ },
7029
7326
  rotateCW: () => {
7030
7327
  rotation = (rotation + 90) % 360;
7031
7328
  applyTransform();
@@ -7506,6 +7803,14 @@ var PptPlugin = class {
7506
7803
  group: "zoom",
7507
7804
  execute: () => instance.fitToPage?.()
7508
7805
  },
7806
+ {
7807
+ id: "reset-zoom",
7808
+ icon: "reset-zoom",
7809
+ label: "Reset Zoom",
7810
+ type: "button",
7811
+ group: "zoom",
7812
+ execute: () => instance.resetZoom?.()
7813
+ },
7509
7814
  {
7510
7815
  id: "rotate-cw",
7511
7816
  icon: "rotate-cw",
@@ -7694,6 +7999,13 @@ var PptPlugin = class {
7694
7999
  rotation = 0;
7695
8000
  applyTransform();
7696
8001
  },
8002
+ resetZoom: () => {
8003
+ scale = calculateFitScale();
8004
+ rotation = 0;
8005
+ container.scrollTop = 0;
8006
+ container.scrollLeft = 0;
8007
+ applyTransform();
8008
+ },
7697
8009
  rotateCW: () => {
7698
8010
  rotation = (rotation + 90) % 360;
7699
8011
  applyTransform();