@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/angular.cjs CHANGED
@@ -576,6 +576,7 @@ var ICON_COPY = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" str
576
576
  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>`;
577
577
  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>`;
578
578
  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>`;
579
+ 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>`;
579
580
  var ICON_MAP = {
580
581
  "zoom-in": ICON_ZOOM_IN,
581
582
  "zoom-out": ICON_ZOOM_OUT,
@@ -605,7 +606,10 @@ var ICON_MAP = {
605
606
  "open-window": ICON_EXTERNAL_WINDOW,
606
607
  "external-window": ICON_EXTERNAL_WINDOW,
607
608
  "openWindow": ICON_EXTERNAL_WINDOW,
608
- "openSeparateWindow": ICON_EXTERNAL_WINDOW
609
+ "openSeparateWindow": ICON_EXTERNAL_WINDOW,
610
+ "reset-zoom": ICON_RESET_ZOOM,
611
+ "zoom-reset": ICON_RESET_ZOOM,
612
+ "resetZoom": ICON_RESET_ZOOM
609
613
  };
610
614
  var ToolbarController = class {
611
615
  el;
@@ -638,6 +642,10 @@ var ToolbarController = class {
638
642
  this.config.fitToPage = false;
639
643
  this.config.fitWidth = false;
640
644
  }
645
+ if (actionId === "reset-zoom" || actionId === "zoom-reset" || actionId === "resetZoom") {
646
+ this.config.resetZoom = false;
647
+ this.config.zoomReset = false;
648
+ }
641
649
  if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = false;
642
650
  if (actionId === "fullscreen") this.config.fullscreen = false;
643
651
  if (actionId === "download") this.config.download = false;
@@ -662,6 +670,10 @@ var ToolbarController = class {
662
670
  this.config.fitToPage = true;
663
671
  this.config.fitWidth = true;
664
672
  }
673
+ if (actionId === "reset-zoom" || actionId === "zoom-reset" || actionId === "resetZoom") {
674
+ this.config.resetZoom = true;
675
+ this.config.zoomReset = true;
676
+ }
665
677
  if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = true;
666
678
  if (actionId === "fullscreen") this.config.fullscreen = true;
667
679
  if (actionId === "download") this.config.download = true;
@@ -681,6 +693,7 @@ var ToolbarController = class {
681
693
  if (actionId === "zoomIn") return "zoom-in";
682
694
  if (actionId === "zoomOut") return "zoom-out";
683
695
  if (actionId === "fitPage" || actionId === "fitToPage" || actionId === "fitWidth") return "fit-page";
696
+ if (actionId === "resetZoom" || actionId === "zoomReset") return "reset-zoom";
684
697
  if (actionId === "rotateCW") return "rotate-cw";
685
698
  if (actionId === "rotateCCW") return "rotate-ccw";
686
699
  if (actionId === "openWindow" || actionId === "openSeparateWindow") return "open-window";
@@ -723,6 +736,9 @@ var ToolbarController = class {
723
736
  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)) {
724
737
  return false;
725
738
  }
739
+ if ((id === "reset-zoom" || id === "zoom-reset") && (c.resetZoom === false || c.zoomReset === false || c["reset-zoom"] === false || c["zoom-reset"] === false)) {
740
+ return false;
741
+ }
726
742
  if ((id === "rotate-cw" || id === "rotate-ccw" || id === "rotate") && (c.rotate === false || c.rotateCW === false || c.rotateCCW === false || c["rotate-cw"] === false)) {
727
743
  return false;
728
744
  }
@@ -1169,6 +1185,9 @@ var FilePreviewViewer = class _FilePreviewViewer {
1169
1185
  this.activeInstance = instance;
1170
1186
  instance.openInSeparateWindow = () => this.openInSeparateWindow();
1171
1187
  instance.toggleThumbnails = () => this.toggleThumbnails();
1188
+ if (!instance.resetZoom && instance.fitToPage) {
1189
+ instance.resetZoom = () => instance.fitToPage?.();
1190
+ }
1172
1191
  this.hideLoading();
1173
1192
  this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
1174
1193
  const isToolbarVisible = options.showToolbar !== false && options.toolbar !== false;
@@ -1452,6 +1471,16 @@ var FilePreviewViewer = class _FilePreviewViewer {
1452
1471
  fitToPage() {
1453
1472
  this.activeInstance?.fitToPage?.();
1454
1473
  }
1474
+ /**
1475
+ * Reset zoom level to initial/default fit state.
1476
+ */
1477
+ resetZoom() {
1478
+ if (this.activeInstance?.resetZoom) {
1479
+ this.activeInstance.resetZoom();
1480
+ } else if (this.activeInstance?.fitToPage) {
1481
+ this.activeInstance.fitToPage();
1482
+ }
1483
+ }
1455
1484
  /**
1456
1485
  * Zoom in.
1457
1486
  */
@@ -2073,6 +2102,14 @@ var PdfPlugin = class {
2073
2102
  group: "zoom",
2074
2103
  execute: () => instance.fitToPage?.()
2075
2104
  },
2105
+ {
2106
+ id: "reset-zoom",
2107
+ icon: "reset-zoom",
2108
+ label: "Reset Zoom",
2109
+ type: "button",
2110
+ group: "zoom",
2111
+ execute: () => instance.resetZoom?.()
2112
+ },
2076
2113
  {
2077
2114
  id: "fit-width",
2078
2115
  icon: "fit-width",
@@ -2335,6 +2372,14 @@ var PdfPlugin = class {
2335
2372
  zoomScale = 1;
2336
2373
  renderPage(currentPage);
2337
2374
  },
2375
+ resetZoom: () => {
2376
+ fitMode = "page";
2377
+ zoomScale = 1;
2378
+ rotation = 0;
2379
+ container.scrollTop = 0;
2380
+ container.scrollLeft = 0;
2381
+ renderPage(currentPage);
2382
+ },
2338
2383
  fitToWidth: () => {
2339
2384
  fitMode = "width";
2340
2385
  zoomScale = 1;
@@ -2502,6 +2547,16 @@ var MediaPlugin = class {
2502
2547
  instance.fitToPage?.();
2503
2548
  }
2504
2549
  },
2550
+ {
2551
+ id: "reset-zoom",
2552
+ icon: "reset-zoom",
2553
+ label: "Reset Zoom",
2554
+ type: "button",
2555
+ group: "zoom",
2556
+ execute: () => {
2557
+ instance.resetZoom?.();
2558
+ }
2559
+ },
2505
2560
  {
2506
2561
  id: "rotate-cw",
2507
2562
  icon: "rotate-cw",
@@ -2675,6 +2730,13 @@ var MediaPlugin = class {
2675
2730
  rotation = 0;
2676
2731
  applyTransform();
2677
2732
  } : void 0,
2733
+ resetZoom: isImage ? () => {
2734
+ currentZoom = 1;
2735
+ rotation = 0;
2736
+ ctx.container.scrollTop = 0;
2737
+ ctx.container.scrollLeft = 0;
2738
+ applyTransform();
2739
+ } : void 0,
2678
2740
  rotateCW: isImage || isVideo ? () => {
2679
2741
  rotation = (rotation + 90) % 360;
2680
2742
  applyTransform();
@@ -2791,6 +2853,14 @@ var DocxPlugin = class {
2791
2853
  group: "zoom",
2792
2854
  execute: () => instance.fitToPage?.()
2793
2855
  },
2856
+ {
2857
+ id: "reset-zoom",
2858
+ icon: "reset-zoom",
2859
+ label: "Reset Zoom",
2860
+ type: "button",
2861
+ group: "zoom",
2862
+ execute: () => instance.resetZoom?.()
2863
+ },
2794
2864
  {
2795
2865
  id: "rotate-cw",
2796
2866
  icon: "rotate-cw",
@@ -3107,6 +3177,14 @@ var DocxPlugin = class {
3107
3177
  rotation = 0;
3108
3178
  applyTransform();
3109
3179
  },
3180
+ resetZoom: () => {
3181
+ isUserZoomed = false;
3182
+ scale = calculateFitScale("page");
3183
+ rotation = 0;
3184
+ ctx.container.scrollTop = 0;
3185
+ ctx.container.scrollLeft = 0;
3186
+ applyTransform();
3187
+ },
3110
3188
  rotateCW: () => {
3111
3189
  rotation = (rotation + 90) % 360;
3112
3190
  applyTransform();
@@ -3556,6 +3634,16 @@ var ExcelPlugin = class {
3556
3634
  instance.zoomIn?.();
3557
3635
  }
3558
3636
  },
3637
+ {
3638
+ id: "reset-zoom",
3639
+ icon: "reset-zoom",
3640
+ label: "Reset Zoom",
3641
+ type: "button",
3642
+ group: "zoom",
3643
+ execute: () => {
3644
+ instance.resetZoom?.();
3645
+ }
3646
+ },
3559
3647
  {
3560
3648
  id: "download",
3561
3649
  icon: "download",
@@ -3743,6 +3831,12 @@ var ExcelPlugin = class {
3743
3831
  scale = calculateFitScale();
3744
3832
  applyTransform();
3745
3833
  },
3834
+ resetZoom: () => {
3835
+ scale = calculateFitScale();
3836
+ contentArea.scrollTop = 0;
3837
+ contentArea.scrollLeft = 0;
3838
+ applyTransform();
3839
+ },
3746
3840
  rotateCW: () => {
3747
3841
  },
3748
3842
  rotateCCW: () => {
@@ -3873,6 +3967,16 @@ var CsvPlugin = class {
3873
3967
  instance.zoomIn?.();
3874
3968
  }
3875
3969
  },
3970
+ {
3971
+ id: "reset-zoom",
3972
+ icon: "reset-zoom",
3973
+ label: "Reset Zoom",
3974
+ type: "button",
3975
+ group: "zoom",
3976
+ execute: () => {
3977
+ instance.resetZoom?.();
3978
+ }
3979
+ },
3876
3980
  {
3877
3981
  id: "download",
3878
3982
  icon: "download",
@@ -4062,6 +4166,12 @@ var CsvPlugin = class {
4062
4166
  scale = calculateFitScale();
4063
4167
  applyScale();
4064
4168
  },
4169
+ resetZoom: () => {
4170
+ scale = calculateFitScale();
4171
+ container.scrollTop = 0;
4172
+ container.scrollLeft = 0;
4173
+ applyScale();
4174
+ },
4065
4175
  rotateCW: () => {
4066
4176
  },
4067
4177
  rotateCCW: () => {
@@ -4177,6 +4287,16 @@ var CodePlugin = class {
4177
4287
  instance.zoomIn?.();
4178
4288
  }
4179
4289
  },
4290
+ {
4291
+ id: "reset-zoom",
4292
+ icon: "reset-zoom",
4293
+ label: "Reset Zoom",
4294
+ type: "button",
4295
+ group: "zoom",
4296
+ execute: () => {
4297
+ instance.resetZoom?.();
4298
+ }
4299
+ },
4180
4300
  {
4181
4301
  id: "copy",
4182
4302
  icon: "copy",
@@ -4456,6 +4576,15 @@ var CodePlugin = class {
4456
4576
  zoomLevel = isTxt ? calculateTxtFit() : 1;
4457
4577
  updateTransform();
4458
4578
  },
4579
+ resetZoom: () => {
4580
+ isUserZoomed = false;
4581
+ fontSize = 13;
4582
+ rotation = 0;
4583
+ zoomLevel = isTxt ? calculateTxtFit() : 1;
4584
+ container.scrollTop = 0;
4585
+ container.scrollLeft = 0;
4586
+ updateTransform();
4587
+ },
4459
4588
  rotateCW: () => {
4460
4589
  rotation = (rotation + 90) % 360;
4461
4590
  updateTransform();
@@ -4518,11 +4647,19 @@ var ArchivePlugin = class {
4518
4647
  {
4519
4648
  id: "fit-page",
4520
4649
  icon: "fit-page",
4521
- label: "Reset Zoom",
4650
+ label: "Fit to Page",
4522
4651
  type: "button",
4523
4652
  group: "zoom",
4524
4653
  execute: () => instance.fitToPage?.()
4525
4654
  },
4655
+ {
4656
+ id: "reset-zoom",
4657
+ icon: "reset-zoom",
4658
+ label: "Reset Zoom",
4659
+ type: "button",
4660
+ group: "zoom",
4661
+ execute: () => instance.resetZoom?.()
4662
+ },
4526
4663
  {
4527
4664
  id: "download",
4528
4665
  icon: "download",
@@ -4677,7 +4814,13 @@ var ArchivePlugin = class {
4677
4814
  },
4678
4815
  fitToPage: () => {
4679
4816
  scale = 1;
4680
- wrapper.style.transform = `scale(1)`;
4817
+ wrapper.style.transform = "scale(1)";
4818
+ },
4819
+ resetZoom: () => {
4820
+ scale = 1;
4821
+ wrapper.style.transform = "scale(1)";
4822
+ ctx.container.scrollTop = 0;
4823
+ ctx.container.scrollLeft = 0;
4681
4824
  },
4682
4825
  download: () => {
4683
4826
  downloadFile(ctx.buffer, ctx.metadata.name || "archive.zip", "application/zip");
@@ -4729,6 +4872,14 @@ var MarkdownPlugin = class {
4729
4872
  group: "zoom",
4730
4873
  execute: () => instance.fitToPage?.()
4731
4874
  },
4875
+ {
4876
+ id: "reset-zoom",
4877
+ icon: "reset-zoom",
4878
+ label: "Reset Zoom",
4879
+ type: "button",
4880
+ group: "zoom",
4881
+ execute: () => instance.resetZoom?.()
4882
+ },
4732
4883
  {
4733
4884
  id: "copy",
4734
4885
  icon: "copy",
@@ -4882,6 +5033,12 @@ var MarkdownPlugin = class {
4882
5033
  fontSize = 15;
4883
5034
  wrapper.style.fontSize = "15px";
4884
5035
  },
5036
+ resetZoom: () => {
5037
+ fontSize = 15;
5038
+ wrapper.style.fontSize = "15px";
5039
+ ctx.container.scrollTop = 0;
5040
+ ctx.container.scrollLeft = 0;
5041
+ },
4885
5042
  download: () => {
4886
5043
  downloadFile(ctx.buffer, ctx.metadata.name || "document.md", "text/markdown");
4887
5044
  },
@@ -4975,6 +5132,14 @@ var PptxPlugin = class {
4975
5132
  group: "zoom",
4976
5133
  execute: () => instance.fitToPage?.()
4977
5134
  },
5135
+ {
5136
+ id: "reset-zoom",
5137
+ icon: "reset-zoom",
5138
+ label: "Reset Zoom",
5139
+ type: "button",
5140
+ group: "zoom",
5141
+ execute: () => instance.resetZoom?.()
5142
+ },
4978
5143
  {
4979
5144
  id: "rotate-cw",
4980
5145
  icon: "rotate-cw",
@@ -5094,6 +5259,13 @@ var PptxPlugin = class {
5094
5259
  rotation = 0;
5095
5260
  applyTransform();
5096
5261
  },
5262
+ resetZoom: () => {
5263
+ scale = calculateFitScale();
5264
+ rotation = 0;
5265
+ wrapper.scrollTop = 0;
5266
+ wrapper.scrollLeft = 0;
5267
+ applyTransform();
5268
+ },
5097
5269
  rotateCW: () => {
5098
5270
  rotation = (rotation + 90) % 360;
5099
5271
  applyTransform();
@@ -5169,6 +5341,14 @@ var ThreeDPlugin = class {
5169
5341
  group: "zoom",
5170
5342
  execute: () => instance.fitToPage?.()
5171
5343
  },
5344
+ {
5345
+ id: "reset-zoom",
5346
+ icon: "reset-zoom",
5347
+ label: "Reset Zoom",
5348
+ type: "button",
5349
+ group: "zoom",
5350
+ execute: () => instance.resetZoom?.()
5351
+ },
5172
5352
  {
5173
5353
  id: "rotate-cw",
5174
5354
  icon: "rotate-cw",
@@ -5305,6 +5485,7 @@ var ThreeDPlugin = class {
5305
5485
  controls.update();
5306
5486
  },
5307
5487
  fitToPage: fitCamera,
5488
+ resetZoom: fitCamera,
5308
5489
  rotateCW: () => {
5309
5490
  isWireframe = !isWireframe;
5310
5491
  materials.forEach((m) => {
@@ -5327,7 +5508,7 @@ function cleanRtfText(raw) {
5327
5508
  return String.fromCharCode(num);
5328
5509
  }).replace(/\\'([0-9a-fA-F]{2})/g, (_, hex) => {
5329
5510
  return String.fromCharCode(parseInt(hex, 16));
5330
- }).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();
5511
+ }).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();
5331
5512
  }
5332
5513
  function parseRtfTables(rtfText) {
5333
5514
  const rowSegments = rtfText.split(/\\row\b/);
@@ -5367,17 +5548,12 @@ function parseRtfTables(rtfText) {
5367
5548
  }
5368
5549
  const isNewTable = !currentTable || segmentStart - currentTable.lastEnd > 2500;
5369
5550
  if (isNewTable) {
5370
- const prevTextSlice = rtfText.slice(Math.max(0, segmentStart - 4e3), segmentStart);
5371
- const cleanPrev = cleanRtfText(prevTextSlice);
5372
- const anchorBefore = cleanPrev.slice(-80).trim();
5373
5551
  currentTable = {
5374
5552
  id: `RTF_TABLE_${rawTables.length}`,
5375
5553
  startPos: segmentStart,
5376
5554
  lastEnd: segmentEnd,
5377
5555
  rows: [],
5378
- columnWidths: cellWidths,
5379
- anchorBefore,
5380
- anchorAfter: ""
5556
+ columnWidths: cellWidths
5381
5557
  };
5382
5558
  rawTables.push(currentTable);
5383
5559
  }
@@ -5391,20 +5567,13 @@ function parseRtfTables(rtfText) {
5391
5567
  }
5392
5568
  charOffset += segment.length + 4;
5393
5569
  }
5394
- rawTables.forEach((tbl) => {
5395
- const afterSlice = rtfText.slice(tbl.lastEnd, Math.min(rtfText.length, tbl.lastEnd + 2e3));
5396
- const cleanAfter = cleanRtfText(afterSlice);
5397
- tbl.anchorAfter = cleanAfter.slice(0, 80).trim();
5398
- });
5399
5570
  return rawTables.map((tbl) => {
5400
5571
  const totalW = (tbl.columnWidths || []).reduce((a, b) => a + b, 0);
5401
5572
  const colPercents = totalW > 0 ? tbl.columnWidths.map((w) => Math.round(w / totalW * 100)) : [];
5402
5573
  return {
5403
5574
  id: tbl.id,
5404
5575
  rows: tbl.rows.map((r) => r.cells),
5405
- colPercents,
5406
- anchorBefore: tbl.anchorBefore,
5407
- anchorAfter: tbl.anchorAfter
5576
+ colPercents
5408
5577
  };
5409
5578
  });
5410
5579
  }
@@ -5417,8 +5586,6 @@ function renderRtfTableElement(table) {
5417
5586
  tableEl.style.fontSize = "10pt";
5418
5587
  tableEl.style.lineHeight = "1.5";
5419
5588
  tableEl.style.border = "1px solid #cbd5e1";
5420
- tableEl.style.borderRadius = "4px";
5421
- tableEl.style.boxSizing = "border-box";
5422
5589
  tableEl.style.backgroundColor = "#ffffff";
5423
5590
  const thead = document.createElement("thead");
5424
5591
  const tbody = document.createElement("tbody");
@@ -5427,27 +5594,17 @@ function renderRtfTableElement(table) {
5427
5594
  const isHeader = rIdx === 0;
5428
5595
  if (isHeader) {
5429
5596
  tr.style.backgroundColor = "#f8fafc";
5430
- tr.style.borderBottom = "2px solid #cbd5e1";
5431
- } else {
5432
- tr.style.borderBottom = "1px solid #e2e8f0";
5433
- if (rIdx % 2 === 0) {
5434
- tr.style.backgroundColor = "#fcfdfe";
5435
- }
5436
5597
  }
5437
5598
  rowCells.forEach((cellText, cIdx) => {
5438
5599
  const cellEl = document.createElement(isHeader ? "th" : "td");
5439
5600
  cellEl.style.padding = "8px 12px";
5440
5601
  cellEl.style.border = "1px solid #cbd5e1";
5441
5602
  cellEl.style.verticalAlign = "top";
5442
- cellEl.style.color = isHeader ? "#0f172a" : "#1e293b";
5443
- cellEl.style.fontWeight = isHeader ? "600" : "normal";
5444
5603
  if (table.colPercents && table.colPercents[cIdx]) {
5445
5604
  cellEl.style.width = `${table.colPercents[cIdx]}%`;
5446
5605
  }
5447
5606
  if (/^\d+$/.test(cellText.trim()) || cellText.trim() === "#") {
5448
5607
  cellEl.style.textAlign = "center";
5449
- } else {
5450
- cellEl.style.textAlign = "left";
5451
5608
  }
5452
5609
  cellEl.textContent = cellText;
5453
5610
  tr.appendChild(cellEl);
@@ -5462,23 +5619,19 @@ function renderRtfTableElement(table) {
5462
5619
  tableEl.appendChild(tbody);
5463
5620
  return tableEl;
5464
5621
  }
5465
- function extractMediaFingerprint(el) {
5466
- const img = el.tagName.toLowerCase() === "img" ? el : el.querySelector("img");
5467
- if (img && img.src) {
5468
- const s = img.src;
5469
- return s.length > 300 ? `img_${s.slice(0, 80)}_${s.length}_${s.slice(-80)}` : `img_${s}`;
5470
- }
5471
- const innerImg = el.querySelector("image");
5472
- if (innerImg) {
5473
- const h = innerImg.getAttribute("xlink:href") || innerImg.getAttribute("href") || "";
5474
- if (h) return h.length > 300 ? `svgimg_${h.slice(0, 80)}_${h.length}_${h.slice(-80)}` : `svgimg_${h}`;
5475
- }
5476
- const svg = el.tagName.toLowerCase() === "svg" ? el : el.querySelector("svg");
5477
- if (svg) {
5478
- const vb = svg.getAttribute("viewBox") || "";
5479
- return `svg_${vb}_${svg.innerHTML.length}`;
5480
- }
5481
- return null;
5622
+ function isHeadingElement(el) {
5623
+ if (["H1", "H2", "H3", "H4"].includes(el.tagName)) return true;
5624
+ const spans = el.querySelectorAll ? Array.from(el.querySelectorAll("span, b, strong, div")) : [];
5625
+ for (const s of spans) {
5626
+ const hEl = s;
5627
+ const fs = parseFloat(hEl.style.fontSize) || 0;
5628
+ const isBold = hEl.style.fontWeight === "bold" || parseInt(hEl.style.fontWeight, 10) >= 600 || ["B", "STRONG"].includes(hEl.tagName);
5629
+ if (isBold && fs >= 14) return true;
5630
+ }
5631
+ const elFs = parseFloat(el.style.fontSize) || 0;
5632
+ const elBold = el.style.fontWeight === "bold" || parseInt(el.style.fontWeight, 10) >= 600;
5633
+ if (elBold && elFs >= 14) return true;
5634
+ return false;
5482
5635
  }
5483
5636
  var RtfPlugin = class {
5484
5637
  id = "rtf";
@@ -5547,6 +5700,14 @@ var RtfPlugin = class {
5547
5700
  group: "zoom",
5548
5701
  execute: () => instance.fitToPage?.()
5549
5702
  },
5703
+ {
5704
+ id: "reset-zoom",
5705
+ icon: "reset-zoom",
5706
+ label: "Reset Zoom",
5707
+ type: "button",
5708
+ group: "zoom",
5709
+ execute: () => instance.resetZoom?.()
5710
+ },
5550
5711
  {
5551
5712
  id: "rotate-cw",
5552
5713
  icon: "rotate-cw",
@@ -5591,10 +5752,66 @@ var RtfPlugin = class {
5591
5752
  return actions;
5592
5753
  }
5593
5754
  async render(ctx) {
5755
+ const rawRtf = new TextDecoder("latin1").decode(ctx.buffer);
5756
+ const paperwMatch = rawRtf.match(/\\paperw(\d+)/);
5757
+ const paperhMatch = rawRtf.match(/\\paperh(\d+)/);
5758
+ const marglMatch = rawRtf.match(/\\margl(\d+)/);
5759
+ const margrMatch = rawRtf.match(/\\margr(\d+)/);
5760
+ const margtMatch = rawRtf.match(/\\margt(\d+)/);
5761
+ const margbMatch = rawRtf.match(/\\margb(\d+)/);
5762
+ const paperwTwips = paperwMatch ? parseInt(paperwMatch[1], 10) : 11906;
5763
+ const paperhTwips = paperhMatch ? parseInt(paperhMatch[1], 10) : 16838;
5764
+ const marglTwips = marglMatch ? parseInt(marglMatch[1], 10) : 1134;
5765
+ const margrTwips = margrMatch ? parseInt(margrMatch[1], 10) : 1134;
5766
+ const margtTwips = margtMatch ? parseInt(margtMatch[1], 10) : 1134;
5767
+ const margbTwips = margbMatch ? parseInt(margbMatch[1], 10) : 1134;
5768
+ const pageWidth = Math.round(paperwTwips / 15);
5769
+ const pageHeight = Math.round(paperhTwips / 15);
5770
+ const padLeft = Math.round(marglTwips / 15);
5771
+ const padRight = Math.round(margrTwips / 15);
5772
+ const padTop = Math.round(margtTwips / 15);
5773
+ const padBottom = Math.round(margbTwips / 15);
5774
+ const printableHeight = pageHeight - padTop - padBottom;
5775
+ const extractedImages = [];
5776
+ let p = 0;
5777
+ while ((p = rawRtf.indexOf("\\pict", p)) !== -1) {
5778
+ const startP = p;
5779
+ p += 5;
5780
+ const header = rawRtf.substring(startP, startP + 600);
5781
+ let mime = "";
5782
+ let magic = "";
5783
+ if (header.includes("\\pngblip")) {
5784
+ mime = "image/png";
5785
+ magic = "89504e47";
5786
+ } else if (header.includes("\\jpegblip")) {
5787
+ mime = "image/jpeg";
5788
+ magic = "ffd8ff";
5789
+ }
5790
+ if (!mime || !magic) continue;
5791
+ const magicPos = rawRtf.indexOf(magic, startP);
5792
+ if (magicPos === -1 || magicPos - startP > 3e3) continue;
5793
+ let endP = magicPos;
5794
+ while (endP < rawRtf.length && /[0-9a-fA-F\r\n\s]/.test(rawRtf[endP])) {
5795
+ endP++;
5796
+ }
5797
+ const cleanHex = rawRtf.substring(magicPos, endP).replace(/[\r\n\s]/g, "");
5798
+ if (cleanHex.length < 100) continue;
5799
+ const hexLen = cleanHex.length / 2;
5800
+ const u8 = new Uint8Array(hexLen);
5801
+ for (let k = 0; k < hexLen; k++) {
5802
+ u8[k] = parseInt(cleanHex.substr(k * 2, 2), 16);
5803
+ }
5804
+ let bStr = "";
5805
+ for (let k = 0; k < u8.length; k += 8192) {
5806
+ bStr += String.fromCharCode.apply(null, Array.from(u8.subarray(k, k + 8192)));
5807
+ }
5808
+ extractedImages.push({ mime, dataUrl: `data:${mime};base64,${btoa(bStr)}`, offset: startP });
5809
+ }
5810
+ const tables = parseRtfTables(rawRtf);
5594
5811
  const wrapper = document.createElement("div");
5595
5812
  wrapper.className = "fp-rtf-wrapper";
5596
5813
  wrapper.style.padding = "0";
5597
- wrapper.style.width = "816px";
5814
+ wrapper.style.width = `${pageWidth}px`;
5598
5815
  wrapper.style.margin = "0 auto";
5599
5816
  wrapper.style.boxSizing = "border-box";
5600
5817
  wrapper.style.display = "flex";
@@ -5614,9 +5831,8 @@ var RtfPlugin = class {
5614
5831
  let isUserZoomed = false;
5615
5832
  let fitMode = ctx?.options?.fitMode || "width";
5616
5833
  const calculateFitScale = (mode = fitMode) => {
5617
- const activeEl = pageElements[currentPage - 1] || wrapper;
5618
- const elW = 816;
5619
- const singlePageH = activeEl?.offsetHeight || 1056;
5834
+ const elW = pageWidth;
5835
+ const singlePageH = pageHeight;
5620
5836
  const availW = Math.max(280, ctx.container.clientWidth - 32);
5621
5837
  const availH = Math.max(280, ctx.container.clientHeight - 32);
5622
5838
  const sW = availW / elW;
@@ -5629,8 +5845,7 @@ var RtfPlugin = class {
5629
5845
  const applyTransform = () => {
5630
5846
  wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5631
5847
  wrapper.style.transformOrigin = "top center";
5632
- const activeEl = pageElements[currentPage - 1];
5633
- const baseH = activeEl?.offsetHeight || 1056;
5848
+ const baseH = pageHeight;
5634
5849
  const scaledH = baseH * scale;
5635
5850
  const extraH = Math.max(0, scaledH - baseH);
5636
5851
  wrapper.style.marginBottom = `${extraH + 32}px`;
@@ -5650,193 +5865,220 @@ var RtfPlugin = class {
5650
5865
  if (typeof RTFJS__namespace.loggingEnabled === "function") {
5651
5866
  RTFJS__namespace.loggingEnabled(false);
5652
5867
  }
5653
- const rawText = new TextDecoder("latin1").decode(ctx.buffer);
5654
- const tables = parseRtfTables(rawText);
5655
- const seenMediaSignatures = /* @__PURE__ */ new Set();
5656
5868
  const doc = new RTFJS__namespace.Document(ctx.buffer, {
5657
5869
  onPicture: (isLegacy, createPic) => {
5658
- if (isLegacy === true) {
5659
- return null;
5660
- }
5661
- const pic = createPic();
5662
- if (!pic) return null;
5663
- const fp = extractMediaFingerprint(pic);
5664
- if (fp) {
5665
- if (seenMediaSignatures.has(fp)) {
5666
- return null;
5667
- }
5668
- seenMediaSignatures.add(fp);
5669
- }
5670
- return pic;
5870
+ if (isLegacy === true) return null;
5871
+ return createPic();
5671
5872
  }
5672
5873
  });
5673
- const htmlElements = await doc.render();
5674
- const contentNodes = [];
5675
- const seenInContentBlocks = /* @__PURE__ */ new Set();
5676
- const extractBlocks = (nodes) => {
5677
- for (const item of nodes) {
5678
- if (!item || !(item instanceof HTMLElement)) continue;
5679
- const tag = item.tagName.toLowerCase();
5680
- const hasChildBlocks = Array.from(item.children).some((c) => {
5681
- const ct = c.tagName.toLowerCase();
5682
- return ["p", "div", "table", "h1", "h2", "h3", "h4", "h5", "h6", "section", "article", "ul", "ol"].includes(ct);
5683
- });
5684
- if (hasChildBlocks && !["table", "tr", "td", "th", "ul", "ol", "li"].includes(tag)) {
5685
- extractBlocks(Array.from(item.children));
5686
- } else {
5687
- const fp = extractMediaFingerprint(item);
5688
- if (fp) {
5689
- if (seenInContentBlocks.has(fp)) {
5690
- continue;
5691
- }
5692
- seenInContentBlocks.add(fp);
5693
- }
5694
- const hasMedia = item.querySelector("img, svg, canvas, table") !== null || ["img", "svg", "table"].includes(tag);
5695
- const textContent = (item.textContent || "").trim();
5696
- if (!hasMedia && textContent.length === 0) {
5697
- continue;
5698
- }
5699
- const svgs = item.querySelectorAll("svg, img");
5700
- svgs.forEach((s) => {
5701
- const el = s;
5702
- el.style.maxWidth = "100%";
5703
- el.style.maxHeight = "360px";
5704
- el.style.display = "block";
5705
- el.style.margin = "12px auto";
5706
- if (s.tagName.toLowerCase() === "svg") {
5707
- s.removeAttribute("width");
5708
- s.removeAttribute("height");
5709
- el.style.width = "100%";
5710
- el.style.maxHeight = "360px";
5711
- }
5712
- });
5713
- if (tag === "p" || tag === "div") {
5714
- item.style.display = "block";
5715
- item.style.marginBottom = "12px";
5716
- item.style.lineHeight = "1.6";
5717
- }
5718
- contentNodes.push(item);
5874
+ const elements = await doc.render();
5875
+ let unsupportedIndex = 1;
5876
+ const usedTables = /* @__PURE__ */ new Set();
5877
+ for (let i = 0; i < elements.length; i++) {
5878
+ const el = elements[i];
5879
+ const text = el.textContent || "";
5880
+ if (text.includes("[Unsupported image format]")) {
5881
+ if (extractedImages[unsupportedIndex]) {
5882
+ const img = document.createElement("img");
5883
+ img.src = extractedImages[unsupportedIndex].dataUrl;
5884
+ img.style.width = "100%";
5885
+ img.style.height = "auto";
5886
+ img.style.maxHeight = "430px";
5887
+ img.style.objectFit = "contain";
5888
+ img.style.display = "block";
5889
+ img.style.margin = "12px auto";
5890
+ el.innerHTML = "";
5891
+ el.appendChild(img);
5892
+ unsupportedIndex++;
5719
5893
  }
5720
5894
  }
5721
- };
5722
- extractBlocks(htmlElements);
5723
- tables.forEach((table) => {
5724
- const tableEl = renderRtfTableElement(table);
5725
- let inserted = false;
5726
- if (table.anchorBefore && table.anchorBefore.length > 10) {
5727
- const keyword = table.anchorBefore.slice(-35).trim();
5728
- for (let i = 0; i < contentNodes.length; i++) {
5729
- if (contentNodes[i].textContent?.includes(keyword)) {
5730
- contentNodes.splice(i + 1, 0, tableEl);
5731
- inserted = true;
5732
- break;
5895
+ if (tables.length > 0) {
5896
+ for (let t = 0; t < tables.length; t++) {
5897
+ if (usedTables.has(t)) continue;
5898
+ const tbl = tables[t];
5899
+ if (tbl.rows.length >= 2) {
5900
+ const sampleCell1 = tbl.rows[1]?.[1] || tbl.rows[0]?.[1] || "";
5901
+ const sampleCell2 = tbl.rows[2]?.[1] || tbl.rows[1]?.[0] || "";
5902
+ const match1 = sampleCell1 && text.includes(sampleCell1.slice(0, 15).trim());
5903
+ const match2 = sampleCell2 && text.includes(sampleCell2.slice(0, 15).trim());
5904
+ if (match1 && match2) {
5905
+ el.innerHTML = "";
5906
+ el.appendChild(renderRtfTableElement(tbl));
5907
+ usedTables.add(t);
5908
+ break;
5909
+ }
5733
5910
  }
5734
5911
  }
5735
5912
  }
5736
- if (!inserted && table.anchorAfter && table.anchorAfter.length > 10) {
5737
- const keyword = table.anchorAfter.slice(0, 35).trim();
5738
- for (let i = 0; i < contentNodes.length; i++) {
5739
- if (contentNodes[i].textContent?.includes(keyword)) {
5740
- contentNodes.splice(i, 0, tableEl);
5741
- inserted = true;
5742
- break;
5743
- }
5744
- }
5913
+ }
5914
+ elements.forEach((el) => {
5915
+ const svgs = el.querySelectorAll ? Array.from(el.querySelectorAll("svg")) : [];
5916
+ svgs.forEach((svg) => {
5917
+ svg.removeAttribute("width");
5918
+ svg.removeAttribute("height");
5919
+ svg.style.maxWidth = "100%";
5920
+ svg.style.maxHeight = "430px";
5921
+ svg.style.height = "auto";
5922
+ svg.style.display = "block";
5923
+ svg.style.margin = "12px auto";
5924
+ });
5925
+ const imgs = el.querySelectorAll ? Array.from(el.querySelectorAll("img")) : [];
5926
+ imgs.forEach((img) => {
5927
+ img.style.maxWidth = "100%";
5928
+ img.style.maxHeight = "430px";
5929
+ img.style.height = "auto";
5930
+ img.style.objectFit = "contain";
5931
+ img.style.display = "block";
5932
+ img.style.margin = "12px auto";
5933
+ });
5934
+ });
5935
+ const allImgs = Array.from(document.querySelectorAll("img")).concat(
5936
+ elements.flatMap((el) => Array.from(el.querySelectorAll ? el.querySelectorAll("img") : []))
5937
+ );
5938
+ await Promise.all(allImgs.map((img) => {
5939
+ if (img.complete && img.naturalHeight > 0) return Promise.resolve();
5940
+ if (img.decode) return img.decode().catch(() => {
5941
+ });
5942
+ return new Promise((r) => {
5943
+ img.onload = r;
5944
+ img.onerror = r;
5945
+ });
5946
+ }));
5947
+ elements.forEach((el) => {
5948
+ const text = el.textContent || "";
5949
+ if (text.includes("\uF0B7")) {
5950
+ const cleanText = text.replace(/^[\s\uf0b7\t]+/, "");
5951
+ el.style.display = "flex";
5952
+ el.style.alignItems = "flex-start";
5953
+ el.style.margin = "6px 0 6px 28px";
5954
+ el.style.fontSize = "11pt";
5955
+ el.style.lineHeight = "1.5";
5956
+ el.innerHTML = `<span style="margin-right:10px; user-select:none;">&#9633;</span><span>${cleanText}</span>`;
5745
5957
  }
5746
- if (!inserted) {
5747
- if (contentNodes.length > 2) {
5748
- contentNodes.splice(2, 0, tableEl);
5749
- } else {
5750
- contentNodes.push(tableEl);
5751
- }
5958
+ });
5959
+ elements.forEach((el) => {
5960
+ const text = (el.textContent || "").trim();
5961
+ const hasMedia = el.querySelector("img, svg, canvas, table") !== null || ["IMG", "SVG", "TABLE"].includes(el.tagName);
5962
+ if (isHeadingElement(el)) {
5963
+ el.style.marginTop = "20px";
5964
+ el.style.marginBottom = "10px";
5965
+ el.style.lineHeight = "1.25";
5966
+ } else if (text.length > 0 && !hasMedia) {
5967
+ el.style.marginBottom = "12px";
5968
+ el.style.lineHeight = "1.45";
5752
5969
  }
5753
5970
  });
5754
- const createRtfCard = (pageNum) => {
5971
+ const measureCard = document.createElement("div");
5972
+ measureCard.style.width = `${pageWidth}px`;
5973
+ measureCard.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
5974
+ measureCard.style.boxSizing = "border-box";
5975
+ measureCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5976
+ measureCard.style.lineHeight = "1.45";
5977
+ measureCard.style.visibility = "hidden";
5978
+ measureCard.style.position = "absolute";
5979
+ measureCard.style.top = "-99999px";
5980
+ document.body.appendChild(measureCard);
5981
+ const createPageCard = (num) => {
5755
5982
  const card = document.createElement("div");
5756
5983
  card.className = "fp-rtf-page-card";
5757
- card.setAttribute("data-page-number", String(pageNum));
5984
+ card.setAttribute("data-page-number", String(num));
5758
5985
  card.style.backgroundColor = "#ffffff";
5759
5986
  card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08), 0 1px 3px rgba(0,0,0,0.04)";
5760
5987
  card.style.borderRadius = "4px";
5761
- card.style.padding = "64px 56px";
5762
- card.style.width = "816px";
5763
- card.style.minHeight = "1056px";
5764
- card.style.maxHeight = "1056px";
5765
- card.style.overflow = "hidden";
5988
+ card.style.width = `${pageWidth}px`;
5989
+ card.style.height = `${pageHeight}px`;
5990
+ card.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
5766
5991
  card.style.boxSizing = "border-box";
5992
+ card.style.overflow = "hidden";
5767
5993
  card.style.marginBottom = "24px";
5768
- card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5769
- card.style.lineHeight = "1.6";
5770
5994
  card.style.color = "#1e293b";
5995
+ card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5996
+ card.style.lineHeight = "1.45";
5771
5997
  card.style.position = "relative";
5998
+ card.style.textAlign = "left";
5772
5999
  return card;
5773
6000
  };
5774
- wrapper.innerHTML = "";
5775
- const measureCard = createRtfCard(0);
5776
- measureCard.style.maxHeight = "none";
5777
- measureCard.style.height = "auto";
5778
- wrapper.appendChild(measureCard);
5779
- contentNodes.forEach((node) => measureCard.appendChild(node));
5780
- const childHeights = contentNodes.map((c) => {
5781
- const rect = c.getBoundingClientRect ? c.getBoundingClientRect() : null;
5782
- const rectH = rect ? rect.height : 0;
5783
- const offH = c.offsetHeight || 0;
5784
- let realH = Math.max(rectH, offH);
5785
- try {
5786
- const cs = window.getComputedStyle(c);
5787
- realH += (parseFloat(cs.marginTop) || 0) + (parseFloat(cs.marginBottom) || 0);
5788
- } catch {
5789
- }
5790
- const hasMedia = c.querySelector("img, svg") !== null || ["img", "svg"].includes(c.tagName.toLowerCase());
5791
- const hasTable = c.querySelector("table") !== null || c.tagName.toLowerCase() === "table";
5792
- if (hasMedia) {
5793
- realH = Math.max(realH, 300);
5794
- } else if (hasTable) {
5795
- realH = Math.max(realH, 240);
5796
- }
5797
- if (realH > 0) return realH;
5798
- const textLen = c.textContent?.trim().length || 0;
5799
- return Math.max(28, Math.ceil(textLen / 75) * 26 + 16);
5800
- });
5801
- wrapper.innerHTML = "";
5802
- let curCard = createRtfCard(1);
5803
- wrapper.appendChild(curCard);
5804
- pageElements = [curCard];
5805
- let curH = 0;
5806
- const maxH = 860;
5807
- for (let i = 0; i < contentNodes.length; i++) {
5808
- const child = contentNodes[i];
5809
- const chH = childHeights[i];
5810
- const isChildEmpty = (child.textContent || "").trim().length === 0 && !child.querySelector("table, img, svg, canvas");
5811
- if (curH === 0 && isChildEmpty) {
6001
+ const pages = [];
6002
+ let curCard = createPageCard(1);
6003
+ pages.push(curCard);
6004
+ let curHeight = 0;
6005
+ for (let i = 0; i < elements.length; i++) {
6006
+ const el = elements[i];
6007
+ if (!el || !(el instanceof HTMLElement)) continue;
6008
+ const text = (el.textContent || "").trim();
6009
+ const hasMedia = el.querySelector("img, svg, canvas, table") !== null || ["IMG", "SVG", "TABLE"].includes(el.tagName);
6010
+ const isEmptyPar = !hasMedia && text.length === 0;
6011
+ if (isEmptyPar) {
6012
+ const emptyH = 35;
6013
+ if (curHeight + emptyH > printableHeight) {
6014
+ if (curCard.childNodes.length > 0) {
6015
+ curCard = createPageCard(pages.length + 1);
6016
+ pages.push(curCard);
6017
+ curHeight = 0;
6018
+ }
6019
+ }
6020
+ const spacer = document.createElement("div");
6021
+ spacer.style.height = `${emptyH}px`;
6022
+ curCard.appendChild(spacer);
6023
+ curHeight += emptyH;
5812
6024
  continue;
5813
6025
  }
5814
- const isTable = child.querySelector("table") !== null || child.tagName.toLowerCase() === "table";
5815
- const shouldBreakBeforeTable = isTable && curH > 400 && curCard.childNodes.length > 0;
5816
- if ((curH + chH > maxH || shouldBreakBeforeTable) && curCard.childNodes.length > 0) {
5817
- curCard = createRtfCard(pageElements.length + 1);
5818
- wrapper.appendChild(curCard);
5819
- pageElements.push(curCard);
5820
- curH = 0;
6026
+ measureCard.innerHTML = "";
6027
+ const clone = el.cloneNode(true);
6028
+ measureCard.appendChild(clone);
6029
+ const compStyle = window.getComputedStyle(clone);
6030
+ const mt = parseFloat(compStyle.marginTop) || 0;
6031
+ const mb = parseFloat(compStyle.marginBottom) || 0;
6032
+ const elH = clone.offsetHeight + mt + mb;
6033
+ const isHeading = isHeadingElement(el);
6034
+ let nextContentH = 0;
6035
+ if (isHeading || hasMedia) {
6036
+ for (let j = i + 1; j < elements.length; j++) {
6037
+ const nextEl = elements[j];
6038
+ if (nextEl && (nextEl.textContent || "").trim().length > 0) {
6039
+ measureCard.innerHTML = "";
6040
+ const nClone = nextEl.cloneNode(true);
6041
+ measureCard.appendChild(nClone);
6042
+ const nStyle = window.getComputedStyle(nClone);
6043
+ nextContentH = nClone.offsetHeight + (parseFloat(nStyle.marginTop) || 0) + (parseFloat(nStyle.marginBottom) || 0);
6044
+ break;
6045
+ }
6046
+ }
5821
6047
  }
5822
- curCard.appendChild(child);
5823
- curH += chH;
5824
- }
5825
- pageElements = pageElements.filter((card) => {
6048
+ const remainingSpace = printableHeight - curHeight;
6049
+ const isLargeMedia = hasMedia && elH > 300;
6050
+ const keepWithNextOverflow = isHeading && nextContentH > 0 && elH + nextContentH + 20 > remainingSpace;
6051
+ const largeMediaOverflow = isLargeMedia && curHeight > 0 && elH + 80 > remainingSpace;
6052
+ const shouldBreak = (curHeight + elH > printableHeight || keepWithNextOverflow || largeMediaOverflow) && curCard.childNodes.length > 0;
6053
+ if (shouldBreak) {
6054
+ curCard = createPageCard(pages.length + 1);
6055
+ pages.push(curCard);
6056
+ curHeight = 0;
6057
+ }
6058
+ curCard.appendChild(el);
6059
+ curHeight += elH;
6060
+ }
6061
+ measureCard.remove();
6062
+ pageElements = pages.filter((card) => {
5826
6063
  const hasText = (card.textContent || "").trim().length > 0;
5827
- const hasMedia = card.querySelector("table, img, svg, canvas") !== null;
5828
- return hasText || hasMedia;
6064
+ const hasCardMedia = card.querySelector("table, img, svg, canvas") !== null;
6065
+ return hasText || hasCardMedia;
5829
6066
  });
5830
6067
  if (pageElements.length === 0) {
5831
6068
  pageElements = [curCard];
5832
6069
  }
6070
+ wrapper.innerHTML = "";
6071
+ pageElements.forEach((card, idx) => {
6072
+ card.setAttribute("data-page-number", String(idx + 1));
6073
+ card.style.display = idx === 0 ? "block" : "none";
6074
+ wrapper.appendChild(card);
6075
+ });
5833
6076
  } catch (err) {
5834
6077
  console.warn("[RtfPlugin] RTF render error, fallback text:", err);
5835
- const text = new TextDecoder("latin1").decode(ctx.buffer);
5836
- const tables = parseRtfTables(text);
6078
+ const text = rawRtf;
5837
6079
  const rawPages = text.split(/\\page\b/).map((segment) => {
5838
6080
  return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
5839
- }).filter((p) => p.length > 0);
6081
+ }).filter((p2) => p2.length > 0);
5840
6082
  const pages = rawPages.length > 0 ? rawPages : [text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim()];
5841
6083
  for (let i = 0; i < pages.length; i++) {
5842
6084
  const pageCard = document.createElement("div");
@@ -5844,9 +6086,9 @@ var RtfPlugin = class {
5844
6086
  pageCard.style.backgroundColor = "#ffffff";
5845
6087
  pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
5846
6088
  pageCard.style.borderRadius = "4px";
5847
- pageCard.style.padding = "64px 56px";
5848
- pageCard.style.width = "816px";
5849
- pageCard.style.minHeight = "1056px";
6089
+ pageCard.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
6090
+ pageCard.style.width = `${pageWidth}px`;
6091
+ pageCard.style.minHeight = `${pageHeight}px`;
5850
6092
  pageCard.style.boxSizing = "border-box";
5851
6093
  pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5852
6094
  pageCard.style.fontSize = "12pt";
@@ -5866,11 +6108,9 @@ var RtfPlugin = class {
5866
6108
  let currentPage = 1;
5867
6109
  const showPage = (pageNum) => {
5868
6110
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
5869
- if (totalPages > 1) {
5870
- pageElements.forEach((el, idx) => {
5871
- el.style.display = idx + 1 === currentPage ? "block" : "none";
5872
- });
5873
- }
6111
+ pageElements.forEach((el, idx) => {
6112
+ el.style.display = idx + 1 === currentPage ? "block" : "none";
6113
+ });
5874
6114
  ctx.container.scrollTop = 0;
5875
6115
  ctx.emit("page-change", { page: currentPage, total: totalPages });
5876
6116
  };
@@ -5937,6 +6177,15 @@ var RtfPlugin = class {
5937
6177
  rotation = 0;
5938
6178
  applyTransform();
5939
6179
  },
6180
+ resetZoom: () => {
6181
+ isUserZoomed = false;
6182
+ fitMode = "width";
6183
+ scale = calculateFitScale("width");
6184
+ rotation = 0;
6185
+ ctx.container.scrollTop = 0;
6186
+ ctx.container.scrollLeft = 0;
6187
+ applyTransform();
6188
+ },
5940
6189
  rotateCW: () => {
5941
6190
  rotation = (rotation + 90) % 360;
5942
6191
  applyTransform();
@@ -6004,6 +6253,14 @@ var HtmlPreviewPlugin = class {
6004
6253
  group: "zoom",
6005
6254
  execute: () => instance.fitToPage?.()
6006
6255
  },
6256
+ {
6257
+ id: "reset-zoom",
6258
+ icon: "reset-zoom",
6259
+ label: "Reset Zoom",
6260
+ type: "button",
6261
+ group: "zoom",
6262
+ execute: () => instance.resetZoom?.()
6263
+ },
6007
6264
  {
6008
6265
  id: "copy",
6009
6266
  icon: "copy",
@@ -6076,6 +6333,12 @@ var HtmlPreviewPlugin = class {
6076
6333
  scale = 1;
6077
6334
  iframe.style.transform = "scale(1)";
6078
6335
  },
6336
+ resetZoom: () => {
6337
+ scale = 1;
6338
+ iframe.style.transform = "scale(1)";
6339
+ ctx.container.scrollTop = 0;
6340
+ ctx.container.scrollLeft = 0;
6341
+ },
6079
6342
  copy: () => {
6080
6343
  navigator.clipboard.writeText(rawHtml);
6081
6344
  },
@@ -6176,6 +6439,14 @@ var OpenDocumentPlugin = class {
6176
6439
  group: "zoom",
6177
6440
  execute: () => instance.fitToPage?.()
6178
6441
  },
6442
+ {
6443
+ id: "reset-zoom",
6444
+ icon: "reset-zoom",
6445
+ label: "Reset Zoom",
6446
+ type: "button",
6447
+ group: "zoom",
6448
+ execute: () => instance.resetZoom?.()
6449
+ },
6179
6450
  {
6180
6451
  id: "rotate-cw",
6181
6452
  icon: "rotate-cw",
@@ -6443,6 +6714,15 @@ var OpenDocumentPlugin = class {
6443
6714
  rotation = 0;
6444
6715
  applyTransform();
6445
6716
  },
6717
+ resetZoom: () => {
6718
+ isUserZoomed = false;
6719
+ fitMode = "width";
6720
+ scale = calculateFitScale("width");
6721
+ rotation = 0;
6722
+ container.scrollTop = 0;
6723
+ container.scrollLeft = 0;
6724
+ applyTransform();
6725
+ },
6446
6726
  rotateCW: () => {
6447
6727
  rotation = (rotation + 90) % 360;
6448
6728
  applyTransform();
@@ -6786,6 +7066,14 @@ var DocPlugin = class {
6786
7066
  group: "zoom",
6787
7067
  execute: () => instance.fitToPage?.()
6788
7068
  },
7069
+ {
7070
+ id: "reset-zoom",
7071
+ icon: "reset-zoom",
7072
+ label: "Reset Zoom",
7073
+ type: "button",
7074
+ group: "zoom",
7075
+ execute: () => instance.resetZoom?.()
7076
+ },
6789
7077
  {
6790
7078
  id: "rotate-cw",
6791
7079
  icon: "rotate-cw",
@@ -6992,6 +7280,15 @@ var DocPlugin = class {
6992
7280
  rotation = 0;
6993
7281
  applyTransform();
6994
7282
  },
7283
+ resetZoom: () => {
7284
+ isUserZoomed = false;
7285
+ fitMode = "width";
7286
+ scale = calculateFitScale("width");
7287
+ rotation = 0;
7288
+ ctx.container.scrollTop = 0;
7289
+ ctx.container.scrollLeft = 0;
7290
+ applyTransform();
7291
+ },
6995
7292
  rotateCW: () => {
6996
7293
  rotation = (rotation + 90) % 360;
6997
7294
  applyTransform();
@@ -7472,6 +7769,14 @@ var PptPlugin = class {
7472
7769
  group: "zoom",
7473
7770
  execute: () => instance.fitToPage?.()
7474
7771
  },
7772
+ {
7773
+ id: "reset-zoom",
7774
+ icon: "reset-zoom",
7775
+ label: "Reset Zoom",
7776
+ type: "button",
7777
+ group: "zoom",
7778
+ execute: () => instance.resetZoom?.()
7779
+ },
7475
7780
  {
7476
7781
  id: "rotate-cw",
7477
7782
  icon: "rotate-cw",
@@ -7660,6 +7965,13 @@ var PptPlugin = class {
7660
7965
  rotation = 0;
7661
7966
  applyTransform();
7662
7967
  },
7968
+ resetZoom: () => {
7969
+ scale = calculateFitScale();
7970
+ rotation = 0;
7971
+ container.scrollTop = 0;
7972
+ container.scrollLeft = 0;
7973
+ applyTransform();
7974
+ },
7663
7975
  rotateCW: () => {
7664
7976
  rotation = (rotation + 90) % 360;
7665
7977
  applyTransform();