@files-preview-app/preview-file 1.3.2 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/vue.js CHANGED
@@ -3475,26 +3475,6 @@ var ExcelPlugin = class {
3475
3475
  instance.zoomIn?.();
3476
3476
  }
3477
3477
  },
3478
- {
3479
- id: "fit-page",
3480
- icon: "fit-page",
3481
- label: "Fit to View",
3482
- type: "button",
3483
- group: "zoom",
3484
- execute: () => {
3485
- instance.fitToPage?.();
3486
- }
3487
- },
3488
- {
3489
- id: "rotate-cw",
3490
- icon: "rotate-cw",
3491
- label: "Rotate",
3492
- type: "button",
3493
- group: "view",
3494
- execute: () => {
3495
- instance.rotateCW?.();
3496
- }
3497
- },
3498
3478
  {
3499
3479
  id: "download",
3500
3480
  icon: "download",
@@ -3555,12 +3535,11 @@ var ExcelPlugin = class {
3555
3535
  container.appendChild(tabsArea);
3556
3536
  ctx.container.appendChild(container);
3557
3537
  let scale = 1;
3558
- let rotation = 0;
3559
3538
  let currentSheetIndex = 1;
3560
3539
  let sheetNames = [];
3561
3540
  let wb = null;
3562
3541
  const applyTransform = () => {
3563
- contentArea.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
3542
+ contentArea.style.transform = `scale(${scale})`;
3564
3543
  contentArea.style.transformOrigin = "top left";
3565
3544
  };
3566
3545
  const calculateFitScale = () => {
@@ -3568,7 +3547,7 @@ var ExcelPlugin = class {
3568
3547
  if (!table) return 1;
3569
3548
  const availW = Math.max(280, container.clientWidth - 48);
3570
3549
  const tW = table.offsetWidth || 800;
3571
- return Math.max(0.65, Math.min(1, availW / tW));
3550
+ return Math.max(0.4, Math.min(1, availW / tW));
3572
3551
  };
3573
3552
  try {
3574
3553
  wb = XLSX.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
@@ -3623,7 +3602,16 @@ var ExcelPlugin = class {
3623
3602
  }
3624
3603
  });
3625
3604
  ctx.emit("page-change", { page: currentSheetIndex, total: sheetNames.length });
3605
+ requestAnimationFrame(() => {
3606
+ scale = calculateFitScale();
3607
+ applyTransform();
3608
+ });
3626
3609
  };
3610
+ const ro = new ResizeObserver(() => {
3611
+ scale = calculateFitScale();
3612
+ applyTransform();
3613
+ });
3614
+ ro.observe(container);
3627
3615
  if (sheetNames.length > 0) {
3628
3616
  sheetNames.forEach((name, idx) => {
3629
3617
  const btn = document.createElement("button");
@@ -3650,6 +3638,7 @@ var ExcelPlugin = class {
3650
3638
  `;
3651
3639
  }
3652
3640
  const cleanup = () => {
3641
+ ro.disconnect();
3653
3642
  container.remove();
3654
3643
  ctx.container.innerHTML = "";
3655
3644
  };
@@ -3671,16 +3660,11 @@ var ExcelPlugin = class {
3671
3660
  },
3672
3661
  fitToPage: () => {
3673
3662
  scale = calculateFitScale();
3674
- rotation = 0;
3675
3663
  applyTransform();
3676
3664
  },
3677
3665
  rotateCW: () => {
3678
- rotation = (rotation + 90) % 360;
3679
- applyTransform();
3680
3666
  },
3681
3667
  rotateCCW: () => {
3682
- rotation = (rotation - 90 + 360) % 360;
3683
- applyTransform();
3684
3668
  },
3685
3669
  goToPage: (page) => {
3686
3670
  if (page > 0 && page <= sheetNames.length) {
@@ -3778,38 +3762,15 @@ var CsvPlugin = class {
3778
3762
  return ext === ".csv" || ext === ".tsv" || mime === "text/csv" || mime === "text/tab-separated-values";
3779
3763
  }
3780
3764
  getToolbarActions(instance) {
3781
- const totalPages = instance.getPageCount?.() ?? 1;
3782
3765
  const actions = [];
3783
3766
  actions.push({
3784
3767
  id: "thumbnails",
3785
3768
  icon: "thumbnails",
3786
- label: "Page Thumbnails",
3769
+ label: "Sheet Thumbnails",
3787
3770
  type: "button",
3788
3771
  group: "navigation",
3789
3772
  execute: () => instance.toggleThumbnails?.()
3790
3773
  });
3791
- if (totalPages > 1) {
3792
- actions.push({
3793
- id: "page-nav",
3794
- icon: "",
3795
- label: "Page Navigation",
3796
- type: "page-nav",
3797
- group: "navigation",
3798
- value: instance.getCurrentPage?.() ?? 1,
3799
- max: totalPages,
3800
- execute: (action, page) => {
3801
- const cur = instance.getCurrentPage?.() ?? 1;
3802
- const max = instance.getPageCount?.() ?? 1;
3803
- if (action === "prev") {
3804
- if (cur > 1) instance.goToPage?.(cur - 1);
3805
- } else if (action === "next") {
3806
- if (cur < max) instance.goToPage?.(cur + 1);
3807
- } else if (typeof page === "number") {
3808
- instance.goToPage?.(page);
3809
- }
3810
- }
3811
- });
3812
- }
3813
3774
  actions.push(
3814
3775
  {
3815
3776
  id: "zoom-out",
@@ -3831,16 +3792,6 @@ var CsvPlugin = class {
3831
3792
  instance.zoomIn?.();
3832
3793
  }
3833
3794
  },
3834
- {
3835
- id: "fit-page",
3836
- icon: "fit-page",
3837
- label: "Fit to View",
3838
- type: "button",
3839
- group: "zoom",
3840
- execute: () => {
3841
- instance.fitToPage?.();
3842
- }
3843
- },
3844
3795
  {
3845
3796
  id: "download",
3846
3797
  icon: "download",
@@ -3883,131 +3834,135 @@ var CsvPlugin = class {
3883
3834
  container.style.overflow = "auto";
3884
3835
  container.style.padding = "16px";
3885
3836
  container.style.boxSizing = "border-box";
3886
- container.style.transformOrigin = "top left";
3837
+ const tableWrapper = document.createElement("div");
3838
+ tableWrapper.style.transformOrigin = "top left";
3887
3839
  const delimiter = ctx.metadata.extension === ".tsv" ? " " : ",";
3888
3840
  const allLines = text.split(/\r?\n/).filter((r) => r.trim().length > 0);
3889
3841
  const headerLine = allLines[0] || "";
3890
3842
  const headerCells = headerLine.split(delimiter);
3891
3843
  const dataLines = allLines.slice(1);
3892
- const ROWS_PER_PAGE = 100;
3893
- const totalPages = Math.max(1, Math.ceil(dataLines.length / ROWS_PER_PAGE));
3894
- let currentPage = 1;
3895
3844
  const table = document.createElement("table");
3896
3845
  table.style.borderCollapse = "collapse";
3897
- table.style.width = "100%";
3846
+ table.style.minWidth = "100%";
3898
3847
  table.style.fontFamily = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace';
3899
3848
  table.style.fontSize = "13px";
3900
- const renderPage = (pageNum) => {
3901
- currentPage = Math.max(1, Math.min(totalPages, pageNum));
3902
- table.innerHTML = "";
3903
- const headerTr = document.createElement("tr");
3904
- headerCells.forEach((cell) => {
3905
- const th = document.createElement("th");
3906
- th.textContent = cell.trim();
3907
- th.style.border = "1px solid #d0d7de";
3908
- th.style.padding = "8px 12px";
3909
- th.style.backgroundColor = "#f6f8fa";
3910
- th.style.fontWeight = "600";
3911
- th.style.whiteSpace = "nowrap";
3912
- headerTr.appendChild(th);
3913
- });
3914
- table.appendChild(headerTr);
3915
- const start = (currentPage - 1) * ROWS_PER_PAGE;
3916
- const end = Math.min(dataLines.length, start + ROWS_PER_PAGE);
3917
- const pageRows = dataLines.slice(start, end);
3918
- pageRows.forEach((row, idx) => {
3919
- const tr = document.createElement("tr");
3920
- if (idx % 2 === 1) tr.style.backgroundColor = "#f8fafc";
3921
- const cells = row.split(delimiter);
3922
- cells.forEach((cell) => {
3923
- const td = document.createElement("td");
3924
- td.textContent = cell.trim();
3925
- td.style.border = "1px solid #d0d7de";
3926
- td.style.padding = "6px 12px";
3927
- td.style.whiteSpace = "nowrap";
3928
- tr.appendChild(td);
3929
- });
3930
- table.appendChild(tr);
3849
+ table.style.background = "#ffffff";
3850
+ table.style.border = "1px solid #d0d7de";
3851
+ const headerTr = document.createElement("tr");
3852
+ headerCells.forEach((cell) => {
3853
+ const th = document.createElement("th");
3854
+ th.textContent = cell.trim();
3855
+ th.style.border = "1px solid #d0d7de";
3856
+ th.style.padding = "8px 12px";
3857
+ th.style.backgroundColor = "#f6f8fa";
3858
+ th.style.fontWeight = "600";
3859
+ th.style.whiteSpace = "nowrap";
3860
+ headerTr.appendChild(th);
3861
+ });
3862
+ table.appendChild(headerTr);
3863
+ dataLines.forEach((row, idx) => {
3864
+ const tr = document.createElement("tr");
3865
+ if (idx % 2 === 1) tr.style.backgroundColor = "#f8fafc";
3866
+ const cells = row.split(delimiter);
3867
+ cells.forEach((cell) => {
3868
+ const td = document.createElement("td");
3869
+ td.textContent = cell.trim();
3870
+ td.style.border = "1px solid #d0d7de";
3871
+ td.style.padding = "6px 12px";
3872
+ td.style.whiteSpace = "nowrap";
3873
+ tr.appendChild(td);
3931
3874
  });
3932
- container.scrollTop = 0;
3933
- ctx.emit("page-change", { page: currentPage, total: totalPages });
3934
- };
3935
- renderPage(1);
3936
- container.appendChild(table);
3875
+ table.appendChild(tr);
3876
+ });
3877
+ tableWrapper.appendChild(table);
3878
+ container.appendChild(tableWrapper);
3937
3879
  ctx.container.appendChild(container);
3938
3880
  let scale = 1;
3881
+ const calculateFitScale = () => {
3882
+ const availW = Math.max(280, container.clientWidth - 48);
3883
+ const tW = table.offsetWidth || 800;
3884
+ return Math.max(0.4, Math.min(1, availW / tW));
3885
+ };
3939
3886
  const applyScale = () => {
3940
- container.style.transform = `scale(${scale})`;
3941
- container.style.transformOrigin = "top left";
3887
+ tableWrapper.style.transform = `scale(${scale})`;
3942
3888
  };
3889
+ requestAnimationFrame(() => {
3890
+ scale = calculateFitScale();
3891
+ applyScale();
3892
+ });
3893
+ const ro = new ResizeObserver(() => {
3894
+ scale = calculateFitScale();
3895
+ applyScale();
3896
+ });
3897
+ ro.observe(container);
3943
3898
  const cleanup = () => {
3899
+ ro.disconnect();
3944
3900
  container.remove();
3945
3901
  ctx.container.innerHTML = "";
3946
3902
  };
3947
3903
  ctx.signal.addEventListener("abort", cleanup);
3948
3904
  return {
3949
3905
  destroy: cleanup,
3950
- getPageCount: () => totalPages,
3951
- getCurrentPage: () => currentPage,
3952
- goToPage: (page) => renderPage(page),
3906
+ getPageCount: () => 1,
3907
+ getCurrentPage: () => 1,
3908
+ goToPage: () => {
3909
+ },
3953
3910
  getThumbnails: () => {
3954
- const thumbnails = [];
3955
- for (let i = 0; i < totalPages; i++) {
3956
- const pageIdx = i;
3957
- const startRow = pageIdx * ROWS_PER_PAGE + 1;
3958
- const endRow = Math.min(dataLines.length, (pageIdx + 1) * ROWS_PER_PAGE);
3959
- const label = totalPages === 1 ? "Table" : `Page ${pageIdx + 1} (${startRow}-${endRow})`;
3960
- thumbnails.push({
3961
- index: pageIdx,
3962
- label,
3963
- render: async (canvas) => {
3964
- canvas.width = 140;
3965
- canvas.height = 100;
3966
- const c = canvas.getContext("2d");
3967
- if (!c) return;
3968
- c.fillStyle = "#ffffff";
3969
- c.fillRect(0, 0, canvas.width, canvas.height);
3970
- c.fillStyle = "#2563eb";
3971
- c.fillRect(0, 0, canvas.width, 16);
3972
- c.fillStyle = "#ffffff";
3973
- c.font = "bold 8px sans-serif";
3974
- c.fillText(`\u{1F4C8} ${label.slice(0, 18)}`, 6, 11);
3975
- const startY = 17;
3976
- const rowH = 13;
3977
- const colW = 28;
3978
- const cols = Math.min(4, headerCells.length || 4);
3979
- c.fillStyle = "#f1f5f9";
3980
- c.fillRect(0, startY, canvas.width, rowH);
3981
- c.strokeStyle = "#cbd5e1";
3982
- c.lineWidth = 0.8;
3983
- c.strokeRect(0, startY, canvas.width, rowH);
3984
- c.fillStyle = "#64748b";
3985
- c.font = "bold 7px sans-serif";
3986
- for (let ci = 0; ci < cols; ci++) {
3987
- const hName = headerCells[ci] || `Col ${ci + 1}`;
3988
- c.fillText(hName.slice(0, 5), 8 + ci * colW, startY + 9);
3989
- }
3990
- const rowsToPreview = dataLines.slice(pageIdx * ROWS_PER_PAGE, pageIdx * ROWS_PER_PAGE + 5);
3991
- for (let ri = 0; ri < rowsToPreview.length; ri++) {
3992
- const y = startY + (ri + 1) * rowH;
3993
- if (y > canvas.height - 2) break;
3994
- c.strokeStyle = "#e2e8f0";
3995
- c.strokeRect(0, y, canvas.width, rowH);
3996
- const cVals = rowsToPreview[ri].split(delimiter);
3997
- c.fillStyle = "#334155";
3998
- c.font = "6px sans-serif";
3999
- for (let ci = 0; ci < cols; ci++) {
4000
- const val = cVals[ci] || "";
4001
- c.fillText(val.trim().slice(0, 6), 8 + ci * colW, y + 9);
3911
+ const sheetName = ctx.metadata.name?.replace(/\.[^/.]+$/, "") || "Sheet1";
3912
+ return [{
3913
+ index: 0,
3914
+ label: sheetName,
3915
+ render: async (canvas) => {
3916
+ canvas.width = 140;
3917
+ canvas.height = 100;
3918
+ const c = canvas.getContext("2d");
3919
+ if (!c) return;
3920
+ c.fillStyle = "#ffffff";
3921
+ c.fillRect(0, 0, canvas.width, canvas.height);
3922
+ c.fillStyle = "#107c41";
3923
+ c.fillRect(0, 0, canvas.width, 16);
3924
+ c.fillStyle = "#ffffff";
3925
+ c.font = 'bold 8px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
3926
+ c.fillText(`\u{1F4CA} ${sheetName.slice(0, 16)}`, 6, 11);
3927
+ const startY = 17;
3928
+ const rowH = 13;
3929
+ const colW = 30;
3930
+ const cols = headerCells.slice(0, 4).map((h2) => h2.trim() || "Col");
3931
+ c.fillStyle = "#f1f5f9";
3932
+ c.fillRect(0, startY, canvas.width, rowH);
3933
+ c.strokeStyle = "#cbd5e1";
3934
+ c.lineWidth = 0.8;
3935
+ c.strokeRect(0, startY, canvas.width, rowH);
3936
+ c.fillStyle = "#64748b";
3937
+ c.font = "bold 7px sans-serif";
3938
+ for (let ci = 0; ci < cols.length; ci++) {
3939
+ c.fillText(cols[ci].slice(0, 5), 14 + ci * colW, startY + 9);
3940
+ }
3941
+ for (let ri = 0; ri < Math.min(5, dataLines.length); ri++) {
3942
+ const y = startY + (ri + 1) * rowH;
3943
+ if (y > canvas.height - 2) break;
3944
+ c.fillStyle = "#f8fafc";
3945
+ c.fillRect(0, y, 12, rowH);
3946
+ c.fillStyle = "#94a3b8";
3947
+ c.font = "6px sans-serif";
3948
+ c.fillText(String(ri + 1), 3, y + 9);
3949
+ c.strokeStyle = "#e2e8f0";
3950
+ c.strokeRect(0, y, canvas.width, rowH);
3951
+ const rowCells = dataLines[ri].split(delimiter);
3952
+ c.fillStyle = "#334155";
3953
+ c.font = "6px sans-serif";
3954
+ for (let ci = 0; ci < cols.length; ci++) {
3955
+ const val = (rowCells[ci] || "").trim();
3956
+ if (val) {
3957
+ c.fillText(val.slice(0, 6), 14 + ci * colW, y + 9);
4002
3958
  }
4003
3959
  }
4004
- c.strokeStyle = "#cbd5e1";
4005
- c.lineWidth = 1;
4006
- c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
4007
3960
  }
4008
- });
4009
- }
4010
- return thumbnails;
3961
+ c.strokeStyle = "#cbd5e1";
3962
+ c.lineWidth = 1;
3963
+ c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
3964
+ }
3965
+ }];
4011
3966
  },
4012
3967
  zoomIn: () => {
4013
3968
  scale += 0.1;
@@ -4023,11 +3978,13 @@ var CsvPlugin = class {
4023
3978
  applyScale();
4024
3979
  },
4025
3980
  fitToPage: () => {
4026
- const availW = Math.max(280, (ctx.container.clientWidth || window.innerWidth) - 48);
4027
- const tW = table.offsetWidth || 600;
4028
- scale = Math.max(0.35, Math.min(1, availW / tW));
3981
+ scale = calculateFitScale();
4029
3982
  applyScale();
4030
3983
  },
3984
+ rotateCW: () => {
3985
+ },
3986
+ rotateCCW: () => {
3987
+ },
4031
3988
  download: () => {
4032
3989
  const blob = new Blob([ctx.buffer], { type: "text/csv" });
4033
3990
  const url = URL.createObjectURL(blob);
@@ -4139,26 +4096,6 @@ var CodePlugin = class {
4139
4096
  instance.zoomIn?.();
4140
4097
  }
4141
4098
  },
4142
- {
4143
- id: "fit-page",
4144
- icon: "fit-page",
4145
- label: "Fit to View",
4146
- type: "button",
4147
- group: "zoom",
4148
- execute: () => {
4149
- instance.fitToPage?.();
4150
- }
4151
- },
4152
- {
4153
- id: "rotate-cw",
4154
- icon: "rotate-cw",
4155
- label: "Rotate",
4156
- type: "button",
4157
- group: "view",
4158
- execute: () => {
4159
- instance.rotateCW?.();
4160
- }
4161
- },
4162
4099
  {
4163
4100
  id: "copy",
4164
4101
  icon: "copy",
@@ -5302,6 +5239,148 @@ var ThreeDPlugin = class {
5302
5239
  function threeDPlugin() {
5303
5240
  return new ThreeDPlugin();
5304
5241
  }
5242
+ function cleanRtfText(raw) {
5243
+ return raw.replace(/\\bin\d+\s/g, "").replace(/{\\\*[^}]+}/g, "").replace(/\\u(-?\d+)\??/g, (_, code) => {
5244
+ let num = parseInt(code, 10);
5245
+ if (num < 0) num += 65536;
5246
+ return String.fromCharCode(num);
5247
+ }).replace(/\\'([0-9a-fA-F]{2})/g, (_, hex) => {
5248
+ return String.fromCharCode(parseInt(hex, 16));
5249
+ }).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();
5250
+ }
5251
+ function parseRtfTables(rtfText) {
5252
+ const rowSegments = rtfText.split(/\\row\b/);
5253
+ if (rowSegments.length <= 1) return [];
5254
+ const rawTables = [];
5255
+ let currentTable = null;
5256
+ let charOffset = 0;
5257
+ for (let i = 0; i < rowSegments.length - 1; i++) {
5258
+ const segment = rowSegments[i];
5259
+ const segmentStart = charOffset;
5260
+ const segmentEnd = charOffset + segment.length + 4;
5261
+ const cellParts = segment.split(/\\cell\b/);
5262
+ if (cellParts.length > 1) {
5263
+ const cellxMatches = [...segment.matchAll(/\\cellx(\d+)/g)].map((m) => parseInt(m[1], 10));
5264
+ let cellWidths = [];
5265
+ if (cellxMatches.length > 0) {
5266
+ let seq = [cellxMatches[0]];
5267
+ for (let k = 1; k < cellxMatches.length; k++) {
5268
+ if (cellxMatches[k] > cellxMatches[k - 1]) seq.push(cellxMatches[k]);
5269
+ else break;
5270
+ }
5271
+ let prev = 0;
5272
+ cellWidths = seq.map((x) => {
5273
+ const w = x - prev;
5274
+ prev = x;
5275
+ return w;
5276
+ });
5277
+ }
5278
+ const cells = [];
5279
+ for (let c = 0; c < cellParts.length - 1; c++) {
5280
+ let rawCell = cellParts[c];
5281
+ if (c === 0) {
5282
+ const lastTrowd = rawCell.lastIndexOf("\\trowd");
5283
+ if (lastTrowd !== -1) rawCell = rawCell.slice(lastTrowd);
5284
+ }
5285
+ cells.push(cleanRtfText(rawCell));
5286
+ }
5287
+ const isNewTable = !currentTable || segmentStart - currentTable.lastEnd > 2500;
5288
+ if (isNewTable) {
5289
+ const prevTextSlice = rtfText.slice(Math.max(0, segmentStart - 4e3), segmentStart);
5290
+ const cleanPrev = cleanRtfText(prevTextSlice);
5291
+ const anchorBefore = cleanPrev.slice(-80).trim();
5292
+ currentTable = {
5293
+ id: `RTF_TABLE_${rawTables.length}`,
5294
+ startPos: segmentStart,
5295
+ lastEnd: segmentEnd,
5296
+ rows: [],
5297
+ columnWidths: cellWidths,
5298
+ anchorBefore,
5299
+ anchorAfter: ""
5300
+ };
5301
+ rawTables.push(currentTable);
5302
+ }
5303
+ if (currentTable) {
5304
+ currentTable.rows.push({
5305
+ cells,
5306
+ widths: cellWidths.length === cells.length ? cellWidths : currentTable.columnWidths
5307
+ });
5308
+ currentTable.lastEnd = segmentEnd;
5309
+ }
5310
+ }
5311
+ charOffset += segment.length + 4;
5312
+ }
5313
+ rawTables.forEach((tbl) => {
5314
+ const afterSlice = rtfText.slice(tbl.lastEnd, Math.min(rtfText.length, tbl.lastEnd + 2e3));
5315
+ const cleanAfter = cleanRtfText(afterSlice);
5316
+ tbl.anchorAfter = cleanAfter.slice(0, 80).trim();
5317
+ });
5318
+ return rawTables.map((tbl) => {
5319
+ const totalW = (tbl.columnWidths || []).reduce((a, b) => a + b, 0);
5320
+ const colPercents = totalW > 0 ? tbl.columnWidths.map((w) => Math.round(w / totalW * 100)) : [];
5321
+ return {
5322
+ id: tbl.id,
5323
+ rows: tbl.rows.map((r) => r.cells),
5324
+ colPercents,
5325
+ anchorBefore: tbl.anchorBefore,
5326
+ anchorAfter: tbl.anchorAfter
5327
+ };
5328
+ });
5329
+ }
5330
+ function renderRtfTableElement(table) {
5331
+ const tableEl = document.createElement("table");
5332
+ tableEl.className = "fp-rtf-table";
5333
+ tableEl.style.width = "100%";
5334
+ tableEl.style.borderCollapse = "collapse";
5335
+ tableEl.style.margin = "16px 0 20px";
5336
+ tableEl.style.fontSize = "10pt";
5337
+ tableEl.style.lineHeight = "1.5";
5338
+ tableEl.style.border = "1px solid #cbd5e1";
5339
+ tableEl.style.borderRadius = "4px";
5340
+ tableEl.style.boxSizing = "border-box";
5341
+ tableEl.style.backgroundColor = "#ffffff";
5342
+ const thead = document.createElement("thead");
5343
+ const tbody = document.createElement("tbody");
5344
+ table.rows.forEach((rowCells, rIdx) => {
5345
+ const tr = document.createElement("tr");
5346
+ const isHeader = rIdx === 0;
5347
+ if (isHeader) {
5348
+ tr.style.backgroundColor = "#f8fafc";
5349
+ tr.style.borderBottom = "2px solid #cbd5e1";
5350
+ } else {
5351
+ tr.style.borderBottom = "1px solid #e2e8f0";
5352
+ if (rIdx % 2 === 0) {
5353
+ tr.style.backgroundColor = "#fcfdfe";
5354
+ }
5355
+ }
5356
+ rowCells.forEach((cellText, cIdx) => {
5357
+ const cellEl = document.createElement(isHeader ? "th" : "td");
5358
+ cellEl.style.padding = "8px 12px";
5359
+ cellEl.style.border = "1px solid #cbd5e1";
5360
+ cellEl.style.verticalAlign = "top";
5361
+ cellEl.style.color = isHeader ? "#0f172a" : "#1e293b";
5362
+ cellEl.style.fontWeight = isHeader ? "600" : "normal";
5363
+ if (table.colPercents && table.colPercents[cIdx]) {
5364
+ cellEl.style.width = `${table.colPercents[cIdx]}%`;
5365
+ }
5366
+ if (/^\d+$/.test(cellText.trim()) || cellText.trim() === "#") {
5367
+ cellEl.style.textAlign = "center";
5368
+ } else {
5369
+ cellEl.style.textAlign = "left";
5370
+ }
5371
+ cellEl.textContent = cellText;
5372
+ tr.appendChild(cellEl);
5373
+ });
5374
+ if (isHeader) {
5375
+ thead.appendChild(tr);
5376
+ } else {
5377
+ tbody.appendChild(tr);
5378
+ }
5379
+ });
5380
+ tableEl.appendChild(thead);
5381
+ tableEl.appendChild(tbody);
5382
+ return tableEl;
5383
+ }
5305
5384
  var RtfPlugin = class {
5306
5385
  id = "rtf";
5307
5386
  name = "Rich Text Format (RTF)";
@@ -5337,6 +5416,14 @@ var RtfPlugin = class {
5337
5416
  }
5338
5417
  });
5339
5418
  actions.push(
5419
+ {
5420
+ id: "thumbnails",
5421
+ icon: "thumbnails",
5422
+ label: "Thumbnails",
5423
+ type: "button",
5424
+ group: "view",
5425
+ execute: () => instance.toggleThumbnails?.()
5426
+ },
5340
5427
  {
5341
5428
  id: "zoom-out",
5342
5429
  icon: "zoom-out",
@@ -5464,6 +5551,8 @@ var RtfPlugin = class {
5464
5551
  if (typeof RTFJS.loggingEnabled === "function") {
5465
5552
  RTFJS.loggingEnabled(false);
5466
5553
  }
5554
+ const rawText = new TextDecoder("latin1").decode(ctx.buffer);
5555
+ const tables = parseRtfTables(rawText);
5467
5556
  const doc = new RTFJS.Document(ctx.buffer, {});
5468
5557
  const htmlElements = await doc.render();
5469
5558
  const contentNodes = [];
@@ -5478,6 +5567,20 @@ var RtfPlugin = class {
5478
5567
  if (hasChildBlocks && !["table", "tr", "td", "th", "ul", "ol", "li"].includes(tag)) {
5479
5568
  extractBlocks(Array.from(item.children));
5480
5569
  } else {
5570
+ const svgs = item.querySelectorAll("svg, img");
5571
+ svgs.forEach((s) => {
5572
+ const el = s;
5573
+ el.style.maxWidth = "100%";
5574
+ el.style.maxHeight = "360px";
5575
+ el.style.display = "block";
5576
+ el.style.margin = "12px auto";
5577
+ if (s.tagName.toLowerCase() === "svg") {
5578
+ s.removeAttribute("width");
5579
+ s.removeAttribute("height");
5580
+ el.style.width = "100%";
5581
+ el.style.maxHeight = "360px";
5582
+ }
5583
+ });
5481
5584
  if (tag === "p" || tag === "div") {
5482
5585
  item.style.display = "block";
5483
5586
  item.style.marginBottom = "12px";
@@ -5488,14 +5591,46 @@ var RtfPlugin = class {
5488
5591
  }
5489
5592
  };
5490
5593
  extractBlocks(htmlElements);
5594
+ tables.forEach((table) => {
5595
+ const tableEl = renderRtfTableElement(table);
5596
+ let inserted = false;
5597
+ if (table.anchorBefore && table.anchorBefore.length > 10) {
5598
+ const keyword = table.anchorBefore.slice(-35).trim();
5599
+ for (let i = 0; i < contentNodes.length; i++) {
5600
+ if (contentNodes[i].textContent?.includes(keyword)) {
5601
+ contentNodes.splice(i + 1, 0, tableEl);
5602
+ inserted = true;
5603
+ break;
5604
+ }
5605
+ }
5606
+ }
5607
+ if (!inserted && table.anchorAfter && table.anchorAfter.length > 10) {
5608
+ const keyword = table.anchorAfter.slice(0, 35).trim();
5609
+ for (let i = 0; i < contentNodes.length; i++) {
5610
+ if (contentNodes[i].textContent?.includes(keyword)) {
5611
+ contentNodes.splice(i, 0, tableEl);
5612
+ inserted = true;
5613
+ break;
5614
+ }
5615
+ }
5616
+ }
5617
+ if (!inserted) {
5618
+ if (contentNodes.length > 2) {
5619
+ contentNodes.splice(2, 0, tableEl);
5620
+ } else {
5621
+ contentNodes.push(tableEl);
5622
+ }
5623
+ }
5624
+ });
5491
5625
  wrapper.innerHTML = "";
5492
5626
  contentNodes.forEach((node) => wrapper.appendChild(node));
5493
5627
  const childHeights = contentNodes.map((c) => {
5494
5628
  const rectH = c.getBoundingClientRect ? c.getBoundingClientRect().height : 0;
5495
5629
  const offH = c.offsetHeight || 0;
5630
+ const realH = Math.max(rectH, offH);
5631
+ if (realH > 0) return realH;
5496
5632
  const textLen = c.textContent?.trim().length || 0;
5497
- const estH = Math.max(28, Math.ceil(textLen / 75) * 24 + 16);
5498
- return Math.max(rectH, offH, estH);
5633
+ return Math.max(24, Math.ceil(textLen / 95) * 22 + 12);
5499
5634
  });
5500
5635
  wrapper.innerHTML = "";
5501
5636
  const createRtfCard = () => {
@@ -5504,7 +5639,7 @@ var RtfPlugin = class {
5504
5639
  card.style.backgroundColor = "#ffffff";
5505
5640
  card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
5506
5641
  card.style.borderRadius = "4px";
5507
- card.style.padding = "72px 56px";
5642
+ card.style.padding = "64px 56px";
5508
5643
  card.style.width = "816px";
5509
5644
  card.style.minHeight = "1056px";
5510
5645
  card.style.boxSizing = "border-box";
@@ -5518,22 +5653,35 @@ var RtfPlugin = class {
5518
5653
  wrapper.appendChild(curCard);
5519
5654
  pageElements = [curCard];
5520
5655
  let curH = 0;
5521
- const maxH = 912;
5656
+ const maxH = 928;
5522
5657
  for (let i = 0; i < contentNodes.length; i++) {
5523
5658
  const child = contentNodes[i];
5524
5659
  const chH = childHeights[i];
5525
- curCard.appendChild(child);
5526
- curH += chH;
5527
- if (curH >= maxH && i < contentNodes.length - 1) {
5660
+ const isChildEmpty = (child.textContent || "").trim().length === 0 && !child.querySelector("table, img, svg, canvas");
5661
+ if (curH === 0 && isChildEmpty) {
5662
+ continue;
5663
+ }
5664
+ if (curH + chH > maxH && curCard.childNodes.length > 0) {
5528
5665
  curCard = createRtfCard();
5529
5666
  wrapper.appendChild(curCard);
5530
5667
  pageElements.push(curCard);
5531
5668
  curH = 0;
5532
5669
  }
5670
+ curCard.appendChild(child);
5671
+ curH += chH;
5672
+ }
5673
+ pageElements = pageElements.filter((card) => {
5674
+ const hasText = (card.textContent || "").trim().length > 0;
5675
+ const hasMedia = card.querySelector("table, img, svg, canvas") !== null;
5676
+ return hasText || hasMedia;
5677
+ });
5678
+ if (pageElements.length === 0) {
5679
+ pageElements = [curCard];
5533
5680
  }
5534
5681
  } catch (err) {
5535
5682
  console.warn("[RtfPlugin] RTF render error, fallback text:", err);
5536
5683
  const text = new TextDecoder("latin1").decode(ctx.buffer);
5684
+ const tables = parseRtfTables(text);
5537
5685
  const rawPages = text.split(/\\page\b/).map((segment) => {
5538
5686
  return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
5539
5687
  }).filter((p) => p.length > 0);
@@ -5544,7 +5692,7 @@ var RtfPlugin = class {
5544
5692
  pageCard.style.backgroundColor = "#ffffff";
5545
5693
  pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
5546
5694
  pageCard.style.borderRadius = "4px";
5547
- pageCard.style.padding = "72px 56px";
5695
+ pageCard.style.padding = "64px 56px";
5548
5696
  pageCard.style.width = "816px";
5549
5697
  pageCard.style.minHeight = "1056px";
5550
5698
  pageCard.style.boxSizing = "border-box";
@@ -5555,6 +5703,9 @@ var RtfPlugin = class {
5555
5703
  pageCard.style.whiteSpace = "pre-wrap";
5556
5704
  pageCard.style.display = i === 0 ? "block" : "none";
5557
5705
  pageCard.textContent = pages[i];
5706
+ if (i === 1 && tables.length > 0) {
5707
+ tables.forEach((tbl) => pageCard.appendChild(renderRtfTableElement(tbl)));
5708
+ }
5558
5709
  wrapper.appendChild(pageCard);
5559
5710
  pageElements.push(pageCard);
5560
5711
  }
@@ -5585,6 +5736,32 @@ var RtfPlugin = class {
5585
5736
  getPageCount: () => totalPages,
5586
5737
  getCurrentPage: () => currentPage,
5587
5738
  goToPage: (page) => showPage(page),
5739
+ getThumbnails: async () => {
5740
+ const items = [];
5741
+ for (let idx = 0; idx < totalPages; idx++) {
5742
+ const pageIdx = idx;
5743
+ items.push({
5744
+ index: pageIdx,
5745
+ label: `Page ${pageIdx + 1}`,
5746
+ render: async (canvas) => {
5747
+ const ctx2d = canvas.getContext("2d");
5748
+ if (!ctx2d) return;
5749
+ canvas.width = 140;
5750
+ canvas.height = 180;
5751
+ ctx2d.fillStyle = "#ffffff";
5752
+ ctx2d.fillRect(0, 0, 140, 180);
5753
+ ctx2d.strokeStyle = "#cbd5e1";
5754
+ ctx2d.lineWidth = 1;
5755
+ ctx2d.strokeRect(0.5, 0.5, 139, 179);
5756
+ ctx2d.fillStyle = "#334155";
5757
+ ctx2d.font = 'bold 11px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
5758
+ ctx2d.textAlign = "center";
5759
+ ctx2d.fillText(`Page ${pageIdx + 1}`, 70, 95);
5760
+ }
5761
+ });
5762
+ }
5763
+ return items;
5764
+ },
5588
5765
  zoomIn: () => {
5589
5766
  isUserZoomed = true;
5590
5767
  scale += 0.15;
@@ -7630,7 +7807,7 @@ var FilePreview = defineComponent({
7630
7807
  default: () => ({})
7631
7808
  }
7632
7809
  },
7633
- emits: ["loading", "loaded", "error", "page-change", "zoom-change"],
7810
+ emits: ["loading", "loaded", "error", "page-change", "zoom-change", "rotate", "destroy"],
7634
7811
  setup(props, { emit, expose }) {
7635
7812
  const containerRef = ref(null);
7636
7813
  let viewer = null;
@@ -7654,6 +7831,8 @@ var FilePreview = defineComponent({
7654
7831
  viewer.on("error", (data) => emit("error", data));
7655
7832
  viewer.on("page-change", (data) => emit("page-change", data));
7656
7833
  viewer.on("zoom-change", (data) => emit("zoom-change", data));
7834
+ viewer.on("rotate", (data) => emit("rotate", data));
7835
+ viewer.on("destroy", (data) => emit("destroy", data));
7657
7836
  renderPreview();
7658
7837
  });
7659
7838
  watch(() => props.src, renderPreview);