@files-preview-app/preview-file 1.3.4 → 1.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.js CHANGED
@@ -496,6 +496,7 @@ var ICON_COPY = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" str
496
496
  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>`;
497
497
  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>`;
498
498
  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>`;
499
+ 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>`;
499
500
  var ICON_MAP = {
500
501
  "zoom-in": ICON_ZOOM_IN,
501
502
  "zoom-out": ICON_ZOOM_OUT,
@@ -525,7 +526,10 @@ var ICON_MAP = {
525
526
  "open-window": ICON_EXTERNAL_WINDOW,
526
527
  "external-window": ICON_EXTERNAL_WINDOW,
527
528
  "openWindow": ICON_EXTERNAL_WINDOW,
528
- "openSeparateWindow": ICON_EXTERNAL_WINDOW
529
+ "openSeparateWindow": ICON_EXTERNAL_WINDOW,
530
+ "reset-zoom": ICON_RESET_ZOOM,
531
+ "zoom-reset": ICON_RESET_ZOOM,
532
+ "resetZoom": ICON_RESET_ZOOM
529
533
  };
530
534
  var ToolbarController = class {
531
535
  el;
@@ -558,6 +562,10 @@ var ToolbarController = class {
558
562
  this.config.fitToPage = false;
559
563
  this.config.fitWidth = false;
560
564
  }
565
+ if (actionId === "reset-zoom" || actionId === "zoom-reset" || actionId === "resetZoom") {
566
+ this.config.resetZoom = false;
567
+ this.config.zoomReset = false;
568
+ }
561
569
  if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = false;
562
570
  if (actionId === "fullscreen") this.config.fullscreen = false;
563
571
  if (actionId === "download") this.config.download = false;
@@ -582,6 +590,10 @@ var ToolbarController = class {
582
590
  this.config.fitToPage = true;
583
591
  this.config.fitWidth = true;
584
592
  }
593
+ if (actionId === "reset-zoom" || actionId === "zoom-reset" || actionId === "resetZoom") {
594
+ this.config.resetZoom = true;
595
+ this.config.zoomReset = true;
596
+ }
585
597
  if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = true;
586
598
  if (actionId === "fullscreen") this.config.fullscreen = true;
587
599
  if (actionId === "download") this.config.download = true;
@@ -601,6 +613,7 @@ var ToolbarController = class {
601
613
  if (actionId === "zoomIn") return "zoom-in";
602
614
  if (actionId === "zoomOut") return "zoom-out";
603
615
  if (actionId === "fitPage" || actionId === "fitToPage" || actionId === "fitWidth") return "fit-page";
616
+ if (actionId === "resetZoom" || actionId === "zoomReset") return "reset-zoom";
604
617
  if (actionId === "rotateCW") return "rotate-cw";
605
618
  if (actionId === "rotateCCW") return "rotate-ccw";
606
619
  if (actionId === "openWindow" || actionId === "openSeparateWindow") return "open-window";
@@ -643,6 +656,9 @@ var ToolbarController = class {
643
656
  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)) {
644
657
  return false;
645
658
  }
659
+ if ((id === "reset-zoom" || id === "zoom-reset") && (c.resetZoom === false || c.zoomReset === false || c["reset-zoom"] === false || c["zoom-reset"] === false)) {
660
+ return false;
661
+ }
646
662
  if ((id === "rotate-cw" || id === "rotate-ccw" || id === "rotate") && (c.rotate === false || c.rotateCW === false || c.rotateCCW === false || c["rotate-cw"] === false)) {
647
663
  return false;
648
664
  }
@@ -1089,6 +1105,9 @@ var FilePreviewViewer = class _FilePreviewViewer {
1089
1105
  this.activeInstance = instance;
1090
1106
  instance.openInSeparateWindow = () => this.openInSeparateWindow();
1091
1107
  instance.toggleThumbnails = () => this.toggleThumbnails();
1108
+ if (!instance.resetZoom && instance.fitToPage) {
1109
+ instance.resetZoom = () => instance.fitToPage?.();
1110
+ }
1092
1111
  this.hideLoading();
1093
1112
  this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
1094
1113
  const isToolbarVisible = options.showToolbar !== false && options.toolbar !== false;
@@ -1372,6 +1391,16 @@ var FilePreviewViewer = class _FilePreviewViewer {
1372
1391
  fitToPage() {
1373
1392
  this.activeInstance?.fitToPage?.();
1374
1393
  }
1394
+ /**
1395
+ * Reset zoom level to initial/default fit state.
1396
+ */
1397
+ resetZoom() {
1398
+ if (this.activeInstance?.resetZoom) {
1399
+ this.activeInstance.resetZoom();
1400
+ } else if (this.activeInstance?.fitToPage) {
1401
+ this.activeInstance.fitToPage();
1402
+ }
1403
+ }
1375
1404
  /**
1376
1405
  * Zoom in.
1377
1406
  */
@@ -1993,6 +2022,14 @@ var PdfPlugin = class {
1993
2022
  group: "zoom",
1994
2023
  execute: () => instance.fitToPage?.()
1995
2024
  },
2025
+ {
2026
+ id: "reset-zoom",
2027
+ icon: "reset-zoom",
2028
+ label: "Reset Zoom",
2029
+ type: "button",
2030
+ group: "zoom",
2031
+ execute: () => instance.resetZoom?.()
2032
+ },
1996
2033
  {
1997
2034
  id: "fit-width",
1998
2035
  icon: "fit-width",
@@ -2255,6 +2292,14 @@ var PdfPlugin = class {
2255
2292
  zoomScale = 1;
2256
2293
  renderPage(currentPage);
2257
2294
  },
2295
+ resetZoom: () => {
2296
+ fitMode = "page";
2297
+ zoomScale = 1;
2298
+ rotation = 0;
2299
+ container.scrollTop = 0;
2300
+ container.scrollLeft = 0;
2301
+ renderPage(currentPage);
2302
+ },
2258
2303
  fitToWidth: () => {
2259
2304
  fitMode = "width";
2260
2305
  zoomScale = 1;
@@ -2422,6 +2467,16 @@ var MediaPlugin = class {
2422
2467
  instance.fitToPage?.();
2423
2468
  }
2424
2469
  },
2470
+ {
2471
+ id: "reset-zoom",
2472
+ icon: "reset-zoom",
2473
+ label: "Reset Zoom",
2474
+ type: "button",
2475
+ group: "zoom",
2476
+ execute: () => {
2477
+ instance.resetZoom?.();
2478
+ }
2479
+ },
2425
2480
  {
2426
2481
  id: "rotate-cw",
2427
2482
  icon: "rotate-cw",
@@ -2595,6 +2650,13 @@ var MediaPlugin = class {
2595
2650
  rotation = 0;
2596
2651
  applyTransform();
2597
2652
  } : void 0,
2653
+ resetZoom: isImage ? () => {
2654
+ currentZoom = 1;
2655
+ rotation = 0;
2656
+ ctx.container.scrollTop = 0;
2657
+ ctx.container.scrollLeft = 0;
2658
+ applyTransform();
2659
+ } : void 0,
2598
2660
  rotateCW: isImage || isVideo ? () => {
2599
2661
  rotation = (rotation + 90) % 360;
2600
2662
  applyTransform();
@@ -2711,6 +2773,14 @@ var DocxPlugin = class {
2711
2773
  group: "zoom",
2712
2774
  execute: () => instance.fitToPage?.()
2713
2775
  },
2776
+ {
2777
+ id: "reset-zoom",
2778
+ icon: "reset-zoom",
2779
+ label: "Reset Zoom",
2780
+ type: "button",
2781
+ group: "zoom",
2782
+ execute: () => instance.resetZoom?.()
2783
+ },
2714
2784
  {
2715
2785
  id: "rotate-cw",
2716
2786
  icon: "rotate-cw",
@@ -3027,6 +3097,14 @@ var DocxPlugin = class {
3027
3097
  rotation = 0;
3028
3098
  applyTransform();
3029
3099
  },
3100
+ resetZoom: () => {
3101
+ isUserZoomed = false;
3102
+ scale = calculateFitScale("page");
3103
+ rotation = 0;
3104
+ ctx.container.scrollTop = 0;
3105
+ ctx.container.scrollLeft = 0;
3106
+ applyTransform();
3107
+ },
3030
3108
  rotateCW: () => {
3031
3109
  rotation = (rotation + 90) % 360;
3032
3110
  applyTransform();
@@ -3476,6 +3554,16 @@ var ExcelPlugin = class {
3476
3554
  instance.zoomIn?.();
3477
3555
  }
3478
3556
  },
3557
+ {
3558
+ id: "reset-zoom",
3559
+ icon: "reset-zoom",
3560
+ label: "Reset Zoom",
3561
+ type: "button",
3562
+ group: "zoom",
3563
+ execute: () => {
3564
+ instance.resetZoom?.();
3565
+ }
3566
+ },
3479
3567
  {
3480
3568
  id: "download",
3481
3569
  icon: "download",
@@ -3663,6 +3751,12 @@ var ExcelPlugin = class {
3663
3751
  scale = calculateFitScale();
3664
3752
  applyTransform();
3665
3753
  },
3754
+ resetZoom: () => {
3755
+ scale = calculateFitScale();
3756
+ contentArea.scrollTop = 0;
3757
+ contentArea.scrollLeft = 0;
3758
+ applyTransform();
3759
+ },
3666
3760
  rotateCW: () => {
3667
3761
  },
3668
3762
  rotateCCW: () => {
@@ -3793,6 +3887,16 @@ var CsvPlugin = class {
3793
3887
  instance.zoomIn?.();
3794
3888
  }
3795
3889
  },
3890
+ {
3891
+ id: "reset-zoom",
3892
+ icon: "reset-zoom",
3893
+ label: "Reset Zoom",
3894
+ type: "button",
3895
+ group: "zoom",
3896
+ execute: () => {
3897
+ instance.resetZoom?.();
3898
+ }
3899
+ },
3796
3900
  {
3797
3901
  id: "download",
3798
3902
  icon: "download",
@@ -3982,6 +4086,12 @@ var CsvPlugin = class {
3982
4086
  scale = calculateFitScale();
3983
4087
  applyScale();
3984
4088
  },
4089
+ resetZoom: () => {
4090
+ scale = calculateFitScale();
4091
+ container.scrollTop = 0;
4092
+ container.scrollLeft = 0;
4093
+ applyScale();
4094
+ },
3985
4095
  rotateCW: () => {
3986
4096
  },
3987
4097
  rotateCCW: () => {
@@ -4097,6 +4207,16 @@ var CodePlugin = class {
4097
4207
  instance.zoomIn?.();
4098
4208
  }
4099
4209
  },
4210
+ {
4211
+ id: "reset-zoom",
4212
+ icon: "reset-zoom",
4213
+ label: "Reset Zoom",
4214
+ type: "button",
4215
+ group: "zoom",
4216
+ execute: () => {
4217
+ instance.resetZoom?.();
4218
+ }
4219
+ },
4100
4220
  {
4101
4221
  id: "copy",
4102
4222
  icon: "copy",
@@ -4376,6 +4496,15 @@ var CodePlugin = class {
4376
4496
  zoomLevel = isTxt ? calculateTxtFit() : 1;
4377
4497
  updateTransform();
4378
4498
  },
4499
+ resetZoom: () => {
4500
+ isUserZoomed = false;
4501
+ fontSize = 13;
4502
+ rotation = 0;
4503
+ zoomLevel = isTxt ? calculateTxtFit() : 1;
4504
+ container.scrollTop = 0;
4505
+ container.scrollLeft = 0;
4506
+ updateTransform();
4507
+ },
4379
4508
  rotateCW: () => {
4380
4509
  rotation = (rotation + 90) % 360;
4381
4510
  updateTransform();
@@ -4438,11 +4567,19 @@ var ArchivePlugin = class {
4438
4567
  {
4439
4568
  id: "fit-page",
4440
4569
  icon: "fit-page",
4441
- label: "Reset Zoom",
4570
+ label: "Fit to Page",
4442
4571
  type: "button",
4443
4572
  group: "zoom",
4444
4573
  execute: () => instance.fitToPage?.()
4445
4574
  },
4575
+ {
4576
+ id: "reset-zoom",
4577
+ icon: "reset-zoom",
4578
+ label: "Reset Zoom",
4579
+ type: "button",
4580
+ group: "zoom",
4581
+ execute: () => instance.resetZoom?.()
4582
+ },
4446
4583
  {
4447
4584
  id: "download",
4448
4585
  icon: "download",
@@ -4597,7 +4734,13 @@ var ArchivePlugin = class {
4597
4734
  },
4598
4735
  fitToPage: () => {
4599
4736
  scale = 1;
4600
- wrapper.style.transform = `scale(1)`;
4737
+ wrapper.style.transform = "scale(1)";
4738
+ },
4739
+ resetZoom: () => {
4740
+ scale = 1;
4741
+ wrapper.style.transform = "scale(1)";
4742
+ ctx.container.scrollTop = 0;
4743
+ ctx.container.scrollLeft = 0;
4601
4744
  },
4602
4745
  download: () => {
4603
4746
  downloadFile(ctx.buffer, ctx.metadata.name || "archive.zip", "application/zip");
@@ -4649,6 +4792,14 @@ var MarkdownPlugin = class {
4649
4792
  group: "zoom",
4650
4793
  execute: () => instance.fitToPage?.()
4651
4794
  },
4795
+ {
4796
+ id: "reset-zoom",
4797
+ icon: "reset-zoom",
4798
+ label: "Reset Zoom",
4799
+ type: "button",
4800
+ group: "zoom",
4801
+ execute: () => instance.resetZoom?.()
4802
+ },
4652
4803
  {
4653
4804
  id: "copy",
4654
4805
  icon: "copy",
@@ -4802,6 +4953,12 @@ var MarkdownPlugin = class {
4802
4953
  fontSize = 15;
4803
4954
  wrapper.style.fontSize = "15px";
4804
4955
  },
4956
+ resetZoom: () => {
4957
+ fontSize = 15;
4958
+ wrapper.style.fontSize = "15px";
4959
+ ctx.container.scrollTop = 0;
4960
+ ctx.container.scrollLeft = 0;
4961
+ },
4805
4962
  download: () => {
4806
4963
  downloadFile(ctx.buffer, ctx.metadata.name || "document.md", "text/markdown");
4807
4964
  },
@@ -4895,6 +5052,14 @@ var PptxPlugin = class {
4895
5052
  group: "zoom",
4896
5053
  execute: () => instance.fitToPage?.()
4897
5054
  },
5055
+ {
5056
+ id: "reset-zoom",
5057
+ icon: "reset-zoom",
5058
+ label: "Reset Zoom",
5059
+ type: "button",
5060
+ group: "zoom",
5061
+ execute: () => instance.resetZoom?.()
5062
+ },
4898
5063
  {
4899
5064
  id: "rotate-cw",
4900
5065
  icon: "rotate-cw",
@@ -5014,6 +5179,13 @@ var PptxPlugin = class {
5014
5179
  rotation = 0;
5015
5180
  applyTransform();
5016
5181
  },
5182
+ resetZoom: () => {
5183
+ scale = calculateFitScale();
5184
+ rotation = 0;
5185
+ wrapper.scrollTop = 0;
5186
+ wrapper.scrollLeft = 0;
5187
+ applyTransform();
5188
+ },
5017
5189
  rotateCW: () => {
5018
5190
  rotation = (rotation + 90) % 360;
5019
5191
  applyTransform();
@@ -5089,6 +5261,14 @@ var ThreeDPlugin = class {
5089
5261
  group: "zoom",
5090
5262
  execute: () => instance.fitToPage?.()
5091
5263
  },
5264
+ {
5265
+ id: "reset-zoom",
5266
+ icon: "reset-zoom",
5267
+ label: "Reset Zoom",
5268
+ type: "button",
5269
+ group: "zoom",
5270
+ execute: () => instance.resetZoom?.()
5271
+ },
5092
5272
  {
5093
5273
  id: "rotate-cw",
5094
5274
  icon: "rotate-cw",
@@ -5225,6 +5405,7 @@ var ThreeDPlugin = class {
5225
5405
  controls.update();
5226
5406
  },
5227
5407
  fitToPage: fitCamera,
5408
+ resetZoom: fitCamera,
5228
5409
  rotateCW: () => {
5229
5410
  isWireframe = !isWireframe;
5230
5411
  materials.forEach((m) => {
@@ -5247,7 +5428,7 @@ function cleanRtfText(raw) {
5247
5428
  return String.fromCharCode(num);
5248
5429
  }).replace(/\\'([0-9a-fA-F]{2})/g, (_, hex) => {
5249
5430
  return String.fromCharCode(parseInt(hex, 16));
5250
- }).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();
5431
+ }).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();
5251
5432
  }
5252
5433
  function parseRtfTables(rtfText) {
5253
5434
  const rowSegments = rtfText.split(/\\row\b/);
@@ -5287,17 +5468,12 @@ function parseRtfTables(rtfText) {
5287
5468
  }
5288
5469
  const isNewTable = !currentTable || segmentStart - currentTable.lastEnd > 2500;
5289
5470
  if (isNewTable) {
5290
- const prevTextSlice = rtfText.slice(Math.max(0, segmentStart - 4e3), segmentStart);
5291
- const cleanPrev = cleanRtfText(prevTextSlice);
5292
- const anchorBefore = cleanPrev.slice(-80).trim();
5293
5471
  currentTable = {
5294
5472
  id: `RTF_TABLE_${rawTables.length}`,
5295
5473
  startPos: segmentStart,
5296
5474
  lastEnd: segmentEnd,
5297
5475
  rows: [],
5298
- columnWidths: cellWidths,
5299
- anchorBefore,
5300
- anchorAfter: ""
5476
+ columnWidths: cellWidths
5301
5477
  };
5302
5478
  rawTables.push(currentTable);
5303
5479
  }
@@ -5311,20 +5487,13 @@ function parseRtfTables(rtfText) {
5311
5487
  }
5312
5488
  charOffset += segment.length + 4;
5313
5489
  }
5314
- rawTables.forEach((tbl) => {
5315
- const afterSlice = rtfText.slice(tbl.lastEnd, Math.min(rtfText.length, tbl.lastEnd + 2e3));
5316
- const cleanAfter = cleanRtfText(afterSlice);
5317
- tbl.anchorAfter = cleanAfter.slice(0, 80).trim();
5318
- });
5319
5490
  return rawTables.map((tbl) => {
5320
5491
  const totalW = (tbl.columnWidths || []).reduce((a, b) => a + b, 0);
5321
5492
  const colPercents = totalW > 0 ? tbl.columnWidths.map((w) => Math.round(w / totalW * 100)) : [];
5322
5493
  return {
5323
5494
  id: tbl.id,
5324
5495
  rows: tbl.rows.map((r) => r.cells),
5325
- colPercents,
5326
- anchorBefore: tbl.anchorBefore,
5327
- anchorAfter: tbl.anchorAfter
5496
+ colPercents
5328
5497
  };
5329
5498
  });
5330
5499
  }
@@ -5337,8 +5506,6 @@ function renderRtfTableElement(table) {
5337
5506
  tableEl.style.fontSize = "10pt";
5338
5507
  tableEl.style.lineHeight = "1.5";
5339
5508
  tableEl.style.border = "1px solid #cbd5e1";
5340
- tableEl.style.borderRadius = "4px";
5341
- tableEl.style.boxSizing = "border-box";
5342
5509
  tableEl.style.backgroundColor = "#ffffff";
5343
5510
  const thead = document.createElement("thead");
5344
5511
  const tbody = document.createElement("tbody");
@@ -5347,27 +5514,17 @@ function renderRtfTableElement(table) {
5347
5514
  const isHeader = rIdx === 0;
5348
5515
  if (isHeader) {
5349
5516
  tr.style.backgroundColor = "#f8fafc";
5350
- tr.style.borderBottom = "2px solid #cbd5e1";
5351
- } else {
5352
- tr.style.borderBottom = "1px solid #e2e8f0";
5353
- if (rIdx % 2 === 0) {
5354
- tr.style.backgroundColor = "#fcfdfe";
5355
- }
5356
5517
  }
5357
5518
  rowCells.forEach((cellText, cIdx) => {
5358
5519
  const cellEl = document.createElement(isHeader ? "th" : "td");
5359
5520
  cellEl.style.padding = "8px 12px";
5360
5521
  cellEl.style.border = "1px solid #cbd5e1";
5361
5522
  cellEl.style.verticalAlign = "top";
5362
- cellEl.style.color = isHeader ? "#0f172a" : "#1e293b";
5363
- cellEl.style.fontWeight = isHeader ? "600" : "normal";
5364
5523
  if (table.colPercents && table.colPercents[cIdx]) {
5365
5524
  cellEl.style.width = `${table.colPercents[cIdx]}%`;
5366
5525
  }
5367
5526
  if (/^\d+$/.test(cellText.trim()) || cellText.trim() === "#") {
5368
5527
  cellEl.style.textAlign = "center";
5369
- } else {
5370
- cellEl.style.textAlign = "left";
5371
5528
  }
5372
5529
  cellEl.textContent = cellText;
5373
5530
  tr.appendChild(cellEl);
@@ -5382,23 +5539,19 @@ function renderRtfTableElement(table) {
5382
5539
  tableEl.appendChild(tbody);
5383
5540
  return tableEl;
5384
5541
  }
5385
- function extractMediaFingerprint(el) {
5386
- const img = el.tagName.toLowerCase() === "img" ? el : el.querySelector("img");
5387
- if (img && img.src) {
5388
- const s = img.src;
5389
- return s.length > 300 ? `img_${s.slice(0, 80)}_${s.length}_${s.slice(-80)}` : `img_${s}`;
5390
- }
5391
- const innerImg = el.querySelector("image");
5392
- if (innerImg) {
5393
- const h = innerImg.getAttribute("xlink:href") || innerImg.getAttribute("href") || "";
5394
- if (h) return h.length > 300 ? `svgimg_${h.slice(0, 80)}_${h.length}_${h.slice(-80)}` : `svgimg_${h}`;
5395
- }
5396
- const svg = el.tagName.toLowerCase() === "svg" ? el : el.querySelector("svg");
5397
- if (svg) {
5398
- const vb = svg.getAttribute("viewBox") || "";
5399
- return `svg_${vb}_${svg.innerHTML.length}`;
5400
- }
5401
- return null;
5542
+ function isHeadingElement(el) {
5543
+ if (["H1", "H2", "H3", "H4"].includes(el.tagName)) return true;
5544
+ const spans = el.querySelectorAll ? Array.from(el.querySelectorAll("span, b, strong, div")) : [];
5545
+ for (const s of spans) {
5546
+ const hEl = s;
5547
+ const fs = parseFloat(hEl.style.fontSize) || 0;
5548
+ const isBold = hEl.style.fontWeight === "bold" || parseInt(hEl.style.fontWeight, 10) >= 600 || ["B", "STRONG"].includes(hEl.tagName);
5549
+ if (isBold && fs >= 14) return true;
5550
+ }
5551
+ const elFs = parseFloat(el.style.fontSize) || 0;
5552
+ const elBold = el.style.fontWeight === "bold" || parseInt(el.style.fontWeight, 10) >= 600;
5553
+ if (elBold && elFs >= 14) return true;
5554
+ return false;
5402
5555
  }
5403
5556
  var RtfPlugin = class {
5404
5557
  id = "rtf";
@@ -5467,6 +5620,14 @@ var RtfPlugin = class {
5467
5620
  group: "zoom",
5468
5621
  execute: () => instance.fitToPage?.()
5469
5622
  },
5623
+ {
5624
+ id: "reset-zoom",
5625
+ icon: "reset-zoom",
5626
+ label: "Reset Zoom",
5627
+ type: "button",
5628
+ group: "zoom",
5629
+ execute: () => instance.resetZoom?.()
5630
+ },
5470
5631
  {
5471
5632
  id: "rotate-cw",
5472
5633
  icon: "rotate-cw",
@@ -5511,10 +5672,66 @@ var RtfPlugin = class {
5511
5672
  return actions;
5512
5673
  }
5513
5674
  async render(ctx) {
5675
+ const rawRtf = new TextDecoder("latin1").decode(ctx.buffer);
5676
+ const paperwMatch = rawRtf.match(/\\paperw(\d+)/);
5677
+ const paperhMatch = rawRtf.match(/\\paperh(\d+)/);
5678
+ const marglMatch = rawRtf.match(/\\margl(\d+)/);
5679
+ const margrMatch = rawRtf.match(/\\margr(\d+)/);
5680
+ const margtMatch = rawRtf.match(/\\margt(\d+)/);
5681
+ const margbMatch = rawRtf.match(/\\margb(\d+)/);
5682
+ const paperwTwips = paperwMatch ? parseInt(paperwMatch[1], 10) : 11906;
5683
+ const paperhTwips = paperhMatch ? parseInt(paperhMatch[1], 10) : 16838;
5684
+ const marglTwips = marglMatch ? parseInt(marglMatch[1], 10) : 1134;
5685
+ const margrTwips = margrMatch ? parseInt(margrMatch[1], 10) : 1134;
5686
+ const margtTwips = margtMatch ? parseInt(margtMatch[1], 10) : 1134;
5687
+ const margbTwips = margbMatch ? parseInt(margbMatch[1], 10) : 1134;
5688
+ const pageWidth = Math.round(paperwTwips / 15);
5689
+ const pageHeight = Math.round(paperhTwips / 15);
5690
+ const padLeft = Math.round(marglTwips / 15);
5691
+ const padRight = Math.round(margrTwips / 15);
5692
+ const padTop = Math.round(margtTwips / 15);
5693
+ const padBottom = Math.round(margbTwips / 15);
5694
+ const printableHeight = pageHeight - padTop - padBottom;
5695
+ const extractedImages = [];
5696
+ let p = 0;
5697
+ while ((p = rawRtf.indexOf("\\pict", p)) !== -1) {
5698
+ const startP = p;
5699
+ p += 5;
5700
+ const header = rawRtf.substring(startP, startP + 600);
5701
+ let mime = "";
5702
+ let magic = "";
5703
+ if (header.includes("\\pngblip")) {
5704
+ mime = "image/png";
5705
+ magic = "89504e47";
5706
+ } else if (header.includes("\\jpegblip")) {
5707
+ mime = "image/jpeg";
5708
+ magic = "ffd8ff";
5709
+ }
5710
+ if (!mime || !magic) continue;
5711
+ const magicPos = rawRtf.indexOf(magic, startP);
5712
+ if (magicPos === -1 || magicPos - startP > 3e3) continue;
5713
+ let endP = magicPos;
5714
+ while (endP < rawRtf.length && /[0-9a-fA-F\r\n\s]/.test(rawRtf[endP])) {
5715
+ endP++;
5716
+ }
5717
+ const cleanHex = rawRtf.substring(magicPos, endP).replace(/[\r\n\s]/g, "");
5718
+ if (cleanHex.length < 100) continue;
5719
+ const hexLen = cleanHex.length / 2;
5720
+ const u8 = new Uint8Array(hexLen);
5721
+ for (let k = 0; k < hexLen; k++) {
5722
+ u8[k] = parseInt(cleanHex.substr(k * 2, 2), 16);
5723
+ }
5724
+ let bStr = "";
5725
+ for (let k = 0; k < u8.length; k += 8192) {
5726
+ bStr += String.fromCharCode.apply(null, Array.from(u8.subarray(k, k + 8192)));
5727
+ }
5728
+ extractedImages.push({ mime, dataUrl: `data:${mime};base64,${btoa(bStr)}`, offset: startP });
5729
+ }
5730
+ const tables = parseRtfTables(rawRtf);
5514
5731
  const wrapper = document.createElement("div");
5515
5732
  wrapper.className = "fp-rtf-wrapper";
5516
5733
  wrapper.style.padding = "0";
5517
- wrapper.style.width = "816px";
5734
+ wrapper.style.width = `${pageWidth}px`;
5518
5735
  wrapper.style.margin = "0 auto";
5519
5736
  wrapper.style.boxSizing = "border-box";
5520
5737
  wrapper.style.display = "flex";
@@ -5534,9 +5751,8 @@ var RtfPlugin = class {
5534
5751
  let isUserZoomed = false;
5535
5752
  let fitMode = ctx?.options?.fitMode || "width";
5536
5753
  const calculateFitScale = (mode = fitMode) => {
5537
- const activeEl = pageElements[currentPage - 1] || wrapper;
5538
- const elW = 816;
5539
- const singlePageH = activeEl?.offsetHeight || 1056;
5754
+ const elW = pageWidth;
5755
+ const singlePageH = pageHeight;
5540
5756
  const availW = Math.max(280, ctx.container.clientWidth - 32);
5541
5757
  const availH = Math.max(280, ctx.container.clientHeight - 32);
5542
5758
  const sW = availW / elW;
@@ -5549,8 +5765,7 @@ var RtfPlugin = class {
5549
5765
  const applyTransform = () => {
5550
5766
  wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5551
5767
  wrapper.style.transformOrigin = "top center";
5552
- const activeEl = pageElements[currentPage - 1];
5553
- const baseH = activeEl?.offsetHeight || 1056;
5768
+ const baseH = pageHeight;
5554
5769
  const scaledH = baseH * scale;
5555
5770
  const extraH = Math.max(0, scaledH - baseH);
5556
5771
  wrapper.style.marginBottom = `${extraH + 32}px`;
@@ -5570,193 +5785,220 @@ var RtfPlugin = class {
5570
5785
  if (typeof RTFJS.loggingEnabled === "function") {
5571
5786
  RTFJS.loggingEnabled(false);
5572
5787
  }
5573
- const rawText = new TextDecoder("latin1").decode(ctx.buffer);
5574
- const tables = parseRtfTables(rawText);
5575
- const seenMediaSignatures = /* @__PURE__ */ new Set();
5576
5788
  const doc = new RTFJS.Document(ctx.buffer, {
5577
5789
  onPicture: (isLegacy, createPic) => {
5578
- if (isLegacy === true) {
5579
- return null;
5580
- }
5581
- const pic = createPic();
5582
- if (!pic) return null;
5583
- const fp = extractMediaFingerprint(pic);
5584
- if (fp) {
5585
- if (seenMediaSignatures.has(fp)) {
5586
- return null;
5587
- }
5588
- seenMediaSignatures.add(fp);
5589
- }
5590
- return pic;
5790
+ if (isLegacy === true) return null;
5791
+ return createPic();
5591
5792
  }
5592
5793
  });
5593
- const htmlElements = await doc.render();
5594
- const contentNodes = [];
5595
- const seenInContentBlocks = /* @__PURE__ */ new Set();
5596
- const extractBlocks = (nodes) => {
5597
- for (const item of nodes) {
5598
- if (!item || !(item instanceof HTMLElement)) continue;
5599
- const tag = item.tagName.toLowerCase();
5600
- const hasChildBlocks = Array.from(item.children).some((c) => {
5601
- const ct = c.tagName.toLowerCase();
5602
- return ["p", "div", "table", "h1", "h2", "h3", "h4", "h5", "h6", "section", "article", "ul", "ol"].includes(ct);
5603
- });
5604
- if (hasChildBlocks && !["table", "tr", "td", "th", "ul", "ol", "li"].includes(tag)) {
5605
- extractBlocks(Array.from(item.children));
5606
- } else {
5607
- const fp = extractMediaFingerprint(item);
5608
- if (fp) {
5609
- if (seenInContentBlocks.has(fp)) {
5610
- continue;
5611
- }
5612
- seenInContentBlocks.add(fp);
5613
- }
5614
- const hasMedia = item.querySelector("img, svg, canvas, table") !== null || ["img", "svg", "table"].includes(tag);
5615
- const textContent = (item.textContent || "").trim();
5616
- if (!hasMedia && textContent.length === 0) {
5617
- continue;
5618
- }
5619
- const svgs = item.querySelectorAll("svg, img");
5620
- svgs.forEach((s) => {
5621
- const el = s;
5622
- el.style.maxWidth = "100%";
5623
- el.style.maxHeight = "360px";
5624
- el.style.display = "block";
5625
- el.style.margin = "12px auto";
5626
- if (s.tagName.toLowerCase() === "svg") {
5627
- s.removeAttribute("width");
5628
- s.removeAttribute("height");
5629
- el.style.width = "100%";
5630
- el.style.maxHeight = "360px";
5631
- }
5632
- });
5633
- if (tag === "p" || tag === "div") {
5634
- item.style.display = "block";
5635
- item.style.marginBottom = "12px";
5636
- item.style.lineHeight = "1.6";
5637
- }
5638
- contentNodes.push(item);
5794
+ const elements = await doc.render();
5795
+ let unsupportedIndex = 1;
5796
+ const usedTables = /* @__PURE__ */ new Set();
5797
+ for (let i = 0; i < elements.length; i++) {
5798
+ const el = elements[i];
5799
+ const text = el.textContent || "";
5800
+ if (text.includes("[Unsupported image format]")) {
5801
+ if (extractedImages[unsupportedIndex]) {
5802
+ const img = document.createElement("img");
5803
+ img.src = extractedImages[unsupportedIndex].dataUrl;
5804
+ img.style.width = "100%";
5805
+ img.style.height = "auto";
5806
+ img.style.maxHeight = "430px";
5807
+ img.style.objectFit = "contain";
5808
+ img.style.display = "block";
5809
+ img.style.margin = "12px auto";
5810
+ el.innerHTML = "";
5811
+ el.appendChild(img);
5812
+ unsupportedIndex++;
5639
5813
  }
5640
5814
  }
5641
- };
5642
- extractBlocks(htmlElements);
5643
- tables.forEach((table) => {
5644
- const tableEl = renderRtfTableElement(table);
5645
- let inserted = false;
5646
- if (table.anchorBefore && table.anchorBefore.length > 10) {
5647
- const keyword = table.anchorBefore.slice(-35).trim();
5648
- for (let i = 0; i < contentNodes.length; i++) {
5649
- if (contentNodes[i].textContent?.includes(keyword)) {
5650
- contentNodes.splice(i + 1, 0, tableEl);
5651
- inserted = true;
5652
- break;
5815
+ if (tables.length > 0) {
5816
+ for (let t = 0; t < tables.length; t++) {
5817
+ if (usedTables.has(t)) continue;
5818
+ const tbl = tables[t];
5819
+ if (tbl.rows.length >= 2) {
5820
+ const sampleCell1 = tbl.rows[1]?.[1] || tbl.rows[0]?.[1] || "";
5821
+ const sampleCell2 = tbl.rows[2]?.[1] || tbl.rows[1]?.[0] || "";
5822
+ const match1 = sampleCell1 && text.includes(sampleCell1.slice(0, 15).trim());
5823
+ const match2 = sampleCell2 && text.includes(sampleCell2.slice(0, 15).trim());
5824
+ if (match1 && match2) {
5825
+ el.innerHTML = "";
5826
+ el.appendChild(renderRtfTableElement(tbl));
5827
+ usedTables.add(t);
5828
+ break;
5829
+ }
5653
5830
  }
5654
5831
  }
5655
5832
  }
5656
- if (!inserted && table.anchorAfter && table.anchorAfter.length > 10) {
5657
- const keyword = table.anchorAfter.slice(0, 35).trim();
5658
- for (let i = 0; i < contentNodes.length; i++) {
5659
- if (contentNodes[i].textContent?.includes(keyword)) {
5660
- contentNodes.splice(i, 0, tableEl);
5661
- inserted = true;
5662
- break;
5663
- }
5664
- }
5833
+ }
5834
+ elements.forEach((el) => {
5835
+ const svgs = el.querySelectorAll ? Array.from(el.querySelectorAll("svg")) : [];
5836
+ svgs.forEach((svg) => {
5837
+ svg.removeAttribute("width");
5838
+ svg.removeAttribute("height");
5839
+ svg.style.maxWidth = "100%";
5840
+ svg.style.maxHeight = "430px";
5841
+ svg.style.height = "auto";
5842
+ svg.style.display = "block";
5843
+ svg.style.margin = "12px auto";
5844
+ });
5845
+ const imgs = el.querySelectorAll ? Array.from(el.querySelectorAll("img")) : [];
5846
+ imgs.forEach((img) => {
5847
+ img.style.maxWidth = "100%";
5848
+ img.style.maxHeight = "430px";
5849
+ img.style.height = "auto";
5850
+ img.style.objectFit = "contain";
5851
+ img.style.display = "block";
5852
+ img.style.margin = "12px auto";
5853
+ });
5854
+ });
5855
+ const allImgs = Array.from(document.querySelectorAll("img")).concat(
5856
+ elements.flatMap((el) => Array.from(el.querySelectorAll ? el.querySelectorAll("img") : []))
5857
+ );
5858
+ await Promise.all(allImgs.map((img) => {
5859
+ if (img.complete && img.naturalHeight > 0) return Promise.resolve();
5860
+ if (img.decode) return img.decode().catch(() => {
5861
+ });
5862
+ return new Promise((r) => {
5863
+ img.onload = r;
5864
+ img.onerror = r;
5865
+ });
5866
+ }));
5867
+ elements.forEach((el) => {
5868
+ const text = el.textContent || "";
5869
+ if (text.includes("\uF0B7")) {
5870
+ const cleanText = text.replace(/^[\s\uf0b7\t]+/, "");
5871
+ el.style.display = "flex";
5872
+ el.style.alignItems = "flex-start";
5873
+ el.style.margin = "6px 0 6px 28px";
5874
+ el.style.fontSize = "11pt";
5875
+ el.style.lineHeight = "1.5";
5876
+ el.innerHTML = `<span style="margin-right:10px; user-select:none;">&#9633;</span><span>${cleanText}</span>`;
5665
5877
  }
5666
- if (!inserted) {
5667
- if (contentNodes.length > 2) {
5668
- contentNodes.splice(2, 0, tableEl);
5669
- } else {
5670
- contentNodes.push(tableEl);
5671
- }
5878
+ });
5879
+ elements.forEach((el) => {
5880
+ const text = (el.textContent || "").trim();
5881
+ const hasMedia = el.querySelector("img, svg, canvas, table") !== null || ["IMG", "SVG", "TABLE"].includes(el.tagName);
5882
+ if (isHeadingElement(el)) {
5883
+ el.style.marginTop = "20px";
5884
+ el.style.marginBottom = "10px";
5885
+ el.style.lineHeight = "1.25";
5886
+ } else if (text.length > 0 && !hasMedia) {
5887
+ el.style.marginBottom = "12px";
5888
+ el.style.lineHeight = "1.45";
5672
5889
  }
5673
5890
  });
5674
- const createRtfCard = (pageNum) => {
5891
+ const measureCard = document.createElement("div");
5892
+ measureCard.style.width = `${pageWidth}px`;
5893
+ measureCard.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
5894
+ measureCard.style.boxSizing = "border-box";
5895
+ measureCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5896
+ measureCard.style.lineHeight = "1.45";
5897
+ measureCard.style.visibility = "hidden";
5898
+ measureCard.style.position = "absolute";
5899
+ measureCard.style.top = "-99999px";
5900
+ document.body.appendChild(measureCard);
5901
+ const createPageCard = (num) => {
5675
5902
  const card = document.createElement("div");
5676
5903
  card.className = "fp-rtf-page-card";
5677
- card.setAttribute("data-page-number", String(pageNum));
5904
+ card.setAttribute("data-page-number", String(num));
5678
5905
  card.style.backgroundColor = "#ffffff";
5679
5906
  card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08), 0 1px 3px rgba(0,0,0,0.04)";
5680
5907
  card.style.borderRadius = "4px";
5681
- card.style.padding = "64px 56px";
5682
- card.style.width = "816px";
5683
- card.style.minHeight = "1056px";
5684
- card.style.maxHeight = "1056px";
5685
- card.style.overflow = "hidden";
5908
+ card.style.width = `${pageWidth}px`;
5909
+ card.style.height = `${pageHeight}px`;
5910
+ card.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
5686
5911
  card.style.boxSizing = "border-box";
5912
+ card.style.overflow = "hidden";
5687
5913
  card.style.marginBottom = "24px";
5688
- card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5689
- card.style.lineHeight = "1.6";
5690
5914
  card.style.color = "#1e293b";
5915
+ card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5916
+ card.style.lineHeight = "1.45";
5691
5917
  card.style.position = "relative";
5918
+ card.style.textAlign = "left";
5692
5919
  return card;
5693
5920
  };
5694
- wrapper.innerHTML = "";
5695
- const measureCard = createRtfCard(0);
5696
- measureCard.style.maxHeight = "none";
5697
- measureCard.style.height = "auto";
5698
- wrapper.appendChild(measureCard);
5699
- contentNodes.forEach((node) => measureCard.appendChild(node));
5700
- const childHeights = contentNodes.map((c) => {
5701
- const rect = c.getBoundingClientRect ? c.getBoundingClientRect() : null;
5702
- const rectH = rect ? rect.height : 0;
5703
- const offH = c.offsetHeight || 0;
5704
- let realH = Math.max(rectH, offH);
5705
- try {
5706
- const cs = window.getComputedStyle(c);
5707
- realH += (parseFloat(cs.marginTop) || 0) + (parseFloat(cs.marginBottom) || 0);
5708
- } catch {
5709
- }
5710
- const hasMedia = c.querySelector("img, svg") !== null || ["img", "svg"].includes(c.tagName.toLowerCase());
5711
- const hasTable = c.querySelector("table") !== null || c.tagName.toLowerCase() === "table";
5712
- if (hasMedia) {
5713
- realH = Math.max(realH, 300);
5714
- } else if (hasTable) {
5715
- realH = Math.max(realH, 240);
5716
- }
5717
- if (realH > 0) return realH;
5718
- const textLen = c.textContent?.trim().length || 0;
5719
- return Math.max(28, Math.ceil(textLen / 75) * 26 + 16);
5720
- });
5721
- wrapper.innerHTML = "";
5722
- let curCard = createRtfCard(1);
5723
- wrapper.appendChild(curCard);
5724
- pageElements = [curCard];
5725
- let curH = 0;
5726
- const maxH = 860;
5727
- for (let i = 0; i < contentNodes.length; i++) {
5728
- const child = contentNodes[i];
5729
- const chH = childHeights[i];
5730
- const isChildEmpty = (child.textContent || "").trim().length === 0 && !child.querySelector("table, img, svg, canvas");
5731
- if (curH === 0 && isChildEmpty) {
5921
+ const pages = [];
5922
+ let curCard = createPageCard(1);
5923
+ pages.push(curCard);
5924
+ let curHeight = 0;
5925
+ for (let i = 0; i < elements.length; i++) {
5926
+ const el = elements[i];
5927
+ if (!el || !(el instanceof HTMLElement)) continue;
5928
+ const text = (el.textContent || "").trim();
5929
+ const hasMedia = el.querySelector("img, svg, canvas, table") !== null || ["IMG", "SVG", "TABLE"].includes(el.tagName);
5930
+ const isEmptyPar = !hasMedia && text.length === 0;
5931
+ if (isEmptyPar) {
5932
+ const emptyH = 35;
5933
+ if (curHeight + emptyH > printableHeight) {
5934
+ if (curCard.childNodes.length > 0) {
5935
+ curCard = createPageCard(pages.length + 1);
5936
+ pages.push(curCard);
5937
+ curHeight = 0;
5938
+ }
5939
+ }
5940
+ const spacer = document.createElement("div");
5941
+ spacer.style.height = `${emptyH}px`;
5942
+ curCard.appendChild(spacer);
5943
+ curHeight += emptyH;
5732
5944
  continue;
5733
5945
  }
5734
- const isTable = child.querySelector("table") !== null || child.tagName.toLowerCase() === "table";
5735
- const shouldBreakBeforeTable = isTable && curH > 400 && curCard.childNodes.length > 0;
5736
- if ((curH + chH > maxH || shouldBreakBeforeTable) && curCard.childNodes.length > 0) {
5737
- curCard = createRtfCard(pageElements.length + 1);
5738
- wrapper.appendChild(curCard);
5739
- pageElements.push(curCard);
5740
- curH = 0;
5946
+ measureCard.innerHTML = "";
5947
+ const clone = el.cloneNode(true);
5948
+ measureCard.appendChild(clone);
5949
+ const compStyle = window.getComputedStyle(clone);
5950
+ const mt = parseFloat(compStyle.marginTop) || 0;
5951
+ const mb = parseFloat(compStyle.marginBottom) || 0;
5952
+ const elH = clone.offsetHeight + mt + mb;
5953
+ const isHeading = isHeadingElement(el);
5954
+ let nextContentH = 0;
5955
+ if (isHeading || hasMedia) {
5956
+ for (let j = i + 1; j < elements.length; j++) {
5957
+ const nextEl = elements[j];
5958
+ if (nextEl && (nextEl.textContent || "").trim().length > 0) {
5959
+ measureCard.innerHTML = "";
5960
+ const nClone = nextEl.cloneNode(true);
5961
+ measureCard.appendChild(nClone);
5962
+ const nStyle = window.getComputedStyle(nClone);
5963
+ nextContentH = nClone.offsetHeight + (parseFloat(nStyle.marginTop) || 0) + (parseFloat(nStyle.marginBottom) || 0);
5964
+ break;
5965
+ }
5966
+ }
5741
5967
  }
5742
- curCard.appendChild(child);
5743
- curH += chH;
5744
- }
5745
- pageElements = pageElements.filter((card) => {
5968
+ const remainingSpace = printableHeight - curHeight;
5969
+ const isLargeMedia = hasMedia && elH > 300;
5970
+ const keepWithNextOverflow = isHeading && nextContentH > 0 && elH + nextContentH + 20 > remainingSpace;
5971
+ const largeMediaOverflow = isLargeMedia && curHeight > 0 && elH + 80 > remainingSpace;
5972
+ const shouldBreak = (curHeight + elH > printableHeight || keepWithNextOverflow || largeMediaOverflow) && curCard.childNodes.length > 0;
5973
+ if (shouldBreak) {
5974
+ curCard = createPageCard(pages.length + 1);
5975
+ pages.push(curCard);
5976
+ curHeight = 0;
5977
+ }
5978
+ curCard.appendChild(el);
5979
+ curHeight += elH;
5980
+ }
5981
+ measureCard.remove();
5982
+ pageElements = pages.filter((card) => {
5746
5983
  const hasText = (card.textContent || "").trim().length > 0;
5747
- const hasMedia = card.querySelector("table, img, svg, canvas") !== null;
5748
- return hasText || hasMedia;
5984
+ const hasCardMedia = card.querySelector("table, img, svg, canvas") !== null;
5985
+ return hasText || hasCardMedia;
5749
5986
  });
5750
5987
  if (pageElements.length === 0) {
5751
5988
  pageElements = [curCard];
5752
5989
  }
5990
+ wrapper.innerHTML = "";
5991
+ pageElements.forEach((card, idx) => {
5992
+ card.setAttribute("data-page-number", String(idx + 1));
5993
+ card.style.display = idx === 0 ? "block" : "none";
5994
+ wrapper.appendChild(card);
5995
+ });
5753
5996
  } catch (err) {
5754
5997
  console.warn("[RtfPlugin] RTF render error, fallback text:", err);
5755
- const text = new TextDecoder("latin1").decode(ctx.buffer);
5756
- const tables = parseRtfTables(text);
5998
+ const text = rawRtf;
5757
5999
  const rawPages = text.split(/\\page\b/).map((segment) => {
5758
6000
  return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
5759
- }).filter((p) => p.length > 0);
6001
+ }).filter((p2) => p2.length > 0);
5760
6002
  const pages = rawPages.length > 0 ? rawPages : [text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim()];
5761
6003
  for (let i = 0; i < pages.length; i++) {
5762
6004
  const pageCard = document.createElement("div");
@@ -5764,9 +6006,9 @@ var RtfPlugin = class {
5764
6006
  pageCard.style.backgroundColor = "#ffffff";
5765
6007
  pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
5766
6008
  pageCard.style.borderRadius = "4px";
5767
- pageCard.style.padding = "64px 56px";
5768
- pageCard.style.width = "816px";
5769
- pageCard.style.minHeight = "1056px";
6009
+ pageCard.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
6010
+ pageCard.style.width = `${pageWidth}px`;
6011
+ pageCard.style.minHeight = `${pageHeight}px`;
5770
6012
  pageCard.style.boxSizing = "border-box";
5771
6013
  pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
5772
6014
  pageCard.style.fontSize = "12pt";
@@ -5786,11 +6028,9 @@ var RtfPlugin = class {
5786
6028
  let currentPage = 1;
5787
6029
  const showPage = (pageNum) => {
5788
6030
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
5789
- if (totalPages > 1) {
5790
- pageElements.forEach((el, idx) => {
5791
- el.style.display = idx + 1 === currentPage ? "block" : "none";
5792
- });
5793
- }
6031
+ pageElements.forEach((el, idx) => {
6032
+ el.style.display = idx + 1 === currentPage ? "block" : "none";
6033
+ });
5794
6034
  ctx.container.scrollTop = 0;
5795
6035
  ctx.emit("page-change", { page: currentPage, total: totalPages });
5796
6036
  };
@@ -5857,6 +6097,15 @@ var RtfPlugin = class {
5857
6097
  rotation = 0;
5858
6098
  applyTransform();
5859
6099
  },
6100
+ resetZoom: () => {
6101
+ isUserZoomed = false;
6102
+ fitMode = "width";
6103
+ scale = calculateFitScale("width");
6104
+ rotation = 0;
6105
+ ctx.container.scrollTop = 0;
6106
+ ctx.container.scrollLeft = 0;
6107
+ applyTransform();
6108
+ },
5860
6109
  rotateCW: () => {
5861
6110
  rotation = (rotation + 90) % 360;
5862
6111
  applyTransform();
@@ -5924,6 +6173,14 @@ var HtmlPreviewPlugin = class {
5924
6173
  group: "zoom",
5925
6174
  execute: () => instance.fitToPage?.()
5926
6175
  },
6176
+ {
6177
+ id: "reset-zoom",
6178
+ icon: "reset-zoom",
6179
+ label: "Reset Zoom",
6180
+ type: "button",
6181
+ group: "zoom",
6182
+ execute: () => instance.resetZoom?.()
6183
+ },
5927
6184
  {
5928
6185
  id: "copy",
5929
6186
  icon: "copy",
@@ -5996,6 +6253,12 @@ var HtmlPreviewPlugin = class {
5996
6253
  scale = 1;
5997
6254
  iframe.style.transform = "scale(1)";
5998
6255
  },
6256
+ resetZoom: () => {
6257
+ scale = 1;
6258
+ iframe.style.transform = "scale(1)";
6259
+ ctx.container.scrollTop = 0;
6260
+ ctx.container.scrollLeft = 0;
6261
+ },
5999
6262
  copy: () => {
6000
6263
  navigator.clipboard.writeText(rawHtml);
6001
6264
  },
@@ -6096,6 +6359,14 @@ var OpenDocumentPlugin = class {
6096
6359
  group: "zoom",
6097
6360
  execute: () => instance.fitToPage?.()
6098
6361
  },
6362
+ {
6363
+ id: "reset-zoom",
6364
+ icon: "reset-zoom",
6365
+ label: "Reset Zoom",
6366
+ type: "button",
6367
+ group: "zoom",
6368
+ execute: () => instance.resetZoom?.()
6369
+ },
6099
6370
  {
6100
6371
  id: "rotate-cw",
6101
6372
  icon: "rotate-cw",
@@ -6363,6 +6634,15 @@ var OpenDocumentPlugin = class {
6363
6634
  rotation = 0;
6364
6635
  applyTransform();
6365
6636
  },
6637
+ resetZoom: () => {
6638
+ isUserZoomed = false;
6639
+ fitMode = "width";
6640
+ scale = calculateFitScale("width");
6641
+ rotation = 0;
6642
+ container.scrollTop = 0;
6643
+ container.scrollLeft = 0;
6644
+ applyTransform();
6645
+ },
6366
6646
  rotateCW: () => {
6367
6647
  rotation = (rotation + 90) % 360;
6368
6648
  applyTransform();
@@ -6706,6 +6986,14 @@ var DocPlugin = class {
6706
6986
  group: "zoom",
6707
6987
  execute: () => instance.fitToPage?.()
6708
6988
  },
6989
+ {
6990
+ id: "reset-zoom",
6991
+ icon: "reset-zoom",
6992
+ label: "Reset Zoom",
6993
+ type: "button",
6994
+ group: "zoom",
6995
+ execute: () => instance.resetZoom?.()
6996
+ },
6709
6997
  {
6710
6998
  id: "rotate-cw",
6711
6999
  icon: "rotate-cw",
@@ -6912,6 +7200,15 @@ var DocPlugin = class {
6912
7200
  rotation = 0;
6913
7201
  applyTransform();
6914
7202
  },
7203
+ resetZoom: () => {
7204
+ isUserZoomed = false;
7205
+ fitMode = "width";
7206
+ scale = calculateFitScale("width");
7207
+ rotation = 0;
7208
+ ctx.container.scrollTop = 0;
7209
+ ctx.container.scrollLeft = 0;
7210
+ applyTransform();
7211
+ },
6915
7212
  rotateCW: () => {
6916
7213
  rotation = (rotation + 90) % 360;
6917
7214
  applyTransform();
@@ -7392,6 +7689,14 @@ var PptPlugin = class {
7392
7689
  group: "zoom",
7393
7690
  execute: () => instance.fitToPage?.()
7394
7691
  },
7692
+ {
7693
+ id: "reset-zoom",
7694
+ icon: "reset-zoom",
7695
+ label: "Reset Zoom",
7696
+ type: "button",
7697
+ group: "zoom",
7698
+ execute: () => instance.resetZoom?.()
7699
+ },
7395
7700
  {
7396
7701
  id: "rotate-cw",
7397
7702
  icon: "rotate-cw",
@@ -7580,6 +7885,13 @@ var PptPlugin = class {
7580
7885
  rotation = 0;
7581
7886
  applyTransform();
7582
7887
  },
7888
+ resetZoom: () => {
7889
+ scale = calculateFitScale();
7890
+ rotation = 0;
7891
+ container.scrollTop = 0;
7892
+ container.scrollLeft = 0;
7893
+ applyTransform();
7894
+ },
7583
7895
  rotateCW: () => {
7584
7896
  rotation = (rotation + 90) % 360;
7585
7897
  applyTransform();