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