@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.js CHANGED
@@ -579,6 +579,7 @@ var ICON_COPY = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" str
579
579
  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>`;
580
580
  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>`;
581
581
  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>`;
582
+ 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>`;
582
583
  var ICON_MAP = {
583
584
  "zoom-in": ICON_ZOOM_IN,
584
585
  "zoom-out": ICON_ZOOM_OUT,
@@ -608,7 +609,10 @@ var ICON_MAP = {
608
609
  "open-window": ICON_EXTERNAL_WINDOW,
609
610
  "external-window": ICON_EXTERNAL_WINDOW,
610
611
  "openWindow": ICON_EXTERNAL_WINDOW,
611
- "openSeparateWindow": ICON_EXTERNAL_WINDOW
612
+ "openSeparateWindow": ICON_EXTERNAL_WINDOW,
613
+ "reset-zoom": ICON_RESET_ZOOM,
614
+ "zoom-reset": ICON_RESET_ZOOM,
615
+ "resetZoom": ICON_RESET_ZOOM
612
616
  };
613
617
  var ToolbarController = class {
614
618
  el;
@@ -641,6 +645,10 @@ var ToolbarController = class {
641
645
  this.config.fitToPage = false;
642
646
  this.config.fitWidth = false;
643
647
  }
648
+ if (actionId === "reset-zoom" || actionId === "zoom-reset" || actionId === "resetZoom") {
649
+ this.config.resetZoom = false;
650
+ this.config.zoomReset = false;
651
+ }
644
652
  if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = false;
645
653
  if (actionId === "fullscreen") this.config.fullscreen = false;
646
654
  if (actionId === "download") this.config.download = false;
@@ -665,6 +673,10 @@ var ToolbarController = class {
665
673
  this.config.fitToPage = true;
666
674
  this.config.fitWidth = true;
667
675
  }
676
+ if (actionId === "reset-zoom" || actionId === "zoom-reset" || actionId === "resetZoom") {
677
+ this.config.resetZoom = true;
678
+ this.config.zoomReset = true;
679
+ }
668
680
  if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = true;
669
681
  if (actionId === "fullscreen") this.config.fullscreen = true;
670
682
  if (actionId === "download") this.config.download = true;
@@ -684,6 +696,7 @@ var ToolbarController = class {
684
696
  if (actionId === "zoomIn") return "zoom-in";
685
697
  if (actionId === "zoomOut") return "zoom-out";
686
698
  if (actionId === "fitPage" || actionId === "fitToPage" || actionId === "fitWidth") return "fit-page";
699
+ if (actionId === "resetZoom" || actionId === "zoomReset") return "reset-zoom";
687
700
  if (actionId === "rotateCW") return "rotate-cw";
688
701
  if (actionId === "rotateCCW") return "rotate-ccw";
689
702
  if (actionId === "openWindow" || actionId === "openSeparateWindow") return "open-window";
@@ -726,6 +739,9 @@ var ToolbarController = class {
726
739
  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)) {
727
740
  return false;
728
741
  }
742
+ if ((id === "reset-zoom" || id === "zoom-reset") && (c.resetZoom === false || c.zoomReset === false || c["reset-zoom"] === false || c["zoom-reset"] === false)) {
743
+ return false;
744
+ }
729
745
  if ((id === "rotate-cw" || id === "rotate-ccw" || id === "rotate") && (c.rotate === false || c.rotateCW === false || c.rotateCCW === false || c["rotate-cw"] === false)) {
730
746
  return false;
731
747
  }
@@ -1172,6 +1188,9 @@ var FilePreviewViewer = class _FilePreviewViewer {
1172
1188
  this.activeInstance = instance;
1173
1189
  instance.openInSeparateWindow = () => this.openInSeparateWindow();
1174
1190
  instance.toggleThumbnails = () => this.toggleThumbnails();
1191
+ if (!instance.resetZoom && instance.fitToPage) {
1192
+ instance.resetZoom = () => instance.fitToPage?.();
1193
+ }
1175
1194
  this.hideLoading();
1176
1195
  this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
1177
1196
  const isToolbarVisible = options.showToolbar !== false && options.toolbar !== false;
@@ -1455,6 +1474,16 @@ var FilePreviewViewer = class _FilePreviewViewer {
1455
1474
  fitToPage() {
1456
1475
  this.activeInstance?.fitToPage?.();
1457
1476
  }
1477
+ /**
1478
+ * Reset zoom level to initial/default fit state.
1479
+ */
1480
+ resetZoom() {
1481
+ if (this.activeInstance?.resetZoom) {
1482
+ this.activeInstance.resetZoom();
1483
+ } else if (this.activeInstance?.fitToPage) {
1484
+ this.activeInstance.fitToPage();
1485
+ }
1486
+ }
1458
1487
  /**
1459
1488
  * Zoom in.
1460
1489
  */
@@ -2076,6 +2105,14 @@ var PdfPlugin = class {
2076
2105
  group: "zoom",
2077
2106
  execute: () => instance.fitToPage?.()
2078
2107
  },
2108
+ {
2109
+ id: "reset-zoom",
2110
+ icon: "reset-zoom",
2111
+ label: "Reset Zoom",
2112
+ type: "button",
2113
+ group: "zoom",
2114
+ execute: () => instance.resetZoom?.()
2115
+ },
2079
2116
  {
2080
2117
  id: "fit-width",
2081
2118
  icon: "fit-width",
@@ -2338,6 +2375,14 @@ var PdfPlugin = class {
2338
2375
  zoomScale = 1;
2339
2376
  renderPage(currentPage);
2340
2377
  },
2378
+ resetZoom: () => {
2379
+ fitMode = "page";
2380
+ zoomScale = 1;
2381
+ rotation = 0;
2382
+ container.scrollTop = 0;
2383
+ container.scrollLeft = 0;
2384
+ renderPage(currentPage);
2385
+ },
2341
2386
  fitToWidth: () => {
2342
2387
  fitMode = "width";
2343
2388
  zoomScale = 1;
@@ -2505,6 +2550,16 @@ var MediaPlugin = class {
2505
2550
  instance.fitToPage?.();
2506
2551
  }
2507
2552
  },
2553
+ {
2554
+ id: "reset-zoom",
2555
+ icon: "reset-zoom",
2556
+ label: "Reset Zoom",
2557
+ type: "button",
2558
+ group: "zoom",
2559
+ execute: () => {
2560
+ instance.resetZoom?.();
2561
+ }
2562
+ },
2508
2563
  {
2509
2564
  id: "rotate-cw",
2510
2565
  icon: "rotate-cw",
@@ -2678,6 +2733,13 @@ var MediaPlugin = class {
2678
2733
  rotation = 0;
2679
2734
  applyTransform();
2680
2735
  } : void 0,
2736
+ resetZoom: isImage ? () => {
2737
+ currentZoom = 1;
2738
+ rotation = 0;
2739
+ ctx.container.scrollTop = 0;
2740
+ ctx.container.scrollLeft = 0;
2741
+ applyTransform();
2742
+ } : void 0,
2681
2743
  rotateCW: isImage || isVideo ? () => {
2682
2744
  rotation = (rotation + 90) % 360;
2683
2745
  applyTransform();
@@ -2794,6 +2856,14 @@ var DocxPlugin = class {
2794
2856
  group: "zoom",
2795
2857
  execute: () => instance.fitToPage?.()
2796
2858
  },
2859
+ {
2860
+ id: "reset-zoom",
2861
+ icon: "reset-zoom",
2862
+ label: "Reset Zoom",
2863
+ type: "button",
2864
+ group: "zoom",
2865
+ execute: () => instance.resetZoom?.()
2866
+ },
2797
2867
  {
2798
2868
  id: "rotate-cw",
2799
2869
  icon: "rotate-cw",
@@ -3110,6 +3180,14 @@ var DocxPlugin = class {
3110
3180
  rotation = 0;
3111
3181
  applyTransform();
3112
3182
  },
3183
+ resetZoom: () => {
3184
+ isUserZoomed = false;
3185
+ scale = calculateFitScale("page");
3186
+ rotation = 0;
3187
+ ctx.container.scrollTop = 0;
3188
+ ctx.container.scrollLeft = 0;
3189
+ applyTransform();
3190
+ },
3113
3191
  rotateCW: () => {
3114
3192
  rotation = (rotation + 90) % 360;
3115
3193
  applyTransform();
@@ -3559,6 +3637,16 @@ var ExcelPlugin = class {
3559
3637
  instance.zoomIn?.();
3560
3638
  }
3561
3639
  },
3640
+ {
3641
+ id: "reset-zoom",
3642
+ icon: "reset-zoom",
3643
+ label: "Reset Zoom",
3644
+ type: "button",
3645
+ group: "zoom",
3646
+ execute: () => {
3647
+ instance.resetZoom?.();
3648
+ }
3649
+ },
3562
3650
  {
3563
3651
  id: "download",
3564
3652
  icon: "download",
@@ -3746,6 +3834,12 @@ var ExcelPlugin = class {
3746
3834
  scale = calculateFitScale();
3747
3835
  applyTransform();
3748
3836
  },
3837
+ resetZoom: () => {
3838
+ scale = calculateFitScale();
3839
+ contentArea.scrollTop = 0;
3840
+ contentArea.scrollLeft = 0;
3841
+ applyTransform();
3842
+ },
3749
3843
  rotateCW: () => {
3750
3844
  },
3751
3845
  rotateCCW: () => {
@@ -3876,6 +3970,16 @@ var CsvPlugin = class {
3876
3970
  instance.zoomIn?.();
3877
3971
  }
3878
3972
  },
3973
+ {
3974
+ id: "reset-zoom",
3975
+ icon: "reset-zoom",
3976
+ label: "Reset Zoom",
3977
+ type: "button",
3978
+ group: "zoom",
3979
+ execute: () => {
3980
+ instance.resetZoom?.();
3981
+ }
3982
+ },
3879
3983
  {
3880
3984
  id: "download",
3881
3985
  icon: "download",
@@ -4065,6 +4169,12 @@ var CsvPlugin = class {
4065
4169
  scale = calculateFitScale();
4066
4170
  applyScale();
4067
4171
  },
4172
+ resetZoom: () => {
4173
+ scale = calculateFitScale();
4174
+ container.scrollTop = 0;
4175
+ container.scrollLeft = 0;
4176
+ applyScale();
4177
+ },
4068
4178
  rotateCW: () => {
4069
4179
  },
4070
4180
  rotateCCW: () => {
@@ -4180,6 +4290,16 @@ var CodePlugin = class {
4180
4290
  instance.zoomIn?.();
4181
4291
  }
4182
4292
  },
4293
+ {
4294
+ id: "reset-zoom",
4295
+ icon: "reset-zoom",
4296
+ label: "Reset Zoom",
4297
+ type: "button",
4298
+ group: "zoom",
4299
+ execute: () => {
4300
+ instance.resetZoom?.();
4301
+ }
4302
+ },
4183
4303
  {
4184
4304
  id: "copy",
4185
4305
  icon: "copy",
@@ -4459,6 +4579,15 @@ var CodePlugin = class {
4459
4579
  zoomLevel = isTxt ? calculateTxtFit() : 1;
4460
4580
  updateTransform();
4461
4581
  },
4582
+ resetZoom: () => {
4583
+ isUserZoomed = false;
4584
+ fontSize = 13;
4585
+ rotation = 0;
4586
+ zoomLevel = isTxt ? calculateTxtFit() : 1;
4587
+ container.scrollTop = 0;
4588
+ container.scrollLeft = 0;
4589
+ updateTransform();
4590
+ },
4462
4591
  rotateCW: () => {
4463
4592
  rotation = (rotation + 90) % 360;
4464
4593
  updateTransform();
@@ -4521,11 +4650,19 @@ var ArchivePlugin = class {
4521
4650
  {
4522
4651
  id: "fit-page",
4523
4652
  icon: "fit-page",
4524
- label: "Reset Zoom",
4653
+ label: "Fit to Page",
4525
4654
  type: "button",
4526
4655
  group: "zoom",
4527
4656
  execute: () => instance.fitToPage?.()
4528
4657
  },
4658
+ {
4659
+ id: "reset-zoom",
4660
+ icon: "reset-zoom",
4661
+ label: "Reset Zoom",
4662
+ type: "button",
4663
+ group: "zoom",
4664
+ execute: () => instance.resetZoom?.()
4665
+ },
4529
4666
  {
4530
4667
  id: "download",
4531
4668
  icon: "download",
@@ -4680,7 +4817,13 @@ var ArchivePlugin = class {
4680
4817
  },
4681
4818
  fitToPage: () => {
4682
4819
  scale = 1;
4683
- wrapper.style.transform = `scale(1)`;
4820
+ wrapper.style.transform = "scale(1)";
4821
+ },
4822
+ resetZoom: () => {
4823
+ scale = 1;
4824
+ wrapper.style.transform = "scale(1)";
4825
+ ctx.container.scrollTop = 0;
4826
+ ctx.container.scrollLeft = 0;
4684
4827
  },
4685
4828
  download: () => {
4686
4829
  downloadFile(ctx.buffer, ctx.metadata.name || "archive.zip", "application/zip");
@@ -4732,6 +4875,14 @@ var MarkdownPlugin = class {
4732
4875
  group: "zoom",
4733
4876
  execute: () => instance.fitToPage?.()
4734
4877
  },
4878
+ {
4879
+ id: "reset-zoom",
4880
+ icon: "reset-zoom",
4881
+ label: "Reset Zoom",
4882
+ type: "button",
4883
+ group: "zoom",
4884
+ execute: () => instance.resetZoom?.()
4885
+ },
4735
4886
  {
4736
4887
  id: "copy",
4737
4888
  icon: "copy",
@@ -4885,6 +5036,12 @@ var MarkdownPlugin = class {
4885
5036
  fontSize = 15;
4886
5037
  wrapper.style.fontSize = "15px";
4887
5038
  },
5039
+ resetZoom: () => {
5040
+ fontSize = 15;
5041
+ wrapper.style.fontSize = "15px";
5042
+ ctx.container.scrollTop = 0;
5043
+ ctx.container.scrollLeft = 0;
5044
+ },
4888
5045
  download: () => {
4889
5046
  downloadFile(ctx.buffer, ctx.metadata.name || "document.md", "text/markdown");
4890
5047
  },
@@ -4978,6 +5135,14 @@ var PptxPlugin = class {
4978
5135
  group: "zoom",
4979
5136
  execute: () => instance.fitToPage?.()
4980
5137
  },
5138
+ {
5139
+ id: "reset-zoom",
5140
+ icon: "reset-zoom",
5141
+ label: "Reset Zoom",
5142
+ type: "button",
5143
+ group: "zoom",
5144
+ execute: () => instance.resetZoom?.()
5145
+ },
4981
5146
  {
4982
5147
  id: "rotate-cw",
4983
5148
  icon: "rotate-cw",
@@ -5097,6 +5262,13 @@ var PptxPlugin = class {
5097
5262
  rotation = 0;
5098
5263
  applyTransform();
5099
5264
  },
5265
+ resetZoom: () => {
5266
+ scale = calculateFitScale();
5267
+ rotation = 0;
5268
+ wrapper.scrollTop = 0;
5269
+ wrapper.scrollLeft = 0;
5270
+ applyTransform();
5271
+ },
5100
5272
  rotateCW: () => {
5101
5273
  rotation = (rotation + 90) % 360;
5102
5274
  applyTransform();
@@ -5172,6 +5344,14 @@ var ThreeDPlugin = class {
5172
5344
  group: "zoom",
5173
5345
  execute: () => instance.fitToPage?.()
5174
5346
  },
5347
+ {
5348
+ id: "reset-zoom",
5349
+ icon: "reset-zoom",
5350
+ label: "Reset Zoom",
5351
+ type: "button",
5352
+ group: "zoom",
5353
+ execute: () => instance.resetZoom?.()
5354
+ },
5175
5355
  {
5176
5356
  id: "rotate-cw",
5177
5357
  icon: "rotate-cw",
@@ -5308,6 +5488,7 @@ var ThreeDPlugin = class {
5308
5488
  controls.update();
5309
5489
  },
5310
5490
  fitToPage: fitCamera,
5491
+ resetZoom: fitCamera,
5311
5492
  rotateCW: () => {
5312
5493
  isWireframe = !isWireframe;
5313
5494
  materials.forEach((m) => {
@@ -5330,7 +5511,7 @@ function cleanRtfText(raw) {
5330
5511
  return String.fromCharCode(num);
5331
5512
  }).replace(/\\'([0-9a-fA-F]{2})/g, (_, hex) => {
5332
5513
  return String.fromCharCode(parseInt(hex, 16));
5333
- }).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();
5514
+ }).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();
5334
5515
  }
5335
5516
  function parseRtfTables(rtfText) {
5336
5517
  const rowSegments = rtfText.split(/\\row\b/);
@@ -5370,17 +5551,12 @@ function parseRtfTables(rtfText) {
5370
5551
  }
5371
5552
  const isNewTable = !currentTable || segmentStart - currentTable.lastEnd > 2500;
5372
5553
  if (isNewTable) {
5373
- const prevTextSlice = rtfText.slice(Math.max(0, segmentStart - 4e3), segmentStart);
5374
- const cleanPrev = cleanRtfText(prevTextSlice);
5375
- const anchorBefore = cleanPrev.slice(-80).trim();
5376
5554
  currentTable = {
5377
5555
  id: `RTF_TABLE_${rawTables.length}`,
5378
5556
  startPos: segmentStart,
5379
5557
  lastEnd: segmentEnd,
5380
5558
  rows: [],
5381
- columnWidths: cellWidths,
5382
- anchorBefore,
5383
- anchorAfter: ""
5559
+ columnWidths: cellWidths
5384
5560
  };
5385
5561
  rawTables.push(currentTable);
5386
5562
  }
@@ -5394,20 +5570,13 @@ function parseRtfTables(rtfText) {
5394
5570
  }
5395
5571
  charOffset += segment.length + 4;
5396
5572
  }
5397
- rawTables.forEach((tbl) => {
5398
- const afterSlice = rtfText.slice(tbl.lastEnd, Math.min(rtfText.length, tbl.lastEnd + 2e3));
5399
- const cleanAfter = cleanRtfText(afterSlice);
5400
- tbl.anchorAfter = cleanAfter.slice(0, 80).trim();
5401
- });
5402
5573
  return rawTables.map((tbl) => {
5403
5574
  const totalW = (tbl.columnWidths || []).reduce((a, b) => a + b, 0);
5404
5575
  const colPercents = totalW > 0 ? tbl.columnWidths.map((w) => Math.round(w / totalW * 100)) : [];
5405
5576
  return {
5406
5577
  id: tbl.id,
5407
5578
  rows: tbl.rows.map((r) => r.cells),
5408
- colPercents,
5409
- anchorBefore: tbl.anchorBefore,
5410
- anchorAfter: tbl.anchorAfter
5579
+ colPercents
5411
5580
  };
5412
5581
  });
5413
5582
  }
@@ -5420,8 +5589,6 @@ function renderRtfTableElement(table) {
5420
5589
  tableEl.style.fontSize = "10pt";
5421
5590
  tableEl.style.lineHeight = "1.5";
5422
5591
  tableEl.style.border = "1px solid #cbd5e1";
5423
- tableEl.style.borderRadius = "4px";
5424
- tableEl.style.boxSizing = "border-box";
5425
5592
  tableEl.style.backgroundColor = "#ffffff";
5426
5593
  const thead = document.createElement("thead");
5427
5594
  const tbody = document.createElement("tbody");
@@ -5430,27 +5597,17 @@ function renderRtfTableElement(table) {
5430
5597
  const isHeader = rIdx === 0;
5431
5598
  if (isHeader) {
5432
5599
  tr.style.backgroundColor = "#f8fafc";
5433
- tr.style.borderBottom = "2px solid #cbd5e1";
5434
- } else {
5435
- tr.style.borderBottom = "1px solid #e2e8f0";
5436
- if (rIdx % 2 === 0) {
5437
- tr.style.backgroundColor = "#fcfdfe";
5438
- }
5439
5600
  }
5440
5601
  rowCells.forEach((cellText, cIdx) => {
5441
5602
  const cellEl = document.createElement(isHeader ? "th" : "td");
5442
5603
  cellEl.style.padding = "8px 12px";
5443
5604
  cellEl.style.border = "1px solid #cbd5e1";
5444
5605
  cellEl.style.verticalAlign = "top";
5445
- cellEl.style.color = isHeader ? "#0f172a" : "#1e293b";
5446
- cellEl.style.fontWeight = isHeader ? "600" : "normal";
5447
5606
  if (table.colPercents && table.colPercents[cIdx]) {
5448
5607
  cellEl.style.width = `${table.colPercents[cIdx]}%`;
5449
5608
  }
5450
5609
  if (/^\d+$/.test(cellText.trim()) || cellText.trim() === "#") {
5451
5610
  cellEl.style.textAlign = "center";
5452
- } else {
5453
- cellEl.style.textAlign = "left";
5454
5611
  }
5455
5612
  cellEl.textContent = cellText;
5456
5613
  tr.appendChild(cellEl);
@@ -5465,23 +5622,19 @@ function renderRtfTableElement(table) {
5465
5622
  tableEl.appendChild(tbody);
5466
5623
  return tableEl;
5467
5624
  }
5468
- function extractMediaFingerprint(el) {
5469
- const img = el.tagName.toLowerCase() === "img" ? el : el.querySelector("img");
5470
- if (img && img.src) {
5471
- const s = img.src;
5472
- return s.length > 300 ? `img_${s.slice(0, 80)}_${s.length}_${s.slice(-80)}` : `img_${s}`;
5473
- }
5474
- const innerImg = el.querySelector("image");
5475
- if (innerImg) {
5476
- const h = innerImg.getAttribute("xlink:href") || innerImg.getAttribute("href") || "";
5477
- if (h) return h.length > 300 ? `svgimg_${h.slice(0, 80)}_${h.length}_${h.slice(-80)}` : `svgimg_${h}`;
5478
- }
5479
- const svg = el.tagName.toLowerCase() === "svg" ? el : el.querySelector("svg");
5480
- if (svg) {
5481
- const vb = svg.getAttribute("viewBox") || "";
5482
- return `svg_${vb}_${svg.innerHTML.length}`;
5483
- }
5484
- return null;
5625
+ function isHeadingElement(el) {
5626
+ if (["H1", "H2", "H3", "H4"].includes(el.tagName)) return true;
5627
+ const spans = el.querySelectorAll ? Array.from(el.querySelectorAll("span, b, strong, div")) : [];
5628
+ for (const s of spans) {
5629
+ const hEl = s;
5630
+ const fs = parseFloat(hEl.style.fontSize) || 0;
5631
+ const isBold = hEl.style.fontWeight === "bold" || parseInt(hEl.style.fontWeight, 10) >= 600 || ["B", "STRONG"].includes(hEl.tagName);
5632
+ if (isBold && fs >= 14) return true;
5633
+ }
5634
+ const elFs = parseFloat(el.style.fontSize) || 0;
5635
+ const elBold = el.style.fontWeight === "bold" || parseInt(el.style.fontWeight, 10) >= 600;
5636
+ if (elBold && elFs >= 14) return true;
5637
+ return false;
5485
5638
  }
5486
5639
  var RtfPlugin = class {
5487
5640
  id = "rtf";
@@ -5550,6 +5703,14 @@ var RtfPlugin = class {
5550
5703
  group: "zoom",
5551
5704
  execute: () => instance.fitToPage?.()
5552
5705
  },
5706
+ {
5707
+ id: "reset-zoom",
5708
+ icon: "reset-zoom",
5709
+ label: "Reset Zoom",
5710
+ type: "button",
5711
+ group: "zoom",
5712
+ execute: () => instance.resetZoom?.()
5713
+ },
5553
5714
  {
5554
5715
  id: "rotate-cw",
5555
5716
  icon: "rotate-cw",
@@ -5594,10 +5755,66 @@ var RtfPlugin = class {
5594
5755
  return actions;
5595
5756
  }
5596
5757
  async render(ctx) {
5758
+ const rawRtf = new TextDecoder("latin1").decode(ctx.buffer);
5759
+ const paperwMatch = rawRtf.match(/\\paperw(\d+)/);
5760
+ const paperhMatch = rawRtf.match(/\\paperh(\d+)/);
5761
+ const marglMatch = rawRtf.match(/\\margl(\d+)/);
5762
+ const margrMatch = rawRtf.match(/\\margr(\d+)/);
5763
+ const margtMatch = rawRtf.match(/\\margt(\d+)/);
5764
+ const margbMatch = rawRtf.match(/\\margb(\d+)/);
5765
+ const paperwTwips = paperwMatch ? parseInt(paperwMatch[1], 10) : 11906;
5766
+ const paperhTwips = paperhMatch ? parseInt(paperhMatch[1], 10) : 16838;
5767
+ const marglTwips = marglMatch ? parseInt(marglMatch[1], 10) : 1134;
5768
+ const margrTwips = margrMatch ? parseInt(margrMatch[1], 10) : 1134;
5769
+ const margtTwips = margtMatch ? parseInt(margtMatch[1], 10) : 1134;
5770
+ const margbTwips = margbMatch ? parseInt(margbMatch[1], 10) : 1134;
5771
+ const pageWidth = Math.round(paperwTwips / 15);
5772
+ const pageHeight = Math.round(paperhTwips / 15);
5773
+ const padLeft = Math.round(marglTwips / 15);
5774
+ const padRight = Math.round(margrTwips / 15);
5775
+ const padTop = Math.round(margtTwips / 15);
5776
+ const padBottom = Math.round(margbTwips / 15);
5777
+ const printableHeight = pageHeight - padTop - padBottom;
5778
+ const extractedImages = [];
5779
+ let p = 0;
5780
+ while ((p = rawRtf.indexOf("\\pict", p)) !== -1) {
5781
+ const startP = p;
5782
+ p += 5;
5783
+ const header = rawRtf.substring(startP, startP + 600);
5784
+ let mime = "";
5785
+ let magic = "";
5786
+ if (header.includes("\\pngblip")) {
5787
+ mime = "image/png";
5788
+ magic = "89504e47";
5789
+ } else if (header.includes("\\jpegblip")) {
5790
+ mime = "image/jpeg";
5791
+ magic = "ffd8ff";
5792
+ }
5793
+ if (!mime || !magic) continue;
5794
+ const magicPos = rawRtf.indexOf(magic, startP);
5795
+ if (magicPos === -1 || magicPos - startP > 3e3) continue;
5796
+ let endP = magicPos;
5797
+ while (endP < rawRtf.length && /[0-9a-fA-F\r\n\s]/.test(rawRtf[endP])) {
5798
+ endP++;
5799
+ }
5800
+ const cleanHex = rawRtf.substring(magicPos, endP).replace(/[\r\n\s]/g, "");
5801
+ if (cleanHex.length < 100) continue;
5802
+ const hexLen = cleanHex.length / 2;
5803
+ const u8 = new Uint8Array(hexLen);
5804
+ for (let k = 0; k < hexLen; k++) {
5805
+ u8[k] = parseInt(cleanHex.substr(k * 2, 2), 16);
5806
+ }
5807
+ let bStr = "";
5808
+ for (let k = 0; k < u8.length; k += 8192) {
5809
+ bStr += String.fromCharCode.apply(null, Array.from(u8.subarray(k, k + 8192)));
5810
+ }
5811
+ extractedImages.push({ mime, dataUrl: `data:${mime};base64,${btoa(bStr)}`, offset: startP });
5812
+ }
5813
+ const tables = parseRtfTables(rawRtf);
5597
5814
  const wrapper = document.createElement("div");
5598
5815
  wrapper.className = "fp-rtf-wrapper";
5599
5816
  wrapper.style.padding = "0";
5600
- wrapper.style.width = "816px";
5817
+ wrapper.style.width = `${pageWidth}px`;
5601
5818
  wrapper.style.margin = "0 auto";
5602
5819
  wrapper.style.boxSizing = "border-box";
5603
5820
  wrapper.style.display = "flex";
@@ -5617,9 +5834,8 @@ var RtfPlugin = class {
5617
5834
  let isUserZoomed = false;
5618
5835
  let fitMode = ctx?.options?.fitMode || "width";
5619
5836
  const calculateFitScale = (mode = fitMode) => {
5620
- const activeEl = pageElements[currentPage - 1] || wrapper;
5621
- const elW = 816;
5622
- const singlePageH = activeEl?.offsetHeight || 1056;
5837
+ const elW = pageWidth;
5838
+ const singlePageH = pageHeight;
5623
5839
  const availW = Math.max(280, ctx.container.clientWidth - 32);
5624
5840
  const availH = Math.max(280, ctx.container.clientHeight - 32);
5625
5841
  const sW = availW / elW;
@@ -5632,8 +5848,7 @@ var RtfPlugin = class {
5632
5848
  const applyTransform = () => {
5633
5849
  wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5634
5850
  wrapper.style.transformOrigin = "top center";
5635
- const activeEl = pageElements[currentPage - 1];
5636
- const baseH = activeEl?.offsetHeight || 1056;
5851
+ const baseH = pageHeight;
5637
5852
  const scaledH = baseH * scale;
5638
5853
  const extraH = Math.max(0, scaledH - baseH);
5639
5854
  wrapper.style.marginBottom = `${extraH + 32}px`;
@@ -5653,193 +5868,220 @@ var RtfPlugin = class {
5653
5868
  if (typeof RTFJS.loggingEnabled === "function") {
5654
5869
  RTFJS.loggingEnabled(false);
5655
5870
  }
5656
- const rawText = new TextDecoder("latin1").decode(ctx.buffer);
5657
- const tables = parseRtfTables(rawText);
5658
- const seenMediaSignatures = /* @__PURE__ */ new Set();
5659
5871
  const doc = new RTFJS.Document(ctx.buffer, {
5660
5872
  onPicture: (isLegacy, createPic) => {
5661
- if (isLegacy === true) {
5662
- return null;
5663
- }
5664
- const pic = createPic();
5665
- if (!pic) return null;
5666
- const fp = extractMediaFingerprint(pic);
5667
- if (fp) {
5668
- if (seenMediaSignatures.has(fp)) {
5669
- return null;
5670
- }
5671
- seenMediaSignatures.add(fp);
5672
- }
5673
- return pic;
5873
+ if (isLegacy === true) return null;
5874
+ return createPic();
5674
5875
  }
5675
5876
  });
5676
- const htmlElements = await doc.render();
5677
- const contentNodes = [];
5678
- const seenInContentBlocks = /* @__PURE__ */ new Set();
5679
- const extractBlocks = (nodes) => {
5680
- for (const item of nodes) {
5681
- if (!item || !(item instanceof HTMLElement)) continue;
5682
- const tag = item.tagName.toLowerCase();
5683
- const hasChildBlocks = Array.from(item.children).some((c) => {
5684
- const ct = c.tagName.toLowerCase();
5685
- return ["p", "div", "table", "h1", "h2", "h3", "h4", "h5", "h6", "section", "article", "ul", "ol"].includes(ct);
5686
- });
5687
- if (hasChildBlocks && !["table", "tr", "td", "th", "ul", "ol", "li"].includes(tag)) {
5688
- extractBlocks(Array.from(item.children));
5689
- } else {
5690
- const fp = extractMediaFingerprint(item);
5691
- if (fp) {
5692
- if (seenInContentBlocks.has(fp)) {
5693
- continue;
5694
- }
5695
- seenInContentBlocks.add(fp);
5696
- }
5697
- const hasMedia = item.querySelector("img, svg, canvas, table") !== null || ["img", "svg", "table"].includes(tag);
5698
- const textContent = (item.textContent || "").trim();
5699
- if (!hasMedia && textContent.length === 0) {
5700
- continue;
5701
- }
5702
- const svgs = item.querySelectorAll("svg, img");
5703
- svgs.forEach((s) => {
5704
- const el = s;
5705
- el.style.maxWidth = "100%";
5706
- el.style.maxHeight = "360px";
5707
- el.style.display = "block";
5708
- el.style.margin = "12px auto";
5709
- if (s.tagName.toLowerCase() === "svg") {
5710
- s.removeAttribute("width");
5711
- s.removeAttribute("height");
5712
- el.style.width = "100%";
5713
- el.style.maxHeight = "360px";
5714
- }
5715
- });
5716
- if (tag === "p" || tag === "div") {
5717
- item.style.display = "block";
5718
- item.style.marginBottom = "12px";
5719
- item.style.lineHeight = "1.6";
5720
- }
5721
- contentNodes.push(item);
5877
+ const elements = await doc.render();
5878
+ let unsupportedIndex = 1;
5879
+ const usedTables = /* @__PURE__ */ new Set();
5880
+ for (let i = 0; i < elements.length; i++) {
5881
+ const el = elements[i];
5882
+ const text = el.textContent || "";
5883
+ if (text.includes("[Unsupported image format]")) {
5884
+ if (extractedImages[unsupportedIndex]) {
5885
+ const img = document.createElement("img");
5886
+ img.src = extractedImages[unsupportedIndex].dataUrl;
5887
+ img.style.width = "100%";
5888
+ img.style.height = "auto";
5889
+ img.style.maxHeight = "430px";
5890
+ img.style.objectFit = "contain";
5891
+ img.style.display = "block";
5892
+ img.style.margin = "12px auto";
5893
+ el.innerHTML = "";
5894
+ el.appendChild(img);
5895
+ unsupportedIndex++;
5722
5896
  }
5723
5897
  }
5724
- };
5725
- extractBlocks(htmlElements);
5726
- tables.forEach((table) => {
5727
- const tableEl = renderRtfTableElement(table);
5728
- let inserted = false;
5729
- if (table.anchorBefore && table.anchorBefore.length > 10) {
5730
- const keyword = table.anchorBefore.slice(-35).trim();
5731
- for (let i = 0; i < contentNodes.length; i++) {
5732
- if (contentNodes[i].textContent?.includes(keyword)) {
5733
- contentNodes.splice(i + 1, 0, tableEl);
5734
- inserted = true;
5735
- break;
5898
+ if (tables.length > 0) {
5899
+ for (let t = 0; t < tables.length; t++) {
5900
+ if (usedTables.has(t)) continue;
5901
+ const tbl = tables[t];
5902
+ if (tbl.rows.length >= 2) {
5903
+ const sampleCell1 = tbl.rows[1]?.[1] || tbl.rows[0]?.[1] || "";
5904
+ const sampleCell2 = tbl.rows[2]?.[1] || tbl.rows[1]?.[0] || "";
5905
+ const match1 = sampleCell1 && text.includes(sampleCell1.slice(0, 15).trim());
5906
+ const match2 = sampleCell2 && text.includes(sampleCell2.slice(0, 15).trim());
5907
+ if (match1 && match2) {
5908
+ el.innerHTML = "";
5909
+ el.appendChild(renderRtfTableElement(tbl));
5910
+ usedTables.add(t);
5911
+ break;
5912
+ }
5736
5913
  }
5737
5914
  }
5738
5915
  }
5739
- if (!inserted && table.anchorAfter && table.anchorAfter.length > 10) {
5740
- const keyword = table.anchorAfter.slice(0, 35).trim();
5741
- for (let i = 0; i < contentNodes.length; i++) {
5742
- if (contentNodes[i].textContent?.includes(keyword)) {
5743
- contentNodes.splice(i, 0, tableEl);
5744
- inserted = true;
5745
- break;
5746
- }
5747
- }
5916
+ }
5917
+ elements.forEach((el) => {
5918
+ const svgs = el.querySelectorAll ? Array.from(el.querySelectorAll("svg")) : [];
5919
+ svgs.forEach((svg) => {
5920
+ svg.removeAttribute("width");
5921
+ svg.removeAttribute("height");
5922
+ svg.style.maxWidth = "100%";
5923
+ svg.style.maxHeight = "430px";
5924
+ svg.style.height = "auto";
5925
+ svg.style.display = "block";
5926
+ svg.style.margin = "12px auto";
5927
+ });
5928
+ const imgs = el.querySelectorAll ? Array.from(el.querySelectorAll("img")) : [];
5929
+ imgs.forEach((img) => {
5930
+ img.style.maxWidth = "100%";
5931
+ img.style.maxHeight = "430px";
5932
+ img.style.height = "auto";
5933
+ img.style.objectFit = "contain";
5934
+ img.style.display = "block";
5935
+ img.style.margin = "12px auto";
5936
+ });
5937
+ });
5938
+ const allImgs = Array.from(document.querySelectorAll("img")).concat(
5939
+ elements.flatMap((el) => Array.from(el.querySelectorAll ? el.querySelectorAll("img") : []))
5940
+ );
5941
+ await Promise.all(allImgs.map((img) => {
5942
+ if (img.complete && img.naturalHeight > 0) return Promise.resolve();
5943
+ if (img.decode) return img.decode().catch(() => {
5944
+ });
5945
+ return new Promise((r) => {
5946
+ img.onload = r;
5947
+ img.onerror = r;
5948
+ });
5949
+ }));
5950
+ elements.forEach((el) => {
5951
+ const text = el.textContent || "";
5952
+ if (text.includes("\uF0B7")) {
5953
+ const cleanText = text.replace(/^[\s\uf0b7\t]+/, "");
5954
+ el.style.display = "flex";
5955
+ el.style.alignItems = "flex-start";
5956
+ el.style.margin = "6px 0 6px 28px";
5957
+ el.style.fontSize = "11pt";
5958
+ el.style.lineHeight = "1.5";
5959
+ el.innerHTML = `<span style="margin-right:10px; user-select:none;">&#9633;</span><span>${cleanText}</span>`;
5748
5960
  }
5749
- if (!inserted) {
5750
- if (contentNodes.length > 2) {
5751
- contentNodes.splice(2, 0, tableEl);
5752
- } else {
5753
- contentNodes.push(tableEl);
5754
- }
5961
+ });
5962
+ elements.forEach((el) => {
5963
+ const text = (el.textContent || "").trim();
5964
+ const hasMedia = el.querySelector("img, svg, canvas, table") !== null || ["IMG", "SVG", "TABLE"].includes(el.tagName);
5965
+ if (isHeadingElement(el)) {
5966
+ el.style.marginTop = "20px";
5967
+ el.style.marginBottom = "10px";
5968
+ el.style.lineHeight = "1.25";
5969
+ } else if (text.length > 0 && !hasMedia) {
5970
+ el.style.marginBottom = "12px";
5971
+ el.style.lineHeight = "1.45";
5755
5972
  }
5756
5973
  });
5757
- const createRtfCard = (pageNum) => {
5974
+ const measureCard = document.createElement("div");
5975
+ measureCard.style.width = `${pageWidth}px`;
5976
+ measureCard.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
5977
+ measureCard.style.boxSizing = "border-box";
5978
+ measureCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5979
+ measureCard.style.lineHeight = "1.45";
5980
+ measureCard.style.visibility = "hidden";
5981
+ measureCard.style.position = "absolute";
5982
+ measureCard.style.top = "-99999px";
5983
+ document.body.appendChild(measureCard);
5984
+ const createPageCard = (num) => {
5758
5985
  const card = document.createElement("div");
5759
5986
  card.className = "fp-rtf-page-card";
5760
- card.setAttribute("data-page-number", String(pageNum));
5987
+ card.setAttribute("data-page-number", String(num));
5761
5988
  card.style.backgroundColor = "#ffffff";
5762
5989
  card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08), 0 1px 3px rgba(0,0,0,0.04)";
5763
5990
  card.style.borderRadius = "4px";
5764
- card.style.padding = "64px 56px";
5765
- card.style.width = "816px";
5766
- card.style.minHeight = "1056px";
5767
- card.style.maxHeight = "1056px";
5768
- card.style.overflow = "hidden";
5991
+ card.style.width = `${pageWidth}px`;
5992
+ card.style.height = `${pageHeight}px`;
5993
+ card.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
5769
5994
  card.style.boxSizing = "border-box";
5995
+ card.style.overflow = "hidden";
5770
5996
  card.style.marginBottom = "24px";
5771
- card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5772
- card.style.lineHeight = "1.6";
5773
5997
  card.style.color = "#1e293b";
5998
+ card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5999
+ card.style.lineHeight = "1.45";
5774
6000
  card.style.position = "relative";
6001
+ card.style.textAlign = "left";
5775
6002
  return card;
5776
6003
  };
5777
- wrapper.innerHTML = "";
5778
- const measureCard = createRtfCard(0);
5779
- measureCard.style.maxHeight = "none";
5780
- measureCard.style.height = "auto";
5781
- wrapper.appendChild(measureCard);
5782
- contentNodes.forEach((node) => measureCard.appendChild(node));
5783
- const childHeights = contentNodes.map((c) => {
5784
- const rect = c.getBoundingClientRect ? c.getBoundingClientRect() : null;
5785
- const rectH = rect ? rect.height : 0;
5786
- const offH = c.offsetHeight || 0;
5787
- let realH = Math.max(rectH, offH);
5788
- try {
5789
- const cs = window.getComputedStyle(c);
5790
- realH += (parseFloat(cs.marginTop) || 0) + (parseFloat(cs.marginBottom) || 0);
5791
- } catch {
5792
- }
5793
- const hasMedia = c.querySelector("img, svg") !== null || ["img", "svg"].includes(c.tagName.toLowerCase());
5794
- const hasTable = c.querySelector("table") !== null || c.tagName.toLowerCase() === "table";
5795
- if (hasMedia) {
5796
- realH = Math.max(realH, 300);
5797
- } else if (hasTable) {
5798
- realH = Math.max(realH, 240);
5799
- }
5800
- if (realH > 0) return realH;
5801
- const textLen = c.textContent?.trim().length || 0;
5802
- return Math.max(28, Math.ceil(textLen / 75) * 26 + 16);
5803
- });
5804
- wrapper.innerHTML = "";
5805
- let curCard = createRtfCard(1);
5806
- wrapper.appendChild(curCard);
5807
- pageElements = [curCard];
5808
- let curH = 0;
5809
- const maxH = 860;
5810
- for (let i = 0; i < contentNodes.length; i++) {
5811
- const child = contentNodes[i];
5812
- const chH = childHeights[i];
5813
- const isChildEmpty = (child.textContent || "").trim().length === 0 && !child.querySelector("table, img, svg, canvas");
5814
- if (curH === 0 && isChildEmpty) {
6004
+ const pages = [];
6005
+ let curCard = createPageCard(1);
6006
+ pages.push(curCard);
6007
+ let curHeight = 0;
6008
+ for (let i = 0; i < elements.length; i++) {
6009
+ const el = elements[i];
6010
+ if (!el || !(el instanceof HTMLElement)) continue;
6011
+ const text = (el.textContent || "").trim();
6012
+ const hasMedia = el.querySelector("img, svg, canvas, table") !== null || ["IMG", "SVG", "TABLE"].includes(el.tagName);
6013
+ const isEmptyPar = !hasMedia && text.length === 0;
6014
+ if (isEmptyPar) {
6015
+ const emptyH = 35;
6016
+ if (curHeight + emptyH > printableHeight) {
6017
+ if (curCard.childNodes.length > 0) {
6018
+ curCard = createPageCard(pages.length + 1);
6019
+ pages.push(curCard);
6020
+ curHeight = 0;
6021
+ }
6022
+ }
6023
+ const spacer = document.createElement("div");
6024
+ spacer.style.height = `${emptyH}px`;
6025
+ curCard.appendChild(spacer);
6026
+ curHeight += emptyH;
5815
6027
  continue;
5816
6028
  }
5817
- const isTable = child.querySelector("table") !== null || child.tagName.toLowerCase() === "table";
5818
- const shouldBreakBeforeTable = isTable && curH > 400 && curCard.childNodes.length > 0;
5819
- if ((curH + chH > maxH || shouldBreakBeforeTable) && curCard.childNodes.length > 0) {
5820
- curCard = createRtfCard(pageElements.length + 1);
5821
- wrapper.appendChild(curCard);
5822
- pageElements.push(curCard);
5823
- curH = 0;
6029
+ measureCard.innerHTML = "";
6030
+ const clone = el.cloneNode(true);
6031
+ measureCard.appendChild(clone);
6032
+ const compStyle = window.getComputedStyle(clone);
6033
+ const mt = parseFloat(compStyle.marginTop) || 0;
6034
+ const mb = parseFloat(compStyle.marginBottom) || 0;
6035
+ const elH = clone.offsetHeight + mt + mb;
6036
+ const isHeading = isHeadingElement(el);
6037
+ let nextContentH = 0;
6038
+ if (isHeading || hasMedia) {
6039
+ for (let j = i + 1; j < elements.length; j++) {
6040
+ const nextEl = elements[j];
6041
+ if (nextEl && (nextEl.textContent || "").trim().length > 0) {
6042
+ measureCard.innerHTML = "";
6043
+ const nClone = nextEl.cloneNode(true);
6044
+ measureCard.appendChild(nClone);
6045
+ const nStyle = window.getComputedStyle(nClone);
6046
+ nextContentH = nClone.offsetHeight + (parseFloat(nStyle.marginTop) || 0) + (parseFloat(nStyle.marginBottom) || 0);
6047
+ break;
6048
+ }
6049
+ }
5824
6050
  }
5825
- curCard.appendChild(child);
5826
- curH += chH;
5827
- }
5828
- pageElements = pageElements.filter((card) => {
6051
+ const remainingSpace = printableHeight - curHeight;
6052
+ const isLargeMedia = hasMedia && elH > 300;
6053
+ const keepWithNextOverflow = isHeading && nextContentH > 0 && elH + nextContentH + 20 > remainingSpace;
6054
+ const largeMediaOverflow = isLargeMedia && curHeight > 0 && elH + 80 > remainingSpace;
6055
+ const shouldBreak = (curHeight + elH > printableHeight || keepWithNextOverflow || largeMediaOverflow) && curCard.childNodes.length > 0;
6056
+ if (shouldBreak) {
6057
+ curCard = createPageCard(pages.length + 1);
6058
+ pages.push(curCard);
6059
+ curHeight = 0;
6060
+ }
6061
+ curCard.appendChild(el);
6062
+ curHeight += elH;
6063
+ }
6064
+ measureCard.remove();
6065
+ pageElements = pages.filter((card) => {
5829
6066
  const hasText = (card.textContent || "").trim().length > 0;
5830
- const hasMedia = card.querySelector("table, img, svg, canvas") !== null;
5831
- return hasText || hasMedia;
6067
+ const hasCardMedia = card.querySelector("table, img, svg, canvas") !== null;
6068
+ return hasText || hasCardMedia;
5832
6069
  });
5833
6070
  if (pageElements.length === 0) {
5834
6071
  pageElements = [curCard];
5835
6072
  }
6073
+ wrapper.innerHTML = "";
6074
+ pageElements.forEach((card, idx) => {
6075
+ card.setAttribute("data-page-number", String(idx + 1));
6076
+ card.style.display = idx === 0 ? "block" : "none";
6077
+ wrapper.appendChild(card);
6078
+ });
5836
6079
  } catch (err) {
5837
6080
  console.warn("[RtfPlugin] RTF render error, fallback text:", err);
5838
- const text = new TextDecoder("latin1").decode(ctx.buffer);
5839
- const tables = parseRtfTables(text);
6081
+ const text = rawRtf;
5840
6082
  const rawPages = text.split(/\\page\b/).map((segment) => {
5841
6083
  return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
5842
- }).filter((p) => p.length > 0);
6084
+ }).filter((p2) => p2.length > 0);
5843
6085
  const pages = rawPages.length > 0 ? rawPages : [text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim()];
5844
6086
  for (let i = 0; i < pages.length; i++) {
5845
6087
  const pageCard = document.createElement("div");
@@ -5847,9 +6089,9 @@ var RtfPlugin = class {
5847
6089
  pageCard.style.backgroundColor = "#ffffff";
5848
6090
  pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
5849
6091
  pageCard.style.borderRadius = "4px";
5850
- pageCard.style.padding = "64px 56px";
5851
- pageCard.style.width = "816px";
5852
- pageCard.style.minHeight = "1056px";
6092
+ pageCard.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
6093
+ pageCard.style.width = `${pageWidth}px`;
6094
+ pageCard.style.minHeight = `${pageHeight}px`;
5853
6095
  pageCard.style.boxSizing = "border-box";
5854
6096
  pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5855
6097
  pageCard.style.fontSize = "12pt";
@@ -5869,11 +6111,9 @@ var RtfPlugin = class {
5869
6111
  let currentPage = 1;
5870
6112
  const showPage = (pageNum) => {
5871
6113
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
5872
- if (totalPages > 1) {
5873
- pageElements.forEach((el, idx) => {
5874
- el.style.display = idx + 1 === currentPage ? "block" : "none";
5875
- });
5876
- }
6114
+ pageElements.forEach((el, idx) => {
6115
+ el.style.display = idx + 1 === currentPage ? "block" : "none";
6116
+ });
5877
6117
  ctx.container.scrollTop = 0;
5878
6118
  ctx.emit("page-change", { page: currentPage, total: totalPages });
5879
6119
  };
@@ -5940,6 +6180,15 @@ var RtfPlugin = class {
5940
6180
  rotation = 0;
5941
6181
  applyTransform();
5942
6182
  },
6183
+ resetZoom: () => {
6184
+ isUserZoomed = false;
6185
+ fitMode = "width";
6186
+ scale = calculateFitScale("width");
6187
+ rotation = 0;
6188
+ ctx.container.scrollTop = 0;
6189
+ ctx.container.scrollLeft = 0;
6190
+ applyTransform();
6191
+ },
5943
6192
  rotateCW: () => {
5944
6193
  rotation = (rotation + 90) % 360;
5945
6194
  applyTransform();
@@ -6007,6 +6256,14 @@ var HtmlPreviewPlugin = class {
6007
6256
  group: "zoom",
6008
6257
  execute: () => instance.fitToPage?.()
6009
6258
  },
6259
+ {
6260
+ id: "reset-zoom",
6261
+ icon: "reset-zoom",
6262
+ label: "Reset Zoom",
6263
+ type: "button",
6264
+ group: "zoom",
6265
+ execute: () => instance.resetZoom?.()
6266
+ },
6010
6267
  {
6011
6268
  id: "copy",
6012
6269
  icon: "copy",
@@ -6079,6 +6336,12 @@ var HtmlPreviewPlugin = class {
6079
6336
  scale = 1;
6080
6337
  iframe.style.transform = "scale(1)";
6081
6338
  },
6339
+ resetZoom: () => {
6340
+ scale = 1;
6341
+ iframe.style.transform = "scale(1)";
6342
+ ctx.container.scrollTop = 0;
6343
+ ctx.container.scrollLeft = 0;
6344
+ },
6082
6345
  copy: () => {
6083
6346
  navigator.clipboard.writeText(rawHtml);
6084
6347
  },
@@ -6179,6 +6442,14 @@ var OpenDocumentPlugin = class {
6179
6442
  group: "zoom",
6180
6443
  execute: () => instance.fitToPage?.()
6181
6444
  },
6445
+ {
6446
+ id: "reset-zoom",
6447
+ icon: "reset-zoom",
6448
+ label: "Reset Zoom",
6449
+ type: "button",
6450
+ group: "zoom",
6451
+ execute: () => instance.resetZoom?.()
6452
+ },
6182
6453
  {
6183
6454
  id: "rotate-cw",
6184
6455
  icon: "rotate-cw",
@@ -6446,6 +6717,15 @@ var OpenDocumentPlugin = class {
6446
6717
  rotation = 0;
6447
6718
  applyTransform();
6448
6719
  },
6720
+ resetZoom: () => {
6721
+ isUserZoomed = false;
6722
+ fitMode = "width";
6723
+ scale = calculateFitScale("width");
6724
+ rotation = 0;
6725
+ container.scrollTop = 0;
6726
+ container.scrollLeft = 0;
6727
+ applyTransform();
6728
+ },
6449
6729
  rotateCW: () => {
6450
6730
  rotation = (rotation + 90) % 360;
6451
6731
  applyTransform();
@@ -6789,6 +7069,14 @@ var DocPlugin = class {
6789
7069
  group: "zoom",
6790
7070
  execute: () => instance.fitToPage?.()
6791
7071
  },
7072
+ {
7073
+ id: "reset-zoom",
7074
+ icon: "reset-zoom",
7075
+ label: "Reset Zoom",
7076
+ type: "button",
7077
+ group: "zoom",
7078
+ execute: () => instance.resetZoom?.()
7079
+ },
6792
7080
  {
6793
7081
  id: "rotate-cw",
6794
7082
  icon: "rotate-cw",
@@ -6995,6 +7283,15 @@ var DocPlugin = class {
6995
7283
  rotation = 0;
6996
7284
  applyTransform();
6997
7285
  },
7286
+ resetZoom: () => {
7287
+ isUserZoomed = false;
7288
+ fitMode = "width";
7289
+ scale = calculateFitScale("width");
7290
+ rotation = 0;
7291
+ ctx.container.scrollTop = 0;
7292
+ ctx.container.scrollLeft = 0;
7293
+ applyTransform();
7294
+ },
6998
7295
  rotateCW: () => {
6999
7296
  rotation = (rotation + 90) % 360;
7000
7297
  applyTransform();
@@ -7475,6 +7772,14 @@ var PptPlugin = class {
7475
7772
  group: "zoom",
7476
7773
  execute: () => instance.fitToPage?.()
7477
7774
  },
7775
+ {
7776
+ id: "reset-zoom",
7777
+ icon: "reset-zoom",
7778
+ label: "Reset Zoom",
7779
+ type: "button",
7780
+ group: "zoom",
7781
+ execute: () => instance.resetZoom?.()
7782
+ },
7478
7783
  {
7479
7784
  id: "rotate-cw",
7480
7785
  icon: "rotate-cw",
@@ -7663,6 +7968,13 @@ var PptPlugin = class {
7663
7968
  rotation = 0;
7664
7969
  applyTransform();
7665
7970
  },
7971
+ resetZoom: () => {
7972
+ scale = calculateFitScale();
7973
+ rotation = 0;
7974
+ container.scrollTop = 0;
7975
+ container.scrollLeft = 0;
7976
+ applyTransform();
7977
+ },
7666
7978
  rotateCW: () => {
7667
7979
  rotation = (rotation + 90) % 360;
7668
7980
  applyTransform();