@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/react.cjs CHANGED
@@ -529,6 +529,7 @@ var ICON_COPY = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" str
529
529
  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>`;
530
530
  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>`;
531
531
  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>`;
532
+ 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>`;
532
533
  var ICON_MAP = {
533
534
  "zoom-in": ICON_ZOOM_IN,
534
535
  "zoom-out": ICON_ZOOM_OUT,
@@ -558,7 +559,10 @@ var ICON_MAP = {
558
559
  "open-window": ICON_EXTERNAL_WINDOW,
559
560
  "external-window": ICON_EXTERNAL_WINDOW,
560
561
  "openWindow": ICON_EXTERNAL_WINDOW,
561
- "openSeparateWindow": ICON_EXTERNAL_WINDOW
562
+ "openSeparateWindow": ICON_EXTERNAL_WINDOW,
563
+ "reset-zoom": ICON_RESET_ZOOM,
564
+ "zoom-reset": ICON_RESET_ZOOM,
565
+ "resetZoom": ICON_RESET_ZOOM
562
566
  };
563
567
  var ToolbarController = class {
564
568
  el;
@@ -591,6 +595,10 @@ var ToolbarController = class {
591
595
  this.config.fitToPage = false;
592
596
  this.config.fitWidth = false;
593
597
  }
598
+ if (actionId === "reset-zoom" || actionId === "zoom-reset" || actionId === "resetZoom") {
599
+ this.config.resetZoom = false;
600
+ this.config.zoomReset = false;
601
+ }
594
602
  if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = false;
595
603
  if (actionId === "fullscreen") this.config.fullscreen = false;
596
604
  if (actionId === "download") this.config.download = false;
@@ -615,6 +623,10 @@ var ToolbarController = class {
615
623
  this.config.fitToPage = true;
616
624
  this.config.fitWidth = true;
617
625
  }
626
+ if (actionId === "reset-zoom" || actionId === "zoom-reset" || actionId === "resetZoom") {
627
+ this.config.resetZoom = true;
628
+ this.config.zoomReset = true;
629
+ }
618
630
  if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = true;
619
631
  if (actionId === "fullscreen") this.config.fullscreen = true;
620
632
  if (actionId === "download") this.config.download = true;
@@ -634,6 +646,7 @@ var ToolbarController = class {
634
646
  if (actionId === "zoomIn") return "zoom-in";
635
647
  if (actionId === "zoomOut") return "zoom-out";
636
648
  if (actionId === "fitPage" || actionId === "fitToPage" || actionId === "fitWidth") return "fit-page";
649
+ if (actionId === "resetZoom" || actionId === "zoomReset") return "reset-zoom";
637
650
  if (actionId === "rotateCW") return "rotate-cw";
638
651
  if (actionId === "rotateCCW") return "rotate-ccw";
639
652
  if (actionId === "openWindow" || actionId === "openSeparateWindow") return "open-window";
@@ -676,6 +689,9 @@ var ToolbarController = class {
676
689
  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)) {
677
690
  return false;
678
691
  }
692
+ if ((id === "reset-zoom" || id === "zoom-reset") && (c.resetZoom === false || c.zoomReset === false || c["reset-zoom"] === false || c["zoom-reset"] === false)) {
693
+ return false;
694
+ }
679
695
  if ((id === "rotate-cw" || id === "rotate-ccw" || id === "rotate") && (c.rotate === false || c.rotateCW === false || c.rotateCCW === false || c["rotate-cw"] === false)) {
680
696
  return false;
681
697
  }
@@ -1122,6 +1138,9 @@ var FilePreviewViewer = class _FilePreviewViewer {
1122
1138
  this.activeInstance = instance;
1123
1139
  instance.openInSeparateWindow = () => this.openInSeparateWindow();
1124
1140
  instance.toggleThumbnails = () => this.toggleThumbnails();
1141
+ if (!instance.resetZoom && instance.fitToPage) {
1142
+ instance.resetZoom = () => instance.fitToPage?.();
1143
+ }
1125
1144
  this.hideLoading();
1126
1145
  this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
1127
1146
  const isToolbarVisible = options.showToolbar !== false && options.toolbar !== false;
@@ -1405,6 +1424,16 @@ var FilePreviewViewer = class _FilePreviewViewer {
1405
1424
  fitToPage() {
1406
1425
  this.activeInstance?.fitToPage?.();
1407
1426
  }
1427
+ /**
1428
+ * Reset zoom level to initial/default fit state.
1429
+ */
1430
+ resetZoom() {
1431
+ if (this.activeInstance?.resetZoom) {
1432
+ this.activeInstance.resetZoom();
1433
+ } else if (this.activeInstance?.fitToPage) {
1434
+ this.activeInstance.fitToPage();
1435
+ }
1436
+ }
1408
1437
  /**
1409
1438
  * Zoom in.
1410
1439
  */
@@ -2026,6 +2055,14 @@ var PdfPlugin = class {
2026
2055
  group: "zoom",
2027
2056
  execute: () => instance.fitToPage?.()
2028
2057
  },
2058
+ {
2059
+ id: "reset-zoom",
2060
+ icon: "reset-zoom",
2061
+ label: "Reset Zoom",
2062
+ type: "button",
2063
+ group: "zoom",
2064
+ execute: () => instance.resetZoom?.()
2065
+ },
2029
2066
  {
2030
2067
  id: "fit-width",
2031
2068
  icon: "fit-width",
@@ -2288,6 +2325,14 @@ var PdfPlugin = class {
2288
2325
  zoomScale = 1;
2289
2326
  renderPage(currentPage);
2290
2327
  },
2328
+ resetZoom: () => {
2329
+ fitMode = "page";
2330
+ zoomScale = 1;
2331
+ rotation = 0;
2332
+ container.scrollTop = 0;
2333
+ container.scrollLeft = 0;
2334
+ renderPage(currentPage);
2335
+ },
2291
2336
  fitToWidth: () => {
2292
2337
  fitMode = "width";
2293
2338
  zoomScale = 1;
@@ -2455,6 +2500,16 @@ var MediaPlugin = class {
2455
2500
  instance.fitToPage?.();
2456
2501
  }
2457
2502
  },
2503
+ {
2504
+ id: "reset-zoom",
2505
+ icon: "reset-zoom",
2506
+ label: "Reset Zoom",
2507
+ type: "button",
2508
+ group: "zoom",
2509
+ execute: () => {
2510
+ instance.resetZoom?.();
2511
+ }
2512
+ },
2458
2513
  {
2459
2514
  id: "rotate-cw",
2460
2515
  icon: "rotate-cw",
@@ -2628,6 +2683,13 @@ var MediaPlugin = class {
2628
2683
  rotation = 0;
2629
2684
  applyTransform();
2630
2685
  } : void 0,
2686
+ resetZoom: isImage ? () => {
2687
+ currentZoom = 1;
2688
+ rotation = 0;
2689
+ ctx.container.scrollTop = 0;
2690
+ ctx.container.scrollLeft = 0;
2691
+ applyTransform();
2692
+ } : void 0,
2631
2693
  rotateCW: isImage || isVideo ? () => {
2632
2694
  rotation = (rotation + 90) % 360;
2633
2695
  applyTransform();
@@ -2744,6 +2806,14 @@ var DocxPlugin = class {
2744
2806
  group: "zoom",
2745
2807
  execute: () => instance.fitToPage?.()
2746
2808
  },
2809
+ {
2810
+ id: "reset-zoom",
2811
+ icon: "reset-zoom",
2812
+ label: "Reset Zoom",
2813
+ type: "button",
2814
+ group: "zoom",
2815
+ execute: () => instance.resetZoom?.()
2816
+ },
2747
2817
  {
2748
2818
  id: "rotate-cw",
2749
2819
  icon: "rotate-cw",
@@ -3060,6 +3130,14 @@ var DocxPlugin = class {
3060
3130
  rotation = 0;
3061
3131
  applyTransform();
3062
3132
  },
3133
+ resetZoom: () => {
3134
+ isUserZoomed = false;
3135
+ scale = calculateFitScale("page");
3136
+ rotation = 0;
3137
+ ctx.container.scrollTop = 0;
3138
+ ctx.container.scrollLeft = 0;
3139
+ applyTransform();
3140
+ },
3063
3141
  rotateCW: () => {
3064
3142
  rotation = (rotation + 90) % 360;
3065
3143
  applyTransform();
@@ -3509,6 +3587,16 @@ var ExcelPlugin = class {
3509
3587
  instance.zoomIn?.();
3510
3588
  }
3511
3589
  },
3590
+ {
3591
+ id: "reset-zoom",
3592
+ icon: "reset-zoom",
3593
+ label: "Reset Zoom",
3594
+ type: "button",
3595
+ group: "zoom",
3596
+ execute: () => {
3597
+ instance.resetZoom?.();
3598
+ }
3599
+ },
3512
3600
  {
3513
3601
  id: "download",
3514
3602
  icon: "download",
@@ -3696,6 +3784,12 @@ var ExcelPlugin = class {
3696
3784
  scale = calculateFitScale();
3697
3785
  applyTransform();
3698
3786
  },
3787
+ resetZoom: () => {
3788
+ scale = calculateFitScale();
3789
+ contentArea.scrollTop = 0;
3790
+ contentArea.scrollLeft = 0;
3791
+ applyTransform();
3792
+ },
3699
3793
  rotateCW: () => {
3700
3794
  },
3701
3795
  rotateCCW: () => {
@@ -3826,6 +3920,16 @@ var CsvPlugin = class {
3826
3920
  instance.zoomIn?.();
3827
3921
  }
3828
3922
  },
3923
+ {
3924
+ id: "reset-zoom",
3925
+ icon: "reset-zoom",
3926
+ label: "Reset Zoom",
3927
+ type: "button",
3928
+ group: "zoom",
3929
+ execute: () => {
3930
+ instance.resetZoom?.();
3931
+ }
3932
+ },
3829
3933
  {
3830
3934
  id: "download",
3831
3935
  icon: "download",
@@ -4015,6 +4119,12 @@ var CsvPlugin = class {
4015
4119
  scale = calculateFitScale();
4016
4120
  applyScale();
4017
4121
  },
4122
+ resetZoom: () => {
4123
+ scale = calculateFitScale();
4124
+ container.scrollTop = 0;
4125
+ container.scrollLeft = 0;
4126
+ applyScale();
4127
+ },
4018
4128
  rotateCW: () => {
4019
4129
  },
4020
4130
  rotateCCW: () => {
@@ -4130,6 +4240,16 @@ var CodePlugin = class {
4130
4240
  instance.zoomIn?.();
4131
4241
  }
4132
4242
  },
4243
+ {
4244
+ id: "reset-zoom",
4245
+ icon: "reset-zoom",
4246
+ label: "Reset Zoom",
4247
+ type: "button",
4248
+ group: "zoom",
4249
+ execute: () => {
4250
+ instance.resetZoom?.();
4251
+ }
4252
+ },
4133
4253
  {
4134
4254
  id: "copy",
4135
4255
  icon: "copy",
@@ -4409,6 +4529,15 @@ var CodePlugin = class {
4409
4529
  zoomLevel = isTxt ? calculateTxtFit() : 1;
4410
4530
  updateTransform();
4411
4531
  },
4532
+ resetZoom: () => {
4533
+ isUserZoomed = false;
4534
+ fontSize = 13;
4535
+ rotation = 0;
4536
+ zoomLevel = isTxt ? calculateTxtFit() : 1;
4537
+ container.scrollTop = 0;
4538
+ container.scrollLeft = 0;
4539
+ updateTransform();
4540
+ },
4412
4541
  rotateCW: () => {
4413
4542
  rotation = (rotation + 90) % 360;
4414
4543
  updateTransform();
@@ -4471,11 +4600,19 @@ var ArchivePlugin = class {
4471
4600
  {
4472
4601
  id: "fit-page",
4473
4602
  icon: "fit-page",
4474
- label: "Reset Zoom",
4603
+ label: "Fit to Page",
4475
4604
  type: "button",
4476
4605
  group: "zoom",
4477
4606
  execute: () => instance.fitToPage?.()
4478
4607
  },
4608
+ {
4609
+ id: "reset-zoom",
4610
+ icon: "reset-zoom",
4611
+ label: "Reset Zoom",
4612
+ type: "button",
4613
+ group: "zoom",
4614
+ execute: () => instance.resetZoom?.()
4615
+ },
4479
4616
  {
4480
4617
  id: "download",
4481
4618
  icon: "download",
@@ -4630,7 +4767,13 @@ var ArchivePlugin = class {
4630
4767
  },
4631
4768
  fitToPage: () => {
4632
4769
  scale = 1;
4633
- wrapper.style.transform = `scale(1)`;
4770
+ wrapper.style.transform = "scale(1)";
4771
+ },
4772
+ resetZoom: () => {
4773
+ scale = 1;
4774
+ wrapper.style.transform = "scale(1)";
4775
+ ctx.container.scrollTop = 0;
4776
+ ctx.container.scrollLeft = 0;
4634
4777
  },
4635
4778
  download: () => {
4636
4779
  downloadFile(ctx.buffer, ctx.metadata.name || "archive.zip", "application/zip");
@@ -4682,6 +4825,14 @@ var MarkdownPlugin = class {
4682
4825
  group: "zoom",
4683
4826
  execute: () => instance.fitToPage?.()
4684
4827
  },
4828
+ {
4829
+ id: "reset-zoom",
4830
+ icon: "reset-zoom",
4831
+ label: "Reset Zoom",
4832
+ type: "button",
4833
+ group: "zoom",
4834
+ execute: () => instance.resetZoom?.()
4835
+ },
4685
4836
  {
4686
4837
  id: "copy",
4687
4838
  icon: "copy",
@@ -4835,6 +4986,12 @@ var MarkdownPlugin = class {
4835
4986
  fontSize = 15;
4836
4987
  wrapper.style.fontSize = "15px";
4837
4988
  },
4989
+ resetZoom: () => {
4990
+ fontSize = 15;
4991
+ wrapper.style.fontSize = "15px";
4992
+ ctx.container.scrollTop = 0;
4993
+ ctx.container.scrollLeft = 0;
4994
+ },
4838
4995
  download: () => {
4839
4996
  downloadFile(ctx.buffer, ctx.metadata.name || "document.md", "text/markdown");
4840
4997
  },
@@ -4928,6 +5085,14 @@ var PptxPlugin = class {
4928
5085
  group: "zoom",
4929
5086
  execute: () => instance.fitToPage?.()
4930
5087
  },
5088
+ {
5089
+ id: "reset-zoom",
5090
+ icon: "reset-zoom",
5091
+ label: "Reset Zoom",
5092
+ type: "button",
5093
+ group: "zoom",
5094
+ execute: () => instance.resetZoom?.()
5095
+ },
4931
5096
  {
4932
5097
  id: "rotate-cw",
4933
5098
  icon: "rotate-cw",
@@ -5047,6 +5212,13 @@ var PptxPlugin = class {
5047
5212
  rotation = 0;
5048
5213
  applyTransform();
5049
5214
  },
5215
+ resetZoom: () => {
5216
+ scale = calculateFitScale();
5217
+ rotation = 0;
5218
+ wrapper.scrollTop = 0;
5219
+ wrapper.scrollLeft = 0;
5220
+ applyTransform();
5221
+ },
5050
5222
  rotateCW: () => {
5051
5223
  rotation = (rotation + 90) % 360;
5052
5224
  applyTransform();
@@ -5122,6 +5294,14 @@ var ThreeDPlugin = class {
5122
5294
  group: "zoom",
5123
5295
  execute: () => instance.fitToPage?.()
5124
5296
  },
5297
+ {
5298
+ id: "reset-zoom",
5299
+ icon: "reset-zoom",
5300
+ label: "Reset Zoom",
5301
+ type: "button",
5302
+ group: "zoom",
5303
+ execute: () => instance.resetZoom?.()
5304
+ },
5125
5305
  {
5126
5306
  id: "rotate-cw",
5127
5307
  icon: "rotate-cw",
@@ -5258,6 +5438,7 @@ var ThreeDPlugin = class {
5258
5438
  controls.update();
5259
5439
  },
5260
5440
  fitToPage: fitCamera,
5441
+ resetZoom: fitCamera,
5261
5442
  rotateCW: () => {
5262
5443
  isWireframe = !isWireframe;
5263
5444
  materials.forEach((m) => {
@@ -5280,7 +5461,7 @@ function cleanRtfText(raw) {
5280
5461
  return String.fromCharCode(num);
5281
5462
  }).replace(/\\'([0-9a-fA-F]{2})/g, (_, hex) => {
5282
5463
  return String.fromCharCode(parseInt(hex, 16));
5283
- }).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();
5464
+ }).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();
5284
5465
  }
5285
5466
  function parseRtfTables(rtfText) {
5286
5467
  const rowSegments = rtfText.split(/\\row\b/);
@@ -5320,17 +5501,12 @@ function parseRtfTables(rtfText) {
5320
5501
  }
5321
5502
  const isNewTable = !currentTable || segmentStart - currentTable.lastEnd > 2500;
5322
5503
  if (isNewTable) {
5323
- const prevTextSlice = rtfText.slice(Math.max(0, segmentStart - 4e3), segmentStart);
5324
- const cleanPrev = cleanRtfText(prevTextSlice);
5325
- const anchorBefore = cleanPrev.slice(-80).trim();
5326
5504
  currentTable = {
5327
5505
  id: `RTF_TABLE_${rawTables.length}`,
5328
5506
  startPos: segmentStart,
5329
5507
  lastEnd: segmentEnd,
5330
5508
  rows: [],
5331
- columnWidths: cellWidths,
5332
- anchorBefore,
5333
- anchorAfter: ""
5509
+ columnWidths: cellWidths
5334
5510
  };
5335
5511
  rawTables.push(currentTable);
5336
5512
  }
@@ -5344,20 +5520,13 @@ function parseRtfTables(rtfText) {
5344
5520
  }
5345
5521
  charOffset += segment.length + 4;
5346
5522
  }
5347
- rawTables.forEach((tbl) => {
5348
- const afterSlice = rtfText.slice(tbl.lastEnd, Math.min(rtfText.length, tbl.lastEnd + 2e3));
5349
- const cleanAfter = cleanRtfText(afterSlice);
5350
- tbl.anchorAfter = cleanAfter.slice(0, 80).trim();
5351
- });
5352
5523
  return rawTables.map((tbl) => {
5353
5524
  const totalW = (tbl.columnWidths || []).reduce((a, b) => a + b, 0);
5354
5525
  const colPercents = totalW > 0 ? tbl.columnWidths.map((w) => Math.round(w / totalW * 100)) : [];
5355
5526
  return {
5356
5527
  id: tbl.id,
5357
5528
  rows: tbl.rows.map((r) => r.cells),
5358
- colPercents,
5359
- anchorBefore: tbl.anchorBefore,
5360
- anchorAfter: tbl.anchorAfter
5529
+ colPercents
5361
5530
  };
5362
5531
  });
5363
5532
  }
@@ -5370,8 +5539,6 @@ function renderRtfTableElement(table) {
5370
5539
  tableEl.style.fontSize = "10pt";
5371
5540
  tableEl.style.lineHeight = "1.5";
5372
5541
  tableEl.style.border = "1px solid #cbd5e1";
5373
- tableEl.style.borderRadius = "4px";
5374
- tableEl.style.boxSizing = "border-box";
5375
5542
  tableEl.style.backgroundColor = "#ffffff";
5376
5543
  const thead = document.createElement("thead");
5377
5544
  const tbody = document.createElement("tbody");
@@ -5380,27 +5547,17 @@ function renderRtfTableElement(table) {
5380
5547
  const isHeader = rIdx === 0;
5381
5548
  if (isHeader) {
5382
5549
  tr.style.backgroundColor = "#f8fafc";
5383
- tr.style.borderBottom = "2px solid #cbd5e1";
5384
- } else {
5385
- tr.style.borderBottom = "1px solid #e2e8f0";
5386
- if (rIdx % 2 === 0) {
5387
- tr.style.backgroundColor = "#fcfdfe";
5388
- }
5389
5550
  }
5390
5551
  rowCells.forEach((cellText, cIdx) => {
5391
5552
  const cellEl = document.createElement(isHeader ? "th" : "td");
5392
5553
  cellEl.style.padding = "8px 12px";
5393
5554
  cellEl.style.border = "1px solid #cbd5e1";
5394
5555
  cellEl.style.verticalAlign = "top";
5395
- cellEl.style.color = isHeader ? "#0f172a" : "#1e293b";
5396
- cellEl.style.fontWeight = isHeader ? "600" : "normal";
5397
5556
  if (table.colPercents && table.colPercents[cIdx]) {
5398
5557
  cellEl.style.width = `${table.colPercents[cIdx]}%`;
5399
5558
  }
5400
5559
  if (/^\d+$/.test(cellText.trim()) || cellText.trim() === "#") {
5401
5560
  cellEl.style.textAlign = "center";
5402
- } else {
5403
- cellEl.style.textAlign = "left";
5404
5561
  }
5405
5562
  cellEl.textContent = cellText;
5406
5563
  tr.appendChild(cellEl);
@@ -5415,23 +5572,19 @@ function renderRtfTableElement(table) {
5415
5572
  tableEl.appendChild(tbody);
5416
5573
  return tableEl;
5417
5574
  }
5418
- function extractMediaFingerprint(el) {
5419
- const img = el.tagName.toLowerCase() === "img" ? el : el.querySelector("img");
5420
- if (img && img.src) {
5421
- const s = img.src;
5422
- return s.length > 300 ? `img_${s.slice(0, 80)}_${s.length}_${s.slice(-80)}` : `img_${s}`;
5423
- }
5424
- const innerImg = el.querySelector("image");
5425
- if (innerImg) {
5426
- const h = innerImg.getAttribute("xlink:href") || innerImg.getAttribute("href") || "";
5427
- if (h) return h.length > 300 ? `svgimg_${h.slice(0, 80)}_${h.length}_${h.slice(-80)}` : `svgimg_${h}`;
5428
- }
5429
- const svg = el.tagName.toLowerCase() === "svg" ? el : el.querySelector("svg");
5430
- if (svg) {
5431
- const vb = svg.getAttribute("viewBox") || "";
5432
- return `svg_${vb}_${svg.innerHTML.length}`;
5433
- }
5434
- return null;
5575
+ function isHeadingElement(el) {
5576
+ if (["H1", "H2", "H3", "H4"].includes(el.tagName)) return true;
5577
+ const spans = el.querySelectorAll ? Array.from(el.querySelectorAll("span, b, strong, div")) : [];
5578
+ for (const s of spans) {
5579
+ const hEl = s;
5580
+ const fs = parseFloat(hEl.style.fontSize) || 0;
5581
+ const isBold = hEl.style.fontWeight === "bold" || parseInt(hEl.style.fontWeight, 10) >= 600 || ["B", "STRONG"].includes(hEl.tagName);
5582
+ if (isBold && fs >= 14) return true;
5583
+ }
5584
+ const elFs = parseFloat(el.style.fontSize) || 0;
5585
+ const elBold = el.style.fontWeight === "bold" || parseInt(el.style.fontWeight, 10) >= 600;
5586
+ if (elBold && elFs >= 14) return true;
5587
+ return false;
5435
5588
  }
5436
5589
  var RtfPlugin = class {
5437
5590
  id = "rtf";
@@ -5500,6 +5653,14 @@ var RtfPlugin = class {
5500
5653
  group: "zoom",
5501
5654
  execute: () => instance.fitToPage?.()
5502
5655
  },
5656
+ {
5657
+ id: "reset-zoom",
5658
+ icon: "reset-zoom",
5659
+ label: "Reset Zoom",
5660
+ type: "button",
5661
+ group: "zoom",
5662
+ execute: () => instance.resetZoom?.()
5663
+ },
5503
5664
  {
5504
5665
  id: "rotate-cw",
5505
5666
  icon: "rotate-cw",
@@ -5544,10 +5705,66 @@ var RtfPlugin = class {
5544
5705
  return actions;
5545
5706
  }
5546
5707
  async render(ctx) {
5708
+ const rawRtf = new TextDecoder("latin1").decode(ctx.buffer);
5709
+ const paperwMatch = rawRtf.match(/\\paperw(\d+)/);
5710
+ const paperhMatch = rawRtf.match(/\\paperh(\d+)/);
5711
+ const marglMatch = rawRtf.match(/\\margl(\d+)/);
5712
+ const margrMatch = rawRtf.match(/\\margr(\d+)/);
5713
+ const margtMatch = rawRtf.match(/\\margt(\d+)/);
5714
+ const margbMatch = rawRtf.match(/\\margb(\d+)/);
5715
+ const paperwTwips = paperwMatch ? parseInt(paperwMatch[1], 10) : 11906;
5716
+ const paperhTwips = paperhMatch ? parseInt(paperhMatch[1], 10) : 16838;
5717
+ const marglTwips = marglMatch ? parseInt(marglMatch[1], 10) : 1134;
5718
+ const margrTwips = margrMatch ? parseInt(margrMatch[1], 10) : 1134;
5719
+ const margtTwips = margtMatch ? parseInt(margtMatch[1], 10) : 1134;
5720
+ const margbTwips = margbMatch ? parseInt(margbMatch[1], 10) : 1134;
5721
+ const pageWidth = Math.round(paperwTwips / 15);
5722
+ const pageHeight = Math.round(paperhTwips / 15);
5723
+ const padLeft = Math.round(marglTwips / 15);
5724
+ const padRight = Math.round(margrTwips / 15);
5725
+ const padTop = Math.round(margtTwips / 15);
5726
+ const padBottom = Math.round(margbTwips / 15);
5727
+ const printableHeight = pageHeight - padTop - padBottom;
5728
+ const extractedImages = [];
5729
+ let p = 0;
5730
+ while ((p = rawRtf.indexOf("\\pict", p)) !== -1) {
5731
+ const startP = p;
5732
+ p += 5;
5733
+ const header = rawRtf.substring(startP, startP + 600);
5734
+ let mime = "";
5735
+ let magic = "";
5736
+ if (header.includes("\\pngblip")) {
5737
+ mime = "image/png";
5738
+ magic = "89504e47";
5739
+ } else if (header.includes("\\jpegblip")) {
5740
+ mime = "image/jpeg";
5741
+ magic = "ffd8ff";
5742
+ }
5743
+ if (!mime || !magic) continue;
5744
+ const magicPos = rawRtf.indexOf(magic, startP);
5745
+ if (magicPos === -1 || magicPos - startP > 3e3) continue;
5746
+ let endP = magicPos;
5747
+ while (endP < rawRtf.length && /[0-9a-fA-F\r\n\s]/.test(rawRtf[endP])) {
5748
+ endP++;
5749
+ }
5750
+ const cleanHex = rawRtf.substring(magicPos, endP).replace(/[\r\n\s]/g, "");
5751
+ if (cleanHex.length < 100) continue;
5752
+ const hexLen = cleanHex.length / 2;
5753
+ const u8 = new Uint8Array(hexLen);
5754
+ for (let k = 0; k < hexLen; k++) {
5755
+ u8[k] = parseInt(cleanHex.substr(k * 2, 2), 16);
5756
+ }
5757
+ let bStr = "";
5758
+ for (let k = 0; k < u8.length; k += 8192) {
5759
+ bStr += String.fromCharCode.apply(null, Array.from(u8.subarray(k, k + 8192)));
5760
+ }
5761
+ extractedImages.push({ mime, dataUrl: `data:${mime};base64,${btoa(bStr)}`, offset: startP });
5762
+ }
5763
+ const tables = parseRtfTables(rawRtf);
5547
5764
  const wrapper = document.createElement("div");
5548
5765
  wrapper.className = "fp-rtf-wrapper";
5549
5766
  wrapper.style.padding = "0";
5550
- wrapper.style.width = "816px";
5767
+ wrapper.style.width = `${pageWidth}px`;
5551
5768
  wrapper.style.margin = "0 auto";
5552
5769
  wrapper.style.boxSizing = "border-box";
5553
5770
  wrapper.style.display = "flex";
@@ -5567,9 +5784,8 @@ var RtfPlugin = class {
5567
5784
  let isUserZoomed = false;
5568
5785
  let fitMode = ctx?.options?.fitMode || "width";
5569
5786
  const calculateFitScale = (mode = fitMode) => {
5570
- const activeEl = pageElements[currentPage - 1] || wrapper;
5571
- const elW = 816;
5572
- const singlePageH = activeEl?.offsetHeight || 1056;
5787
+ const elW = pageWidth;
5788
+ const singlePageH = pageHeight;
5573
5789
  const availW = Math.max(280, ctx.container.clientWidth - 32);
5574
5790
  const availH = Math.max(280, ctx.container.clientHeight - 32);
5575
5791
  const sW = availW / elW;
@@ -5582,8 +5798,7 @@ var RtfPlugin = class {
5582
5798
  const applyTransform = () => {
5583
5799
  wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5584
5800
  wrapper.style.transformOrigin = "top center";
5585
- const activeEl = pageElements[currentPage - 1];
5586
- const baseH = activeEl?.offsetHeight || 1056;
5801
+ const baseH = pageHeight;
5587
5802
  const scaledH = baseH * scale;
5588
5803
  const extraH = Math.max(0, scaledH - baseH);
5589
5804
  wrapper.style.marginBottom = `${extraH + 32}px`;
@@ -5603,193 +5818,220 @@ var RtfPlugin = class {
5603
5818
  if (typeof RTFJS__namespace.loggingEnabled === "function") {
5604
5819
  RTFJS__namespace.loggingEnabled(false);
5605
5820
  }
5606
- const rawText = new TextDecoder("latin1").decode(ctx.buffer);
5607
- const tables = parseRtfTables(rawText);
5608
- const seenMediaSignatures = /* @__PURE__ */ new Set();
5609
5821
  const doc = new RTFJS__namespace.Document(ctx.buffer, {
5610
5822
  onPicture: (isLegacy, createPic) => {
5611
- if (isLegacy === true) {
5612
- return null;
5613
- }
5614
- const pic = createPic();
5615
- if (!pic) return null;
5616
- const fp = extractMediaFingerprint(pic);
5617
- if (fp) {
5618
- if (seenMediaSignatures.has(fp)) {
5619
- return null;
5620
- }
5621
- seenMediaSignatures.add(fp);
5622
- }
5623
- return pic;
5823
+ if (isLegacy === true) return null;
5824
+ return createPic();
5624
5825
  }
5625
5826
  });
5626
- const htmlElements = await doc.render();
5627
- const contentNodes = [];
5628
- const seenInContentBlocks = /* @__PURE__ */ new Set();
5629
- const extractBlocks = (nodes) => {
5630
- for (const item of nodes) {
5631
- if (!item || !(item instanceof HTMLElement)) continue;
5632
- const tag = item.tagName.toLowerCase();
5633
- const hasChildBlocks = Array.from(item.children).some((c) => {
5634
- const ct = c.tagName.toLowerCase();
5635
- return ["p", "div", "table", "h1", "h2", "h3", "h4", "h5", "h6", "section", "article", "ul", "ol"].includes(ct);
5636
- });
5637
- if (hasChildBlocks && !["table", "tr", "td", "th", "ul", "ol", "li"].includes(tag)) {
5638
- extractBlocks(Array.from(item.children));
5639
- } else {
5640
- const fp = extractMediaFingerprint(item);
5641
- if (fp) {
5642
- if (seenInContentBlocks.has(fp)) {
5643
- continue;
5644
- }
5645
- seenInContentBlocks.add(fp);
5646
- }
5647
- const hasMedia = item.querySelector("img, svg, canvas, table") !== null || ["img", "svg", "table"].includes(tag);
5648
- const textContent = (item.textContent || "").trim();
5649
- if (!hasMedia && textContent.length === 0) {
5650
- continue;
5651
- }
5652
- const svgs = item.querySelectorAll("svg, img");
5653
- svgs.forEach((s) => {
5654
- const el = s;
5655
- el.style.maxWidth = "100%";
5656
- el.style.maxHeight = "360px";
5657
- el.style.display = "block";
5658
- el.style.margin = "12px auto";
5659
- if (s.tagName.toLowerCase() === "svg") {
5660
- s.removeAttribute("width");
5661
- s.removeAttribute("height");
5662
- el.style.width = "100%";
5663
- el.style.maxHeight = "360px";
5664
- }
5665
- });
5666
- if (tag === "p" || tag === "div") {
5667
- item.style.display = "block";
5668
- item.style.marginBottom = "12px";
5669
- item.style.lineHeight = "1.6";
5670
- }
5671
- contentNodes.push(item);
5827
+ const elements = await doc.render();
5828
+ let unsupportedIndex = 1;
5829
+ const usedTables = /* @__PURE__ */ new Set();
5830
+ for (let i = 0; i < elements.length; i++) {
5831
+ const el = elements[i];
5832
+ const text = el.textContent || "";
5833
+ if (text.includes("[Unsupported image format]")) {
5834
+ if (extractedImages[unsupportedIndex]) {
5835
+ const img = document.createElement("img");
5836
+ img.src = extractedImages[unsupportedIndex].dataUrl;
5837
+ img.style.width = "100%";
5838
+ img.style.height = "auto";
5839
+ img.style.maxHeight = "430px";
5840
+ img.style.objectFit = "contain";
5841
+ img.style.display = "block";
5842
+ img.style.margin = "12px auto";
5843
+ el.innerHTML = "";
5844
+ el.appendChild(img);
5845
+ unsupportedIndex++;
5672
5846
  }
5673
5847
  }
5674
- };
5675
- extractBlocks(htmlElements);
5676
- tables.forEach((table) => {
5677
- const tableEl = renderRtfTableElement(table);
5678
- let inserted = false;
5679
- if (table.anchorBefore && table.anchorBefore.length > 10) {
5680
- const keyword = table.anchorBefore.slice(-35).trim();
5681
- for (let i = 0; i < contentNodes.length; i++) {
5682
- if (contentNodes[i].textContent?.includes(keyword)) {
5683
- contentNodes.splice(i + 1, 0, tableEl);
5684
- inserted = true;
5685
- break;
5848
+ if (tables.length > 0) {
5849
+ for (let t = 0; t < tables.length; t++) {
5850
+ if (usedTables.has(t)) continue;
5851
+ const tbl = tables[t];
5852
+ if (tbl.rows.length >= 2) {
5853
+ const sampleCell1 = tbl.rows[1]?.[1] || tbl.rows[0]?.[1] || "";
5854
+ const sampleCell2 = tbl.rows[2]?.[1] || tbl.rows[1]?.[0] || "";
5855
+ const match1 = sampleCell1 && text.includes(sampleCell1.slice(0, 15).trim());
5856
+ const match2 = sampleCell2 && text.includes(sampleCell2.slice(0, 15).trim());
5857
+ if (match1 && match2) {
5858
+ el.innerHTML = "";
5859
+ el.appendChild(renderRtfTableElement(tbl));
5860
+ usedTables.add(t);
5861
+ break;
5862
+ }
5686
5863
  }
5687
5864
  }
5688
5865
  }
5689
- if (!inserted && table.anchorAfter && table.anchorAfter.length > 10) {
5690
- const keyword = table.anchorAfter.slice(0, 35).trim();
5691
- for (let i = 0; i < contentNodes.length; i++) {
5692
- if (contentNodes[i].textContent?.includes(keyword)) {
5693
- contentNodes.splice(i, 0, tableEl);
5694
- inserted = true;
5695
- break;
5696
- }
5697
- }
5866
+ }
5867
+ elements.forEach((el) => {
5868
+ const svgs = el.querySelectorAll ? Array.from(el.querySelectorAll("svg")) : [];
5869
+ svgs.forEach((svg) => {
5870
+ svg.removeAttribute("width");
5871
+ svg.removeAttribute("height");
5872
+ svg.style.maxWidth = "100%";
5873
+ svg.style.maxHeight = "430px";
5874
+ svg.style.height = "auto";
5875
+ svg.style.display = "block";
5876
+ svg.style.margin = "12px auto";
5877
+ });
5878
+ const imgs = el.querySelectorAll ? Array.from(el.querySelectorAll("img")) : [];
5879
+ imgs.forEach((img) => {
5880
+ img.style.maxWidth = "100%";
5881
+ img.style.maxHeight = "430px";
5882
+ img.style.height = "auto";
5883
+ img.style.objectFit = "contain";
5884
+ img.style.display = "block";
5885
+ img.style.margin = "12px auto";
5886
+ });
5887
+ });
5888
+ const allImgs = Array.from(document.querySelectorAll("img")).concat(
5889
+ elements.flatMap((el) => Array.from(el.querySelectorAll ? el.querySelectorAll("img") : []))
5890
+ );
5891
+ await Promise.all(allImgs.map((img) => {
5892
+ if (img.complete && img.naturalHeight > 0) return Promise.resolve();
5893
+ if (img.decode) return img.decode().catch(() => {
5894
+ });
5895
+ return new Promise((r) => {
5896
+ img.onload = r;
5897
+ img.onerror = r;
5898
+ });
5899
+ }));
5900
+ elements.forEach((el) => {
5901
+ const text = el.textContent || "";
5902
+ if (text.includes("\uF0B7")) {
5903
+ const cleanText = text.replace(/^[\s\uf0b7\t]+/, "");
5904
+ el.style.display = "flex";
5905
+ el.style.alignItems = "flex-start";
5906
+ el.style.margin = "6px 0 6px 28px";
5907
+ el.style.fontSize = "11pt";
5908
+ el.style.lineHeight = "1.5";
5909
+ el.innerHTML = `<span style="margin-right:10px; user-select:none;">&#9633;</span><span>${cleanText}</span>`;
5698
5910
  }
5699
- if (!inserted) {
5700
- if (contentNodes.length > 2) {
5701
- contentNodes.splice(2, 0, tableEl);
5702
- } else {
5703
- contentNodes.push(tableEl);
5704
- }
5911
+ });
5912
+ elements.forEach((el) => {
5913
+ const text = (el.textContent || "").trim();
5914
+ const hasMedia = el.querySelector("img, svg, canvas, table") !== null || ["IMG", "SVG", "TABLE"].includes(el.tagName);
5915
+ if (isHeadingElement(el)) {
5916
+ el.style.marginTop = "20px";
5917
+ el.style.marginBottom = "10px";
5918
+ el.style.lineHeight = "1.25";
5919
+ } else if (text.length > 0 && !hasMedia) {
5920
+ el.style.marginBottom = "12px";
5921
+ el.style.lineHeight = "1.45";
5705
5922
  }
5706
5923
  });
5707
- const createRtfCard = (pageNum) => {
5924
+ const measureCard = document.createElement("div");
5925
+ measureCard.style.width = `${pageWidth}px`;
5926
+ measureCard.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
5927
+ measureCard.style.boxSizing = "border-box";
5928
+ measureCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5929
+ measureCard.style.lineHeight = "1.45";
5930
+ measureCard.style.visibility = "hidden";
5931
+ measureCard.style.position = "absolute";
5932
+ measureCard.style.top = "-99999px";
5933
+ document.body.appendChild(measureCard);
5934
+ const createPageCard = (num) => {
5708
5935
  const card = document.createElement("div");
5709
5936
  card.className = "fp-rtf-page-card";
5710
- card.setAttribute("data-page-number", String(pageNum));
5937
+ card.setAttribute("data-page-number", String(num));
5711
5938
  card.style.backgroundColor = "#ffffff";
5712
5939
  card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08), 0 1px 3px rgba(0,0,0,0.04)";
5713
5940
  card.style.borderRadius = "4px";
5714
- card.style.padding = "64px 56px";
5715
- card.style.width = "816px";
5716
- card.style.minHeight = "1056px";
5717
- card.style.maxHeight = "1056px";
5718
- card.style.overflow = "hidden";
5941
+ card.style.width = `${pageWidth}px`;
5942
+ card.style.height = `${pageHeight}px`;
5943
+ card.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
5719
5944
  card.style.boxSizing = "border-box";
5945
+ card.style.overflow = "hidden";
5720
5946
  card.style.marginBottom = "24px";
5721
- card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5722
- card.style.lineHeight = "1.6";
5723
5947
  card.style.color = "#1e293b";
5948
+ card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5949
+ card.style.lineHeight = "1.45";
5724
5950
  card.style.position = "relative";
5951
+ card.style.textAlign = "left";
5725
5952
  return card;
5726
5953
  };
5727
- wrapper.innerHTML = "";
5728
- const measureCard = createRtfCard(0);
5729
- measureCard.style.maxHeight = "none";
5730
- measureCard.style.height = "auto";
5731
- wrapper.appendChild(measureCard);
5732
- contentNodes.forEach((node) => measureCard.appendChild(node));
5733
- const childHeights = contentNodes.map((c) => {
5734
- const rect = c.getBoundingClientRect ? c.getBoundingClientRect() : null;
5735
- const rectH = rect ? rect.height : 0;
5736
- const offH = c.offsetHeight || 0;
5737
- let realH = Math.max(rectH, offH);
5738
- try {
5739
- const cs = window.getComputedStyle(c);
5740
- realH += (parseFloat(cs.marginTop) || 0) + (parseFloat(cs.marginBottom) || 0);
5741
- } catch {
5742
- }
5743
- const hasMedia = c.querySelector("img, svg") !== null || ["img", "svg"].includes(c.tagName.toLowerCase());
5744
- const hasTable = c.querySelector("table") !== null || c.tagName.toLowerCase() === "table";
5745
- if (hasMedia) {
5746
- realH = Math.max(realH, 300);
5747
- } else if (hasTable) {
5748
- realH = Math.max(realH, 240);
5749
- }
5750
- if (realH > 0) return realH;
5751
- const textLen = c.textContent?.trim().length || 0;
5752
- return Math.max(28, Math.ceil(textLen / 75) * 26 + 16);
5753
- });
5754
- wrapper.innerHTML = "";
5755
- let curCard = createRtfCard(1);
5756
- wrapper.appendChild(curCard);
5757
- pageElements = [curCard];
5758
- let curH = 0;
5759
- const maxH = 860;
5760
- for (let i = 0; i < contentNodes.length; i++) {
5761
- const child = contentNodes[i];
5762
- const chH = childHeights[i];
5763
- const isChildEmpty = (child.textContent || "").trim().length === 0 && !child.querySelector("table, img, svg, canvas");
5764
- if (curH === 0 && isChildEmpty) {
5954
+ const pages = [];
5955
+ let curCard = createPageCard(1);
5956
+ pages.push(curCard);
5957
+ let curHeight = 0;
5958
+ for (let i = 0; i < elements.length; i++) {
5959
+ const el = elements[i];
5960
+ if (!el || !(el instanceof HTMLElement)) continue;
5961
+ const text = (el.textContent || "").trim();
5962
+ const hasMedia = el.querySelector("img, svg, canvas, table") !== null || ["IMG", "SVG", "TABLE"].includes(el.tagName);
5963
+ const isEmptyPar = !hasMedia && text.length === 0;
5964
+ if (isEmptyPar) {
5965
+ const emptyH = 35;
5966
+ if (curHeight + emptyH > printableHeight) {
5967
+ if (curCard.childNodes.length > 0) {
5968
+ curCard = createPageCard(pages.length + 1);
5969
+ pages.push(curCard);
5970
+ curHeight = 0;
5971
+ }
5972
+ }
5973
+ const spacer = document.createElement("div");
5974
+ spacer.style.height = `${emptyH}px`;
5975
+ curCard.appendChild(spacer);
5976
+ curHeight += emptyH;
5765
5977
  continue;
5766
5978
  }
5767
- const isTable = child.querySelector("table") !== null || child.tagName.toLowerCase() === "table";
5768
- const shouldBreakBeforeTable = isTable && curH > 400 && curCard.childNodes.length > 0;
5769
- if ((curH + chH > maxH || shouldBreakBeforeTable) && curCard.childNodes.length > 0) {
5770
- curCard = createRtfCard(pageElements.length + 1);
5771
- wrapper.appendChild(curCard);
5772
- pageElements.push(curCard);
5773
- curH = 0;
5979
+ measureCard.innerHTML = "";
5980
+ const clone = el.cloneNode(true);
5981
+ measureCard.appendChild(clone);
5982
+ const compStyle = window.getComputedStyle(clone);
5983
+ const mt = parseFloat(compStyle.marginTop) || 0;
5984
+ const mb = parseFloat(compStyle.marginBottom) || 0;
5985
+ const elH = clone.offsetHeight + mt + mb;
5986
+ const isHeading = isHeadingElement(el);
5987
+ let nextContentH = 0;
5988
+ if (isHeading || hasMedia) {
5989
+ for (let j = i + 1; j < elements.length; j++) {
5990
+ const nextEl = elements[j];
5991
+ if (nextEl && (nextEl.textContent || "").trim().length > 0) {
5992
+ measureCard.innerHTML = "";
5993
+ const nClone = nextEl.cloneNode(true);
5994
+ measureCard.appendChild(nClone);
5995
+ const nStyle = window.getComputedStyle(nClone);
5996
+ nextContentH = nClone.offsetHeight + (parseFloat(nStyle.marginTop) || 0) + (parseFloat(nStyle.marginBottom) || 0);
5997
+ break;
5998
+ }
5999
+ }
5774
6000
  }
5775
- curCard.appendChild(child);
5776
- curH += chH;
5777
- }
5778
- pageElements = pageElements.filter((card) => {
6001
+ const remainingSpace = printableHeight - curHeight;
6002
+ const isLargeMedia = hasMedia && elH > 300;
6003
+ const keepWithNextOverflow = isHeading && nextContentH > 0 && elH + nextContentH + 20 > remainingSpace;
6004
+ const largeMediaOverflow = isLargeMedia && curHeight > 0 && elH + 80 > remainingSpace;
6005
+ const shouldBreak = (curHeight + elH > printableHeight || keepWithNextOverflow || largeMediaOverflow) && curCard.childNodes.length > 0;
6006
+ if (shouldBreak) {
6007
+ curCard = createPageCard(pages.length + 1);
6008
+ pages.push(curCard);
6009
+ curHeight = 0;
6010
+ }
6011
+ curCard.appendChild(el);
6012
+ curHeight += elH;
6013
+ }
6014
+ measureCard.remove();
6015
+ pageElements = pages.filter((card) => {
5779
6016
  const hasText = (card.textContent || "").trim().length > 0;
5780
- const hasMedia = card.querySelector("table, img, svg, canvas") !== null;
5781
- return hasText || hasMedia;
6017
+ const hasCardMedia = card.querySelector("table, img, svg, canvas") !== null;
6018
+ return hasText || hasCardMedia;
5782
6019
  });
5783
6020
  if (pageElements.length === 0) {
5784
6021
  pageElements = [curCard];
5785
6022
  }
6023
+ wrapper.innerHTML = "";
6024
+ pageElements.forEach((card, idx) => {
6025
+ card.setAttribute("data-page-number", String(idx + 1));
6026
+ card.style.display = idx === 0 ? "block" : "none";
6027
+ wrapper.appendChild(card);
6028
+ });
5786
6029
  } catch (err) {
5787
6030
  console.warn("[RtfPlugin] RTF render error, fallback text:", err);
5788
- const text = new TextDecoder("latin1").decode(ctx.buffer);
5789
- const tables = parseRtfTables(text);
6031
+ const text = rawRtf;
5790
6032
  const rawPages = text.split(/\\page\b/).map((segment) => {
5791
6033
  return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
5792
- }).filter((p) => p.length > 0);
6034
+ }).filter((p2) => p2.length > 0);
5793
6035
  const pages = rawPages.length > 0 ? rawPages : [text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim()];
5794
6036
  for (let i = 0; i < pages.length; i++) {
5795
6037
  const pageCard = document.createElement("div");
@@ -5797,9 +6039,9 @@ var RtfPlugin = class {
5797
6039
  pageCard.style.backgroundColor = "#ffffff";
5798
6040
  pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
5799
6041
  pageCard.style.borderRadius = "4px";
5800
- pageCard.style.padding = "64px 56px";
5801
- pageCard.style.width = "816px";
5802
- pageCard.style.minHeight = "1056px";
6042
+ pageCard.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
6043
+ pageCard.style.width = `${pageWidth}px`;
6044
+ pageCard.style.minHeight = `${pageHeight}px`;
5803
6045
  pageCard.style.boxSizing = "border-box";
5804
6046
  pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5805
6047
  pageCard.style.fontSize = "12pt";
@@ -5819,11 +6061,9 @@ var RtfPlugin = class {
5819
6061
  let currentPage = 1;
5820
6062
  const showPage = (pageNum) => {
5821
6063
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
5822
- if (totalPages > 1) {
5823
- pageElements.forEach((el, idx) => {
5824
- el.style.display = idx + 1 === currentPage ? "block" : "none";
5825
- });
5826
- }
6064
+ pageElements.forEach((el, idx) => {
6065
+ el.style.display = idx + 1 === currentPage ? "block" : "none";
6066
+ });
5827
6067
  ctx.container.scrollTop = 0;
5828
6068
  ctx.emit("page-change", { page: currentPage, total: totalPages });
5829
6069
  };
@@ -5890,6 +6130,15 @@ var RtfPlugin = class {
5890
6130
  rotation = 0;
5891
6131
  applyTransform();
5892
6132
  },
6133
+ resetZoom: () => {
6134
+ isUserZoomed = false;
6135
+ fitMode = "width";
6136
+ scale = calculateFitScale("width");
6137
+ rotation = 0;
6138
+ ctx.container.scrollTop = 0;
6139
+ ctx.container.scrollLeft = 0;
6140
+ applyTransform();
6141
+ },
5893
6142
  rotateCW: () => {
5894
6143
  rotation = (rotation + 90) % 360;
5895
6144
  applyTransform();
@@ -5957,6 +6206,14 @@ var HtmlPreviewPlugin = class {
5957
6206
  group: "zoom",
5958
6207
  execute: () => instance.fitToPage?.()
5959
6208
  },
6209
+ {
6210
+ id: "reset-zoom",
6211
+ icon: "reset-zoom",
6212
+ label: "Reset Zoom",
6213
+ type: "button",
6214
+ group: "zoom",
6215
+ execute: () => instance.resetZoom?.()
6216
+ },
5960
6217
  {
5961
6218
  id: "copy",
5962
6219
  icon: "copy",
@@ -6029,6 +6286,12 @@ var HtmlPreviewPlugin = class {
6029
6286
  scale = 1;
6030
6287
  iframe.style.transform = "scale(1)";
6031
6288
  },
6289
+ resetZoom: () => {
6290
+ scale = 1;
6291
+ iframe.style.transform = "scale(1)";
6292
+ ctx.container.scrollTop = 0;
6293
+ ctx.container.scrollLeft = 0;
6294
+ },
6032
6295
  copy: () => {
6033
6296
  navigator.clipboard.writeText(rawHtml);
6034
6297
  },
@@ -6129,6 +6392,14 @@ var OpenDocumentPlugin = class {
6129
6392
  group: "zoom",
6130
6393
  execute: () => instance.fitToPage?.()
6131
6394
  },
6395
+ {
6396
+ id: "reset-zoom",
6397
+ icon: "reset-zoom",
6398
+ label: "Reset Zoom",
6399
+ type: "button",
6400
+ group: "zoom",
6401
+ execute: () => instance.resetZoom?.()
6402
+ },
6132
6403
  {
6133
6404
  id: "rotate-cw",
6134
6405
  icon: "rotate-cw",
@@ -6396,6 +6667,15 @@ var OpenDocumentPlugin = class {
6396
6667
  rotation = 0;
6397
6668
  applyTransform();
6398
6669
  },
6670
+ resetZoom: () => {
6671
+ isUserZoomed = false;
6672
+ fitMode = "width";
6673
+ scale = calculateFitScale("width");
6674
+ rotation = 0;
6675
+ container.scrollTop = 0;
6676
+ container.scrollLeft = 0;
6677
+ applyTransform();
6678
+ },
6399
6679
  rotateCW: () => {
6400
6680
  rotation = (rotation + 90) % 360;
6401
6681
  applyTransform();
@@ -6739,6 +7019,14 @@ var DocPlugin = class {
6739
7019
  group: "zoom",
6740
7020
  execute: () => instance.fitToPage?.()
6741
7021
  },
7022
+ {
7023
+ id: "reset-zoom",
7024
+ icon: "reset-zoom",
7025
+ label: "Reset Zoom",
7026
+ type: "button",
7027
+ group: "zoom",
7028
+ execute: () => instance.resetZoom?.()
7029
+ },
6742
7030
  {
6743
7031
  id: "rotate-cw",
6744
7032
  icon: "rotate-cw",
@@ -6945,6 +7233,15 @@ var DocPlugin = class {
6945
7233
  rotation = 0;
6946
7234
  applyTransform();
6947
7235
  },
7236
+ resetZoom: () => {
7237
+ isUserZoomed = false;
7238
+ fitMode = "width";
7239
+ scale = calculateFitScale("width");
7240
+ rotation = 0;
7241
+ ctx.container.scrollTop = 0;
7242
+ ctx.container.scrollLeft = 0;
7243
+ applyTransform();
7244
+ },
6948
7245
  rotateCW: () => {
6949
7246
  rotation = (rotation + 90) % 360;
6950
7247
  applyTransform();
@@ -7425,6 +7722,14 @@ var PptPlugin = class {
7425
7722
  group: "zoom",
7426
7723
  execute: () => instance.fitToPage?.()
7427
7724
  },
7725
+ {
7726
+ id: "reset-zoom",
7727
+ icon: "reset-zoom",
7728
+ label: "Reset Zoom",
7729
+ type: "button",
7730
+ group: "zoom",
7731
+ execute: () => instance.resetZoom?.()
7732
+ },
7428
7733
  {
7429
7734
  id: "rotate-cw",
7430
7735
  icon: "rotate-cw",
@@ -7613,6 +7918,13 @@ var PptPlugin = class {
7613
7918
  rotation = 0;
7614
7919
  applyTransform();
7615
7920
  },
7921
+ resetZoom: () => {
7922
+ scale = calculateFitScale();
7923
+ rotation = 0;
7924
+ container.scrollTop = 0;
7925
+ container.scrollLeft = 0;
7926
+ applyTransform();
7927
+ },
7616
7928
  rotateCW: () => {
7617
7929
  rotation = (rotation + 90) % 360;
7618
7930
  applyTransform();