@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.js CHANGED
@@ -543,6 +543,7 @@ var ICON_COPY = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" str
543
543
  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>`;
544
544
  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>`;
545
545
  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>`;
546
+ 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>`;
546
547
  var ICON_MAP = {
547
548
  "zoom-in": ICON_ZOOM_IN,
548
549
  "zoom-out": ICON_ZOOM_OUT,
@@ -572,7 +573,10 @@ var ICON_MAP = {
572
573
  "open-window": ICON_EXTERNAL_WINDOW,
573
574
  "external-window": ICON_EXTERNAL_WINDOW,
574
575
  "openWindow": ICON_EXTERNAL_WINDOW,
575
- "openSeparateWindow": ICON_EXTERNAL_WINDOW
576
+ "openSeparateWindow": ICON_EXTERNAL_WINDOW,
577
+ "reset-zoom": ICON_RESET_ZOOM,
578
+ "zoom-reset": ICON_RESET_ZOOM,
579
+ "resetZoom": ICON_RESET_ZOOM
576
580
  };
577
581
  var ToolbarController = class {
578
582
  el;
@@ -605,6 +609,10 @@ var ToolbarController = class {
605
609
  this.config.fitToPage = false;
606
610
  this.config.fitWidth = false;
607
611
  }
612
+ if (actionId === "reset-zoom" || actionId === "zoom-reset" || actionId === "resetZoom") {
613
+ this.config.resetZoom = false;
614
+ this.config.zoomReset = false;
615
+ }
608
616
  if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = false;
609
617
  if (actionId === "fullscreen") this.config.fullscreen = false;
610
618
  if (actionId === "download") this.config.download = false;
@@ -629,6 +637,10 @@ var ToolbarController = class {
629
637
  this.config.fitToPage = true;
630
638
  this.config.fitWidth = true;
631
639
  }
640
+ if (actionId === "reset-zoom" || actionId === "zoom-reset" || actionId === "resetZoom") {
641
+ this.config.resetZoom = true;
642
+ this.config.zoomReset = true;
643
+ }
632
644
  if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = true;
633
645
  if (actionId === "fullscreen") this.config.fullscreen = true;
634
646
  if (actionId === "download") this.config.download = true;
@@ -648,6 +660,7 @@ var ToolbarController = class {
648
660
  if (actionId === "zoomIn") return "zoom-in";
649
661
  if (actionId === "zoomOut") return "zoom-out";
650
662
  if (actionId === "fitPage" || actionId === "fitToPage" || actionId === "fitWidth") return "fit-page";
663
+ if (actionId === "resetZoom" || actionId === "zoomReset") return "reset-zoom";
651
664
  if (actionId === "rotateCW") return "rotate-cw";
652
665
  if (actionId === "rotateCCW") return "rotate-ccw";
653
666
  if (actionId === "openWindow" || actionId === "openSeparateWindow") return "open-window";
@@ -690,6 +703,9 @@ var ToolbarController = class {
690
703
  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)) {
691
704
  return false;
692
705
  }
706
+ if ((id === "reset-zoom" || id === "zoom-reset") && (c.resetZoom === false || c.zoomReset === false || c["reset-zoom"] === false || c["zoom-reset"] === false)) {
707
+ return false;
708
+ }
693
709
  if ((id === "rotate-cw" || id === "rotate-ccw" || id === "rotate") && (c.rotate === false || c.rotateCW === false || c.rotateCCW === false || c["rotate-cw"] === false)) {
694
710
  return false;
695
711
  }
@@ -1136,6 +1152,9 @@ var FilePreviewViewer = class _FilePreviewViewer {
1136
1152
  this.activeInstance = instance;
1137
1153
  instance.openInSeparateWindow = () => this.openInSeparateWindow();
1138
1154
  instance.toggleThumbnails = () => this.toggleThumbnails();
1155
+ if (!instance.resetZoom && instance.fitToPage) {
1156
+ instance.resetZoom = () => instance.fitToPage?.();
1157
+ }
1139
1158
  this.hideLoading();
1140
1159
  this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
1141
1160
  const isToolbarVisible = options.showToolbar !== false && options.toolbar !== false;
@@ -1419,6 +1438,16 @@ var FilePreviewViewer = class _FilePreviewViewer {
1419
1438
  fitToPage() {
1420
1439
  this.activeInstance?.fitToPage?.();
1421
1440
  }
1441
+ /**
1442
+ * Reset zoom level to initial/default fit state.
1443
+ */
1444
+ resetZoom() {
1445
+ if (this.activeInstance?.resetZoom) {
1446
+ this.activeInstance.resetZoom();
1447
+ } else if (this.activeInstance?.fitToPage) {
1448
+ this.activeInstance.fitToPage();
1449
+ }
1450
+ }
1422
1451
  /**
1423
1452
  * Zoom in.
1424
1453
  */
@@ -2040,6 +2069,14 @@ var PdfPlugin = class {
2040
2069
  group: "zoom",
2041
2070
  execute: () => instance.fitToPage?.()
2042
2071
  },
2072
+ {
2073
+ id: "reset-zoom",
2074
+ icon: "reset-zoom",
2075
+ label: "Reset Zoom",
2076
+ type: "button",
2077
+ group: "zoom",
2078
+ execute: () => instance.resetZoom?.()
2079
+ },
2043
2080
  {
2044
2081
  id: "fit-width",
2045
2082
  icon: "fit-width",
@@ -2302,6 +2339,14 @@ var PdfPlugin = class {
2302
2339
  zoomScale = 1;
2303
2340
  renderPage(currentPage);
2304
2341
  },
2342
+ resetZoom: () => {
2343
+ fitMode = "page";
2344
+ zoomScale = 1;
2345
+ rotation = 0;
2346
+ container.scrollTop = 0;
2347
+ container.scrollLeft = 0;
2348
+ renderPage(currentPage);
2349
+ },
2305
2350
  fitToWidth: () => {
2306
2351
  fitMode = "width";
2307
2352
  zoomScale = 1;
@@ -2469,6 +2514,16 @@ var MediaPlugin = class {
2469
2514
  instance.fitToPage?.();
2470
2515
  }
2471
2516
  },
2517
+ {
2518
+ id: "reset-zoom",
2519
+ icon: "reset-zoom",
2520
+ label: "Reset Zoom",
2521
+ type: "button",
2522
+ group: "zoom",
2523
+ execute: () => {
2524
+ instance.resetZoom?.();
2525
+ }
2526
+ },
2472
2527
  {
2473
2528
  id: "rotate-cw",
2474
2529
  icon: "rotate-cw",
@@ -2642,6 +2697,13 @@ var MediaPlugin = class {
2642
2697
  rotation = 0;
2643
2698
  applyTransform();
2644
2699
  } : void 0,
2700
+ resetZoom: isImage ? () => {
2701
+ currentZoom = 1;
2702
+ rotation = 0;
2703
+ ctx.container.scrollTop = 0;
2704
+ ctx.container.scrollLeft = 0;
2705
+ applyTransform();
2706
+ } : void 0,
2645
2707
  rotateCW: isImage || isVideo ? () => {
2646
2708
  rotation = (rotation + 90) % 360;
2647
2709
  applyTransform();
@@ -2758,6 +2820,14 @@ var DocxPlugin = class {
2758
2820
  group: "zoom",
2759
2821
  execute: () => instance.fitToPage?.()
2760
2822
  },
2823
+ {
2824
+ id: "reset-zoom",
2825
+ icon: "reset-zoom",
2826
+ label: "Reset Zoom",
2827
+ type: "button",
2828
+ group: "zoom",
2829
+ execute: () => instance.resetZoom?.()
2830
+ },
2761
2831
  {
2762
2832
  id: "rotate-cw",
2763
2833
  icon: "rotate-cw",
@@ -3074,6 +3144,14 @@ var DocxPlugin = class {
3074
3144
  rotation = 0;
3075
3145
  applyTransform();
3076
3146
  },
3147
+ resetZoom: () => {
3148
+ isUserZoomed = false;
3149
+ scale = calculateFitScale("page");
3150
+ rotation = 0;
3151
+ ctx.container.scrollTop = 0;
3152
+ ctx.container.scrollLeft = 0;
3153
+ applyTransform();
3154
+ },
3077
3155
  rotateCW: () => {
3078
3156
  rotation = (rotation + 90) % 360;
3079
3157
  applyTransform();
@@ -3523,6 +3601,16 @@ var ExcelPlugin = class {
3523
3601
  instance.zoomIn?.();
3524
3602
  }
3525
3603
  },
3604
+ {
3605
+ id: "reset-zoom",
3606
+ icon: "reset-zoom",
3607
+ label: "Reset Zoom",
3608
+ type: "button",
3609
+ group: "zoom",
3610
+ execute: () => {
3611
+ instance.resetZoom?.();
3612
+ }
3613
+ },
3526
3614
  {
3527
3615
  id: "download",
3528
3616
  icon: "download",
@@ -3710,6 +3798,12 @@ var ExcelPlugin = class {
3710
3798
  scale = calculateFitScale();
3711
3799
  applyTransform();
3712
3800
  },
3801
+ resetZoom: () => {
3802
+ scale = calculateFitScale();
3803
+ contentArea.scrollTop = 0;
3804
+ contentArea.scrollLeft = 0;
3805
+ applyTransform();
3806
+ },
3713
3807
  rotateCW: () => {
3714
3808
  },
3715
3809
  rotateCCW: () => {
@@ -3840,6 +3934,16 @@ var CsvPlugin = class {
3840
3934
  instance.zoomIn?.();
3841
3935
  }
3842
3936
  },
3937
+ {
3938
+ id: "reset-zoom",
3939
+ icon: "reset-zoom",
3940
+ label: "Reset Zoom",
3941
+ type: "button",
3942
+ group: "zoom",
3943
+ execute: () => {
3944
+ instance.resetZoom?.();
3945
+ }
3946
+ },
3843
3947
  {
3844
3948
  id: "download",
3845
3949
  icon: "download",
@@ -4029,6 +4133,12 @@ var CsvPlugin = class {
4029
4133
  scale = calculateFitScale();
4030
4134
  applyScale();
4031
4135
  },
4136
+ resetZoom: () => {
4137
+ scale = calculateFitScale();
4138
+ container.scrollTop = 0;
4139
+ container.scrollLeft = 0;
4140
+ applyScale();
4141
+ },
4032
4142
  rotateCW: () => {
4033
4143
  },
4034
4144
  rotateCCW: () => {
@@ -4144,6 +4254,16 @@ var CodePlugin = class {
4144
4254
  instance.zoomIn?.();
4145
4255
  }
4146
4256
  },
4257
+ {
4258
+ id: "reset-zoom",
4259
+ icon: "reset-zoom",
4260
+ label: "Reset Zoom",
4261
+ type: "button",
4262
+ group: "zoom",
4263
+ execute: () => {
4264
+ instance.resetZoom?.();
4265
+ }
4266
+ },
4147
4267
  {
4148
4268
  id: "copy",
4149
4269
  icon: "copy",
@@ -4423,6 +4543,15 @@ var CodePlugin = class {
4423
4543
  zoomLevel = isTxt ? calculateTxtFit() : 1;
4424
4544
  updateTransform();
4425
4545
  },
4546
+ resetZoom: () => {
4547
+ isUserZoomed = false;
4548
+ fontSize = 13;
4549
+ rotation = 0;
4550
+ zoomLevel = isTxt ? calculateTxtFit() : 1;
4551
+ container.scrollTop = 0;
4552
+ container.scrollLeft = 0;
4553
+ updateTransform();
4554
+ },
4426
4555
  rotateCW: () => {
4427
4556
  rotation = (rotation + 90) % 360;
4428
4557
  updateTransform();
@@ -4485,11 +4614,19 @@ var ArchivePlugin = class {
4485
4614
  {
4486
4615
  id: "fit-page",
4487
4616
  icon: "fit-page",
4488
- label: "Reset Zoom",
4617
+ label: "Fit to Page",
4489
4618
  type: "button",
4490
4619
  group: "zoom",
4491
4620
  execute: () => instance.fitToPage?.()
4492
4621
  },
4622
+ {
4623
+ id: "reset-zoom",
4624
+ icon: "reset-zoom",
4625
+ label: "Reset Zoom",
4626
+ type: "button",
4627
+ group: "zoom",
4628
+ execute: () => instance.resetZoom?.()
4629
+ },
4493
4630
  {
4494
4631
  id: "download",
4495
4632
  icon: "download",
@@ -4644,7 +4781,13 @@ var ArchivePlugin = class {
4644
4781
  },
4645
4782
  fitToPage: () => {
4646
4783
  scale = 1;
4647
- wrapper.style.transform = `scale(1)`;
4784
+ wrapper.style.transform = "scale(1)";
4785
+ },
4786
+ resetZoom: () => {
4787
+ scale = 1;
4788
+ wrapper.style.transform = "scale(1)";
4789
+ ctx.container.scrollTop = 0;
4790
+ ctx.container.scrollLeft = 0;
4648
4791
  },
4649
4792
  download: () => {
4650
4793
  downloadFile(ctx.buffer, ctx.metadata.name || "archive.zip", "application/zip");
@@ -4696,6 +4839,14 @@ var MarkdownPlugin = class {
4696
4839
  group: "zoom",
4697
4840
  execute: () => instance.fitToPage?.()
4698
4841
  },
4842
+ {
4843
+ id: "reset-zoom",
4844
+ icon: "reset-zoom",
4845
+ label: "Reset Zoom",
4846
+ type: "button",
4847
+ group: "zoom",
4848
+ execute: () => instance.resetZoom?.()
4849
+ },
4699
4850
  {
4700
4851
  id: "copy",
4701
4852
  icon: "copy",
@@ -4849,6 +5000,12 @@ var MarkdownPlugin = class {
4849
5000
  fontSize = 15;
4850
5001
  wrapper.style.fontSize = "15px";
4851
5002
  },
5003
+ resetZoom: () => {
5004
+ fontSize = 15;
5005
+ wrapper.style.fontSize = "15px";
5006
+ ctx.container.scrollTop = 0;
5007
+ ctx.container.scrollLeft = 0;
5008
+ },
4852
5009
  download: () => {
4853
5010
  downloadFile(ctx.buffer, ctx.metadata.name || "document.md", "text/markdown");
4854
5011
  },
@@ -4942,6 +5099,14 @@ var PptxPlugin = class {
4942
5099
  group: "zoom",
4943
5100
  execute: () => instance.fitToPage?.()
4944
5101
  },
5102
+ {
5103
+ id: "reset-zoom",
5104
+ icon: "reset-zoom",
5105
+ label: "Reset Zoom",
5106
+ type: "button",
5107
+ group: "zoom",
5108
+ execute: () => instance.resetZoom?.()
5109
+ },
4945
5110
  {
4946
5111
  id: "rotate-cw",
4947
5112
  icon: "rotate-cw",
@@ -5061,6 +5226,13 @@ var PptxPlugin = class {
5061
5226
  rotation = 0;
5062
5227
  applyTransform();
5063
5228
  },
5229
+ resetZoom: () => {
5230
+ scale = calculateFitScale();
5231
+ rotation = 0;
5232
+ wrapper.scrollTop = 0;
5233
+ wrapper.scrollLeft = 0;
5234
+ applyTransform();
5235
+ },
5064
5236
  rotateCW: () => {
5065
5237
  rotation = (rotation + 90) % 360;
5066
5238
  applyTransform();
@@ -5136,6 +5308,14 @@ var ThreeDPlugin = class {
5136
5308
  group: "zoom",
5137
5309
  execute: () => instance.fitToPage?.()
5138
5310
  },
5311
+ {
5312
+ id: "reset-zoom",
5313
+ icon: "reset-zoom",
5314
+ label: "Reset Zoom",
5315
+ type: "button",
5316
+ group: "zoom",
5317
+ execute: () => instance.resetZoom?.()
5318
+ },
5139
5319
  {
5140
5320
  id: "rotate-cw",
5141
5321
  icon: "rotate-cw",
@@ -5272,6 +5452,7 @@ var ThreeDPlugin = class {
5272
5452
  controls.update();
5273
5453
  },
5274
5454
  fitToPage: fitCamera,
5455
+ resetZoom: fitCamera,
5275
5456
  rotateCW: () => {
5276
5457
  isWireframe = !isWireframe;
5277
5458
  materials.forEach((m) => {
@@ -5294,7 +5475,7 @@ function cleanRtfText(raw) {
5294
5475
  return String.fromCharCode(num);
5295
5476
  }).replace(/\\'([0-9a-fA-F]{2})/g, (_, hex) => {
5296
5477
  return String.fromCharCode(parseInt(hex, 16));
5297
- }).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();
5478
+ }).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();
5298
5479
  }
5299
5480
  function parseRtfTables(rtfText) {
5300
5481
  const rowSegments = rtfText.split(/\\row\b/);
@@ -5334,17 +5515,12 @@ function parseRtfTables(rtfText) {
5334
5515
  }
5335
5516
  const isNewTable = !currentTable || segmentStart - currentTable.lastEnd > 2500;
5336
5517
  if (isNewTable) {
5337
- const prevTextSlice = rtfText.slice(Math.max(0, segmentStart - 4e3), segmentStart);
5338
- const cleanPrev = cleanRtfText(prevTextSlice);
5339
- const anchorBefore = cleanPrev.slice(-80).trim();
5340
5518
  currentTable = {
5341
5519
  id: `RTF_TABLE_${rawTables.length}`,
5342
5520
  startPos: segmentStart,
5343
5521
  lastEnd: segmentEnd,
5344
5522
  rows: [],
5345
- columnWidths: cellWidths,
5346
- anchorBefore,
5347
- anchorAfter: ""
5523
+ columnWidths: cellWidths
5348
5524
  };
5349
5525
  rawTables.push(currentTable);
5350
5526
  }
@@ -5358,20 +5534,13 @@ function parseRtfTables(rtfText) {
5358
5534
  }
5359
5535
  charOffset += segment.length + 4;
5360
5536
  }
5361
- rawTables.forEach((tbl) => {
5362
- const afterSlice = rtfText.slice(tbl.lastEnd, Math.min(rtfText.length, tbl.lastEnd + 2e3));
5363
- const cleanAfter = cleanRtfText(afterSlice);
5364
- tbl.anchorAfter = cleanAfter.slice(0, 80).trim();
5365
- });
5366
5537
  return rawTables.map((tbl) => {
5367
5538
  const totalW = (tbl.columnWidths || []).reduce((a, b) => a + b, 0);
5368
5539
  const colPercents = totalW > 0 ? tbl.columnWidths.map((w) => Math.round(w / totalW * 100)) : [];
5369
5540
  return {
5370
5541
  id: tbl.id,
5371
5542
  rows: tbl.rows.map((r) => r.cells),
5372
- colPercents,
5373
- anchorBefore: tbl.anchorBefore,
5374
- anchorAfter: tbl.anchorAfter
5543
+ colPercents
5375
5544
  };
5376
5545
  });
5377
5546
  }
@@ -5384,8 +5553,6 @@ function renderRtfTableElement(table) {
5384
5553
  tableEl.style.fontSize = "10pt";
5385
5554
  tableEl.style.lineHeight = "1.5";
5386
5555
  tableEl.style.border = "1px solid #cbd5e1";
5387
- tableEl.style.borderRadius = "4px";
5388
- tableEl.style.boxSizing = "border-box";
5389
5556
  tableEl.style.backgroundColor = "#ffffff";
5390
5557
  const thead = document.createElement("thead");
5391
5558
  const tbody = document.createElement("tbody");
@@ -5394,27 +5561,17 @@ function renderRtfTableElement(table) {
5394
5561
  const isHeader = rIdx === 0;
5395
5562
  if (isHeader) {
5396
5563
  tr.style.backgroundColor = "#f8fafc";
5397
- tr.style.borderBottom = "2px solid #cbd5e1";
5398
- } else {
5399
- tr.style.borderBottom = "1px solid #e2e8f0";
5400
- if (rIdx % 2 === 0) {
5401
- tr.style.backgroundColor = "#fcfdfe";
5402
- }
5403
5564
  }
5404
5565
  rowCells.forEach((cellText, cIdx) => {
5405
5566
  const cellEl = document.createElement(isHeader ? "th" : "td");
5406
5567
  cellEl.style.padding = "8px 12px";
5407
5568
  cellEl.style.border = "1px solid #cbd5e1";
5408
5569
  cellEl.style.verticalAlign = "top";
5409
- cellEl.style.color = isHeader ? "#0f172a" : "#1e293b";
5410
- cellEl.style.fontWeight = isHeader ? "600" : "normal";
5411
5570
  if (table.colPercents && table.colPercents[cIdx]) {
5412
5571
  cellEl.style.width = `${table.colPercents[cIdx]}%`;
5413
5572
  }
5414
5573
  if (/^\d+$/.test(cellText.trim()) || cellText.trim() === "#") {
5415
5574
  cellEl.style.textAlign = "center";
5416
- } else {
5417
- cellEl.style.textAlign = "left";
5418
5575
  }
5419
5576
  cellEl.textContent = cellText;
5420
5577
  tr.appendChild(cellEl);
@@ -5429,23 +5586,19 @@ function renderRtfTableElement(table) {
5429
5586
  tableEl.appendChild(tbody);
5430
5587
  return tableEl;
5431
5588
  }
5432
- function extractMediaFingerprint(el) {
5433
- const img = el.tagName.toLowerCase() === "img" ? el : el.querySelector("img");
5434
- if (img && img.src) {
5435
- const s = img.src;
5436
- return s.length > 300 ? `img_${s.slice(0, 80)}_${s.length}_${s.slice(-80)}` : `img_${s}`;
5437
- }
5438
- const innerImg = el.querySelector("image");
5439
- if (innerImg) {
5440
- const h = innerImg.getAttribute("xlink:href") || innerImg.getAttribute("href") || "";
5441
- if (h) return h.length > 300 ? `svgimg_${h.slice(0, 80)}_${h.length}_${h.slice(-80)}` : `svgimg_${h}`;
5442
- }
5443
- const svg = el.tagName.toLowerCase() === "svg" ? el : el.querySelector("svg");
5444
- if (svg) {
5445
- const vb = svg.getAttribute("viewBox") || "";
5446
- return `svg_${vb}_${svg.innerHTML.length}`;
5447
- }
5448
- return null;
5589
+ function isHeadingElement(el) {
5590
+ if (["H1", "H2", "H3", "H4"].includes(el.tagName)) return true;
5591
+ const spans = el.querySelectorAll ? Array.from(el.querySelectorAll("span, b, strong, div")) : [];
5592
+ for (const s of spans) {
5593
+ const hEl = s;
5594
+ const fs = parseFloat(hEl.style.fontSize) || 0;
5595
+ const isBold = hEl.style.fontWeight === "bold" || parseInt(hEl.style.fontWeight, 10) >= 600 || ["B", "STRONG"].includes(hEl.tagName);
5596
+ if (isBold && fs >= 14) return true;
5597
+ }
5598
+ const elFs = parseFloat(el.style.fontSize) || 0;
5599
+ const elBold = el.style.fontWeight === "bold" || parseInt(el.style.fontWeight, 10) >= 600;
5600
+ if (elBold && elFs >= 14) return true;
5601
+ return false;
5449
5602
  }
5450
5603
  var RtfPlugin = class {
5451
5604
  id = "rtf";
@@ -5514,6 +5667,14 @@ var RtfPlugin = class {
5514
5667
  group: "zoom",
5515
5668
  execute: () => instance.fitToPage?.()
5516
5669
  },
5670
+ {
5671
+ id: "reset-zoom",
5672
+ icon: "reset-zoom",
5673
+ label: "Reset Zoom",
5674
+ type: "button",
5675
+ group: "zoom",
5676
+ execute: () => instance.resetZoom?.()
5677
+ },
5517
5678
  {
5518
5679
  id: "rotate-cw",
5519
5680
  icon: "rotate-cw",
@@ -5558,10 +5719,66 @@ var RtfPlugin = class {
5558
5719
  return actions;
5559
5720
  }
5560
5721
  async render(ctx) {
5722
+ const rawRtf = new TextDecoder("latin1").decode(ctx.buffer);
5723
+ const paperwMatch = rawRtf.match(/\\paperw(\d+)/);
5724
+ const paperhMatch = rawRtf.match(/\\paperh(\d+)/);
5725
+ const marglMatch = rawRtf.match(/\\margl(\d+)/);
5726
+ const margrMatch = rawRtf.match(/\\margr(\d+)/);
5727
+ const margtMatch = rawRtf.match(/\\margt(\d+)/);
5728
+ const margbMatch = rawRtf.match(/\\margb(\d+)/);
5729
+ const paperwTwips = paperwMatch ? parseInt(paperwMatch[1], 10) : 11906;
5730
+ const paperhTwips = paperhMatch ? parseInt(paperhMatch[1], 10) : 16838;
5731
+ const marglTwips = marglMatch ? parseInt(marglMatch[1], 10) : 1134;
5732
+ const margrTwips = margrMatch ? parseInt(margrMatch[1], 10) : 1134;
5733
+ const margtTwips = margtMatch ? parseInt(margtMatch[1], 10) : 1134;
5734
+ const margbTwips = margbMatch ? parseInt(margbMatch[1], 10) : 1134;
5735
+ const pageWidth = Math.round(paperwTwips / 15);
5736
+ const pageHeight = Math.round(paperhTwips / 15);
5737
+ const padLeft = Math.round(marglTwips / 15);
5738
+ const padRight = Math.round(margrTwips / 15);
5739
+ const padTop = Math.round(margtTwips / 15);
5740
+ const padBottom = Math.round(margbTwips / 15);
5741
+ const printableHeight = pageHeight - padTop - padBottom;
5742
+ const extractedImages = [];
5743
+ let p = 0;
5744
+ while ((p = rawRtf.indexOf("\\pict", p)) !== -1) {
5745
+ const startP = p;
5746
+ p += 5;
5747
+ const header = rawRtf.substring(startP, startP + 600);
5748
+ let mime = "";
5749
+ let magic = "";
5750
+ if (header.includes("\\pngblip")) {
5751
+ mime = "image/png";
5752
+ magic = "89504e47";
5753
+ } else if (header.includes("\\jpegblip")) {
5754
+ mime = "image/jpeg";
5755
+ magic = "ffd8ff";
5756
+ }
5757
+ if (!mime || !magic) continue;
5758
+ const magicPos = rawRtf.indexOf(magic, startP);
5759
+ if (magicPos === -1 || magicPos - startP > 3e3) continue;
5760
+ let endP = magicPos;
5761
+ while (endP < rawRtf.length && /[0-9a-fA-F\r\n\s]/.test(rawRtf[endP])) {
5762
+ endP++;
5763
+ }
5764
+ const cleanHex = rawRtf.substring(magicPos, endP).replace(/[\r\n\s]/g, "");
5765
+ if (cleanHex.length < 100) continue;
5766
+ const hexLen = cleanHex.length / 2;
5767
+ const u8 = new Uint8Array(hexLen);
5768
+ for (let k = 0; k < hexLen; k++) {
5769
+ u8[k] = parseInt(cleanHex.substr(k * 2, 2), 16);
5770
+ }
5771
+ let bStr = "";
5772
+ for (let k = 0; k < u8.length; k += 8192) {
5773
+ bStr += String.fromCharCode.apply(null, Array.from(u8.subarray(k, k + 8192)));
5774
+ }
5775
+ extractedImages.push({ mime, dataUrl: `data:${mime};base64,${btoa(bStr)}`, offset: startP });
5776
+ }
5777
+ const tables = parseRtfTables(rawRtf);
5561
5778
  const wrapper = document.createElement("div");
5562
5779
  wrapper.className = "fp-rtf-wrapper";
5563
5780
  wrapper.style.padding = "0";
5564
- wrapper.style.width = "816px";
5781
+ wrapper.style.width = `${pageWidth}px`;
5565
5782
  wrapper.style.margin = "0 auto";
5566
5783
  wrapper.style.boxSizing = "border-box";
5567
5784
  wrapper.style.display = "flex";
@@ -5581,9 +5798,8 @@ var RtfPlugin = class {
5581
5798
  let isUserZoomed = false;
5582
5799
  let fitMode = ctx?.options?.fitMode || "width";
5583
5800
  const calculateFitScale = (mode = fitMode) => {
5584
- const activeEl = pageElements[currentPage - 1] || wrapper;
5585
- const elW = 816;
5586
- const singlePageH = activeEl?.offsetHeight || 1056;
5801
+ const elW = pageWidth;
5802
+ const singlePageH = pageHeight;
5587
5803
  const availW = Math.max(280, ctx.container.clientWidth - 32);
5588
5804
  const availH = Math.max(280, ctx.container.clientHeight - 32);
5589
5805
  const sW = availW / elW;
@@ -5596,8 +5812,7 @@ var RtfPlugin = class {
5596
5812
  const applyTransform = () => {
5597
5813
  wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5598
5814
  wrapper.style.transformOrigin = "top center";
5599
- const activeEl = pageElements[currentPage - 1];
5600
- const baseH = activeEl?.offsetHeight || 1056;
5815
+ const baseH = pageHeight;
5601
5816
  const scaledH = baseH * scale;
5602
5817
  const extraH = Math.max(0, scaledH - baseH);
5603
5818
  wrapper.style.marginBottom = `${extraH + 32}px`;
@@ -5617,193 +5832,220 @@ var RtfPlugin = class {
5617
5832
  if (typeof RTFJS.loggingEnabled === "function") {
5618
5833
  RTFJS.loggingEnabled(false);
5619
5834
  }
5620
- const rawText = new TextDecoder("latin1").decode(ctx.buffer);
5621
- const tables = parseRtfTables(rawText);
5622
- const seenMediaSignatures = /* @__PURE__ */ new Set();
5623
5835
  const doc = new RTFJS.Document(ctx.buffer, {
5624
5836
  onPicture: (isLegacy, createPic) => {
5625
- if (isLegacy === true) {
5626
- return null;
5627
- }
5628
- const pic = createPic();
5629
- if (!pic) return null;
5630
- const fp = extractMediaFingerprint(pic);
5631
- if (fp) {
5632
- if (seenMediaSignatures.has(fp)) {
5633
- return null;
5634
- }
5635
- seenMediaSignatures.add(fp);
5636
- }
5637
- return pic;
5837
+ if (isLegacy === true) return null;
5838
+ return createPic();
5638
5839
  }
5639
5840
  });
5640
- const htmlElements = await doc.render();
5641
- const contentNodes = [];
5642
- const seenInContentBlocks = /* @__PURE__ */ new Set();
5643
- const extractBlocks = (nodes) => {
5644
- for (const item of nodes) {
5645
- if (!item || !(item instanceof HTMLElement)) continue;
5646
- const tag = item.tagName.toLowerCase();
5647
- const hasChildBlocks = Array.from(item.children).some((c) => {
5648
- const ct = c.tagName.toLowerCase();
5649
- return ["p", "div", "table", "h1", "h2", "h3", "h4", "h5", "h6", "section", "article", "ul", "ol"].includes(ct);
5650
- });
5651
- if (hasChildBlocks && !["table", "tr", "td", "th", "ul", "ol", "li"].includes(tag)) {
5652
- extractBlocks(Array.from(item.children));
5653
- } else {
5654
- const fp = extractMediaFingerprint(item);
5655
- if (fp) {
5656
- if (seenInContentBlocks.has(fp)) {
5657
- continue;
5658
- }
5659
- seenInContentBlocks.add(fp);
5660
- }
5661
- const hasMedia = item.querySelector("img, svg, canvas, table") !== null || ["img", "svg", "table"].includes(tag);
5662
- const textContent = (item.textContent || "").trim();
5663
- if (!hasMedia && textContent.length === 0) {
5664
- continue;
5665
- }
5666
- const svgs = item.querySelectorAll("svg, img");
5667
- svgs.forEach((s) => {
5668
- const el = s;
5669
- el.style.maxWidth = "100%";
5670
- el.style.maxHeight = "360px";
5671
- el.style.display = "block";
5672
- el.style.margin = "12px auto";
5673
- if (s.tagName.toLowerCase() === "svg") {
5674
- s.removeAttribute("width");
5675
- s.removeAttribute("height");
5676
- el.style.width = "100%";
5677
- el.style.maxHeight = "360px";
5678
- }
5679
- });
5680
- if (tag === "p" || tag === "div") {
5681
- item.style.display = "block";
5682
- item.style.marginBottom = "12px";
5683
- item.style.lineHeight = "1.6";
5684
- }
5685
- contentNodes.push(item);
5841
+ const elements = await doc.render();
5842
+ let unsupportedIndex = 1;
5843
+ const usedTables = /* @__PURE__ */ new Set();
5844
+ for (let i = 0; i < elements.length; i++) {
5845
+ const el = elements[i];
5846
+ const text = el.textContent || "";
5847
+ if (text.includes("[Unsupported image format]")) {
5848
+ if (extractedImages[unsupportedIndex]) {
5849
+ const img = document.createElement("img");
5850
+ img.src = extractedImages[unsupportedIndex].dataUrl;
5851
+ img.style.width = "100%";
5852
+ img.style.height = "auto";
5853
+ img.style.maxHeight = "430px";
5854
+ img.style.objectFit = "contain";
5855
+ img.style.display = "block";
5856
+ img.style.margin = "12px auto";
5857
+ el.innerHTML = "";
5858
+ el.appendChild(img);
5859
+ unsupportedIndex++;
5686
5860
  }
5687
5861
  }
5688
- };
5689
- extractBlocks(htmlElements);
5690
- tables.forEach((table) => {
5691
- const tableEl = renderRtfTableElement(table);
5692
- let inserted = false;
5693
- if (table.anchorBefore && table.anchorBefore.length > 10) {
5694
- const keyword = table.anchorBefore.slice(-35).trim();
5695
- for (let i = 0; i < contentNodes.length; i++) {
5696
- if (contentNodes[i].textContent?.includes(keyword)) {
5697
- contentNodes.splice(i + 1, 0, tableEl);
5698
- inserted = true;
5699
- break;
5862
+ if (tables.length > 0) {
5863
+ for (let t = 0; t < tables.length; t++) {
5864
+ if (usedTables.has(t)) continue;
5865
+ const tbl = tables[t];
5866
+ if (tbl.rows.length >= 2) {
5867
+ const sampleCell1 = tbl.rows[1]?.[1] || tbl.rows[0]?.[1] || "";
5868
+ const sampleCell2 = tbl.rows[2]?.[1] || tbl.rows[1]?.[0] || "";
5869
+ const match1 = sampleCell1 && text.includes(sampleCell1.slice(0, 15).trim());
5870
+ const match2 = sampleCell2 && text.includes(sampleCell2.slice(0, 15).trim());
5871
+ if (match1 && match2) {
5872
+ el.innerHTML = "";
5873
+ el.appendChild(renderRtfTableElement(tbl));
5874
+ usedTables.add(t);
5875
+ break;
5876
+ }
5700
5877
  }
5701
5878
  }
5702
5879
  }
5703
- if (!inserted && table.anchorAfter && table.anchorAfter.length > 10) {
5704
- const keyword = table.anchorAfter.slice(0, 35).trim();
5705
- for (let i = 0; i < contentNodes.length; i++) {
5706
- if (contentNodes[i].textContent?.includes(keyword)) {
5707
- contentNodes.splice(i, 0, tableEl);
5708
- inserted = true;
5709
- break;
5710
- }
5711
- }
5880
+ }
5881
+ elements.forEach((el) => {
5882
+ const svgs = el.querySelectorAll ? Array.from(el.querySelectorAll("svg")) : [];
5883
+ svgs.forEach((svg) => {
5884
+ svg.removeAttribute("width");
5885
+ svg.removeAttribute("height");
5886
+ svg.style.maxWidth = "100%";
5887
+ svg.style.maxHeight = "430px";
5888
+ svg.style.height = "auto";
5889
+ svg.style.display = "block";
5890
+ svg.style.margin = "12px auto";
5891
+ });
5892
+ const imgs = el.querySelectorAll ? Array.from(el.querySelectorAll("img")) : [];
5893
+ imgs.forEach((img) => {
5894
+ img.style.maxWidth = "100%";
5895
+ img.style.maxHeight = "430px";
5896
+ img.style.height = "auto";
5897
+ img.style.objectFit = "contain";
5898
+ img.style.display = "block";
5899
+ img.style.margin = "12px auto";
5900
+ });
5901
+ });
5902
+ const allImgs = Array.from(document.querySelectorAll("img")).concat(
5903
+ elements.flatMap((el) => Array.from(el.querySelectorAll ? el.querySelectorAll("img") : []))
5904
+ );
5905
+ await Promise.all(allImgs.map((img) => {
5906
+ if (img.complete && img.naturalHeight > 0) return Promise.resolve();
5907
+ if (img.decode) return img.decode().catch(() => {
5908
+ });
5909
+ return new Promise((r) => {
5910
+ img.onload = r;
5911
+ img.onerror = r;
5912
+ });
5913
+ }));
5914
+ elements.forEach((el) => {
5915
+ const text = el.textContent || "";
5916
+ if (text.includes("\uF0B7")) {
5917
+ const cleanText = text.replace(/^[\s\uf0b7\t]+/, "");
5918
+ el.style.display = "flex";
5919
+ el.style.alignItems = "flex-start";
5920
+ el.style.margin = "6px 0 6px 28px";
5921
+ el.style.fontSize = "11pt";
5922
+ el.style.lineHeight = "1.5";
5923
+ el.innerHTML = `<span style="margin-right:10px; user-select:none;">&#9633;</span><span>${cleanText}</span>`;
5712
5924
  }
5713
- if (!inserted) {
5714
- if (contentNodes.length > 2) {
5715
- contentNodes.splice(2, 0, tableEl);
5716
- } else {
5717
- contentNodes.push(tableEl);
5718
- }
5925
+ });
5926
+ elements.forEach((el) => {
5927
+ const text = (el.textContent || "").trim();
5928
+ const hasMedia = el.querySelector("img, svg, canvas, table") !== null || ["IMG", "SVG", "TABLE"].includes(el.tagName);
5929
+ if (isHeadingElement(el)) {
5930
+ el.style.marginTop = "20px";
5931
+ el.style.marginBottom = "10px";
5932
+ el.style.lineHeight = "1.25";
5933
+ } else if (text.length > 0 && !hasMedia) {
5934
+ el.style.marginBottom = "12px";
5935
+ el.style.lineHeight = "1.45";
5719
5936
  }
5720
5937
  });
5721
- const createRtfCard = (pageNum) => {
5938
+ const measureCard = document.createElement("div");
5939
+ measureCard.style.width = `${pageWidth}px`;
5940
+ measureCard.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
5941
+ measureCard.style.boxSizing = "border-box";
5942
+ measureCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5943
+ measureCard.style.lineHeight = "1.45";
5944
+ measureCard.style.visibility = "hidden";
5945
+ measureCard.style.position = "absolute";
5946
+ measureCard.style.top = "-99999px";
5947
+ document.body.appendChild(measureCard);
5948
+ const createPageCard = (num) => {
5722
5949
  const card = document.createElement("div");
5723
5950
  card.className = "fp-rtf-page-card";
5724
- card.setAttribute("data-page-number", String(pageNum));
5951
+ card.setAttribute("data-page-number", String(num));
5725
5952
  card.style.backgroundColor = "#ffffff";
5726
5953
  card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08), 0 1px 3px rgba(0,0,0,0.04)";
5727
5954
  card.style.borderRadius = "4px";
5728
- card.style.padding = "64px 56px";
5729
- card.style.width = "816px";
5730
- card.style.minHeight = "1056px";
5731
- card.style.maxHeight = "1056px";
5732
- card.style.overflow = "hidden";
5955
+ card.style.width = `${pageWidth}px`;
5956
+ card.style.height = `${pageHeight}px`;
5957
+ card.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
5733
5958
  card.style.boxSizing = "border-box";
5959
+ card.style.overflow = "hidden";
5734
5960
  card.style.marginBottom = "24px";
5735
- card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5736
- card.style.lineHeight = "1.6";
5737
5961
  card.style.color = "#1e293b";
5962
+ card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5963
+ card.style.lineHeight = "1.45";
5738
5964
  card.style.position = "relative";
5965
+ card.style.textAlign = "left";
5739
5966
  return card;
5740
5967
  };
5741
- wrapper.innerHTML = "";
5742
- const measureCard = createRtfCard(0);
5743
- measureCard.style.maxHeight = "none";
5744
- measureCard.style.height = "auto";
5745
- wrapper.appendChild(measureCard);
5746
- contentNodes.forEach((node) => measureCard.appendChild(node));
5747
- const childHeights = contentNodes.map((c) => {
5748
- const rect = c.getBoundingClientRect ? c.getBoundingClientRect() : null;
5749
- const rectH = rect ? rect.height : 0;
5750
- const offH = c.offsetHeight || 0;
5751
- let realH = Math.max(rectH, offH);
5752
- try {
5753
- const cs = window.getComputedStyle(c);
5754
- realH += (parseFloat(cs.marginTop) || 0) + (parseFloat(cs.marginBottom) || 0);
5755
- } catch {
5756
- }
5757
- const hasMedia = c.querySelector("img, svg") !== null || ["img", "svg"].includes(c.tagName.toLowerCase());
5758
- const hasTable = c.querySelector("table") !== null || c.tagName.toLowerCase() === "table";
5759
- if (hasMedia) {
5760
- realH = Math.max(realH, 300);
5761
- } else if (hasTable) {
5762
- realH = Math.max(realH, 240);
5763
- }
5764
- if (realH > 0) return realH;
5765
- const textLen = c.textContent?.trim().length || 0;
5766
- return Math.max(28, Math.ceil(textLen / 75) * 26 + 16);
5767
- });
5768
- wrapper.innerHTML = "";
5769
- let curCard = createRtfCard(1);
5770
- wrapper.appendChild(curCard);
5771
- pageElements = [curCard];
5772
- let curH = 0;
5773
- const maxH = 860;
5774
- for (let i = 0; i < contentNodes.length; i++) {
5775
- const child = contentNodes[i];
5776
- const chH = childHeights[i];
5777
- const isChildEmpty = (child.textContent || "").trim().length === 0 && !child.querySelector("table, img, svg, canvas");
5778
- if (curH === 0 && isChildEmpty) {
5968
+ const pages = [];
5969
+ let curCard = createPageCard(1);
5970
+ pages.push(curCard);
5971
+ let curHeight = 0;
5972
+ for (let i = 0; i < elements.length; i++) {
5973
+ const el = elements[i];
5974
+ if (!el || !(el instanceof HTMLElement)) continue;
5975
+ const text = (el.textContent || "").trim();
5976
+ const hasMedia = el.querySelector("img, svg, canvas, table") !== null || ["IMG", "SVG", "TABLE"].includes(el.tagName);
5977
+ const isEmptyPar = !hasMedia && text.length === 0;
5978
+ if (isEmptyPar) {
5979
+ const emptyH = 35;
5980
+ if (curHeight + emptyH > printableHeight) {
5981
+ if (curCard.childNodes.length > 0) {
5982
+ curCard = createPageCard(pages.length + 1);
5983
+ pages.push(curCard);
5984
+ curHeight = 0;
5985
+ }
5986
+ }
5987
+ const spacer = document.createElement("div");
5988
+ spacer.style.height = `${emptyH}px`;
5989
+ curCard.appendChild(spacer);
5990
+ curHeight += emptyH;
5779
5991
  continue;
5780
5992
  }
5781
- const isTable = child.querySelector("table") !== null || child.tagName.toLowerCase() === "table";
5782
- const shouldBreakBeforeTable = isTable && curH > 400 && curCard.childNodes.length > 0;
5783
- if ((curH + chH > maxH || shouldBreakBeforeTable) && curCard.childNodes.length > 0) {
5784
- curCard = createRtfCard(pageElements.length + 1);
5785
- wrapper.appendChild(curCard);
5786
- pageElements.push(curCard);
5787
- curH = 0;
5993
+ measureCard.innerHTML = "";
5994
+ const clone = el.cloneNode(true);
5995
+ measureCard.appendChild(clone);
5996
+ const compStyle = window.getComputedStyle(clone);
5997
+ const mt = parseFloat(compStyle.marginTop) || 0;
5998
+ const mb = parseFloat(compStyle.marginBottom) || 0;
5999
+ const elH = clone.offsetHeight + mt + mb;
6000
+ const isHeading = isHeadingElement(el);
6001
+ let nextContentH = 0;
6002
+ if (isHeading || hasMedia) {
6003
+ for (let j = i + 1; j < elements.length; j++) {
6004
+ const nextEl = elements[j];
6005
+ if (nextEl && (nextEl.textContent || "").trim().length > 0) {
6006
+ measureCard.innerHTML = "";
6007
+ const nClone = nextEl.cloneNode(true);
6008
+ measureCard.appendChild(nClone);
6009
+ const nStyle = window.getComputedStyle(nClone);
6010
+ nextContentH = nClone.offsetHeight + (parseFloat(nStyle.marginTop) || 0) + (parseFloat(nStyle.marginBottom) || 0);
6011
+ break;
6012
+ }
6013
+ }
5788
6014
  }
5789
- curCard.appendChild(child);
5790
- curH += chH;
5791
- }
5792
- pageElements = pageElements.filter((card) => {
6015
+ const remainingSpace = printableHeight - curHeight;
6016
+ const isLargeMedia = hasMedia && elH > 300;
6017
+ const keepWithNextOverflow = isHeading && nextContentH > 0 && elH + nextContentH + 20 > remainingSpace;
6018
+ const largeMediaOverflow = isLargeMedia && curHeight > 0 && elH + 80 > remainingSpace;
6019
+ const shouldBreak = (curHeight + elH > printableHeight || keepWithNextOverflow || largeMediaOverflow) && curCard.childNodes.length > 0;
6020
+ if (shouldBreak) {
6021
+ curCard = createPageCard(pages.length + 1);
6022
+ pages.push(curCard);
6023
+ curHeight = 0;
6024
+ }
6025
+ curCard.appendChild(el);
6026
+ curHeight += elH;
6027
+ }
6028
+ measureCard.remove();
6029
+ pageElements = pages.filter((card) => {
5793
6030
  const hasText = (card.textContent || "").trim().length > 0;
5794
- const hasMedia = card.querySelector("table, img, svg, canvas") !== null;
5795
- return hasText || hasMedia;
6031
+ const hasCardMedia = card.querySelector("table, img, svg, canvas") !== null;
6032
+ return hasText || hasCardMedia;
5796
6033
  });
5797
6034
  if (pageElements.length === 0) {
5798
6035
  pageElements = [curCard];
5799
6036
  }
6037
+ wrapper.innerHTML = "";
6038
+ pageElements.forEach((card, idx) => {
6039
+ card.setAttribute("data-page-number", String(idx + 1));
6040
+ card.style.display = idx === 0 ? "block" : "none";
6041
+ wrapper.appendChild(card);
6042
+ });
5800
6043
  } catch (err) {
5801
6044
  console.warn("[RtfPlugin] RTF render error, fallback text:", err);
5802
- const text = new TextDecoder("latin1").decode(ctx.buffer);
5803
- const tables = parseRtfTables(text);
6045
+ const text = rawRtf;
5804
6046
  const rawPages = text.split(/\\page\b/).map((segment) => {
5805
6047
  return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
5806
- }).filter((p) => p.length > 0);
6048
+ }).filter((p2) => p2.length > 0);
5807
6049
  const pages = rawPages.length > 0 ? rawPages : [text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim()];
5808
6050
  for (let i = 0; i < pages.length; i++) {
5809
6051
  const pageCard = document.createElement("div");
@@ -5811,9 +6053,9 @@ var RtfPlugin = class {
5811
6053
  pageCard.style.backgroundColor = "#ffffff";
5812
6054
  pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
5813
6055
  pageCard.style.borderRadius = "4px";
5814
- pageCard.style.padding = "64px 56px";
5815
- pageCard.style.width = "816px";
5816
- pageCard.style.minHeight = "1056px";
6056
+ pageCard.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
6057
+ pageCard.style.width = `${pageWidth}px`;
6058
+ pageCard.style.minHeight = `${pageHeight}px`;
5817
6059
  pageCard.style.boxSizing = "border-box";
5818
6060
  pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5819
6061
  pageCard.style.fontSize = "12pt";
@@ -5833,11 +6075,9 @@ var RtfPlugin = class {
5833
6075
  let currentPage = 1;
5834
6076
  const showPage = (pageNum) => {
5835
6077
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
5836
- if (totalPages > 1) {
5837
- pageElements.forEach((el, idx) => {
5838
- el.style.display = idx + 1 === currentPage ? "block" : "none";
5839
- });
5840
- }
6078
+ pageElements.forEach((el, idx) => {
6079
+ el.style.display = idx + 1 === currentPage ? "block" : "none";
6080
+ });
5841
6081
  ctx.container.scrollTop = 0;
5842
6082
  ctx.emit("page-change", { page: currentPage, total: totalPages });
5843
6083
  };
@@ -5904,6 +6144,15 @@ var RtfPlugin = class {
5904
6144
  rotation = 0;
5905
6145
  applyTransform();
5906
6146
  },
6147
+ resetZoom: () => {
6148
+ isUserZoomed = false;
6149
+ fitMode = "width";
6150
+ scale = calculateFitScale("width");
6151
+ rotation = 0;
6152
+ ctx.container.scrollTop = 0;
6153
+ ctx.container.scrollLeft = 0;
6154
+ applyTransform();
6155
+ },
5907
6156
  rotateCW: () => {
5908
6157
  rotation = (rotation + 90) % 360;
5909
6158
  applyTransform();
@@ -5971,6 +6220,14 @@ var HtmlPreviewPlugin = class {
5971
6220
  group: "zoom",
5972
6221
  execute: () => instance.fitToPage?.()
5973
6222
  },
6223
+ {
6224
+ id: "reset-zoom",
6225
+ icon: "reset-zoom",
6226
+ label: "Reset Zoom",
6227
+ type: "button",
6228
+ group: "zoom",
6229
+ execute: () => instance.resetZoom?.()
6230
+ },
5974
6231
  {
5975
6232
  id: "copy",
5976
6233
  icon: "copy",
@@ -6043,6 +6300,12 @@ var HtmlPreviewPlugin = class {
6043
6300
  scale = 1;
6044
6301
  iframe.style.transform = "scale(1)";
6045
6302
  },
6303
+ resetZoom: () => {
6304
+ scale = 1;
6305
+ iframe.style.transform = "scale(1)";
6306
+ ctx.container.scrollTop = 0;
6307
+ ctx.container.scrollLeft = 0;
6308
+ },
6046
6309
  copy: () => {
6047
6310
  navigator.clipboard.writeText(rawHtml);
6048
6311
  },
@@ -6143,6 +6406,14 @@ var OpenDocumentPlugin = class {
6143
6406
  group: "zoom",
6144
6407
  execute: () => instance.fitToPage?.()
6145
6408
  },
6409
+ {
6410
+ id: "reset-zoom",
6411
+ icon: "reset-zoom",
6412
+ label: "Reset Zoom",
6413
+ type: "button",
6414
+ group: "zoom",
6415
+ execute: () => instance.resetZoom?.()
6416
+ },
6146
6417
  {
6147
6418
  id: "rotate-cw",
6148
6419
  icon: "rotate-cw",
@@ -6410,6 +6681,15 @@ var OpenDocumentPlugin = class {
6410
6681
  rotation = 0;
6411
6682
  applyTransform();
6412
6683
  },
6684
+ resetZoom: () => {
6685
+ isUserZoomed = false;
6686
+ fitMode = "width";
6687
+ scale = calculateFitScale("width");
6688
+ rotation = 0;
6689
+ container.scrollTop = 0;
6690
+ container.scrollLeft = 0;
6691
+ applyTransform();
6692
+ },
6413
6693
  rotateCW: () => {
6414
6694
  rotation = (rotation + 90) % 360;
6415
6695
  applyTransform();
@@ -6753,6 +7033,14 @@ var DocPlugin = class {
6753
7033
  group: "zoom",
6754
7034
  execute: () => instance.fitToPage?.()
6755
7035
  },
7036
+ {
7037
+ id: "reset-zoom",
7038
+ icon: "reset-zoom",
7039
+ label: "Reset Zoom",
7040
+ type: "button",
7041
+ group: "zoom",
7042
+ execute: () => instance.resetZoom?.()
7043
+ },
6756
7044
  {
6757
7045
  id: "rotate-cw",
6758
7046
  icon: "rotate-cw",
@@ -6959,6 +7247,15 @@ var DocPlugin = class {
6959
7247
  rotation = 0;
6960
7248
  applyTransform();
6961
7249
  },
7250
+ resetZoom: () => {
7251
+ isUserZoomed = false;
7252
+ fitMode = "width";
7253
+ scale = calculateFitScale("width");
7254
+ rotation = 0;
7255
+ ctx.container.scrollTop = 0;
7256
+ ctx.container.scrollLeft = 0;
7257
+ applyTransform();
7258
+ },
6962
7259
  rotateCW: () => {
6963
7260
  rotation = (rotation + 90) % 360;
6964
7261
  applyTransform();
@@ -7439,6 +7736,14 @@ var PptPlugin = class {
7439
7736
  group: "zoom",
7440
7737
  execute: () => instance.fitToPage?.()
7441
7738
  },
7739
+ {
7740
+ id: "reset-zoom",
7741
+ icon: "reset-zoom",
7742
+ label: "Reset Zoom",
7743
+ type: "button",
7744
+ group: "zoom",
7745
+ execute: () => instance.resetZoom?.()
7746
+ },
7442
7747
  {
7443
7748
  id: "rotate-cw",
7444
7749
  icon: "rotate-cw",
@@ -7627,6 +7932,13 @@ var PptPlugin = class {
7627
7932
  rotation = 0;
7628
7933
  applyTransform();
7629
7934
  },
7935
+ resetZoom: () => {
7936
+ scale = calculateFitScale();
7937
+ rotation = 0;
7938
+ container.scrollTop = 0;
7939
+ container.scrollLeft = 0;
7940
+ applyTransform();
7941
+ },
7630
7942
  rotateCW: () => {
7631
7943
  rotation = (rotation + 90) % 360;
7632
7944
  applyTransform();