Skip to content

Commit 3592ab9

Browse files
committed
feat: add copy as Tab Seperated Values (for excel pasting)
1 parent e638e80 commit 3592ab9

File tree

2 files changed

+48
-0
lines changed

2 files changed

+48
-0
lines changed

src/controls/export-controls.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66
export interface ExportControlsConfig {
77
onMarkdownCopy?: () => void;
88
onCsvCopy?: () => void;
9+
onTsvCopy?: () => void;
910
}
1011

1112
export class ExportControls {
1213
private container: HTMLDivElement;
1314
private markdownButton: HTMLButtonElement;
1415
private csvButton: HTMLButtonElement;
16+
private tsvButton: HTMLButtonElement;
1517
private config: ExportControlsConfig;
1618

1719
constructor(config: ExportControlsConfig) {
@@ -29,9 +31,11 @@ export class ExportControls {
2931
// Create buttons
3032
this.markdownButton = this.createMarkdownButton();
3133
this.csvButton = this.createCsvButton();
34+
this.tsvButton = this.createTsvButton();
3235

3336
this.container.appendChild(this.markdownButton);
3437
this.container.appendChild(this.csvButton);
38+
this.container.appendChild(this.tsvButton);
3539
}
3640

3741
private createMarkdownButton(): HTMLButtonElement {
@@ -62,6 +66,20 @@ export class ExportControls {
6266
return button;
6367
}
6468

69+
private createTsvButton(): HTMLButtonElement {
70+
const button = document.createElement('button');
71+
button.className = 'table-export-button';
72+
button.textContent = 'TSV';
73+
button.title = 'Copy table as TSV (tab-delimited) to clipboard';
74+
button.setAttribute('aria-label', 'Copy as TSV');
75+
button.addEventListener('click', () => {
76+
if (this.config.onTsvCopy) {
77+
this.config.onTsvCopy();
78+
}
79+
});
80+
return button;
81+
}
82+
6583
getElement(): HTMLDivElement {
6684
return this.container;
6785
}

src/plugin.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ export class TablePlugin {
249249
this.exportControls = new ExportControls({
250250
onMarkdownCopy: () => this.handleMarkdownExport(),
251251
onCsvCopy: () => this.handleCsvExport(),
252+
onTsvCopy: () => this.handleTsvExport(),
252253
});
253254

254255
// Add controls toolbar to container
@@ -705,6 +706,35 @@ export class TablePlugin {
705706
});
706707
}
707708

709+
/**
710+
* Handle TSV export to clipboard
711+
*/
712+
private handleTsvExport(): void {
713+
const results = this.getResultsData();
714+
if (!this.clipboardManager || !this.table || !results) {
715+
return;
716+
}
717+
718+
const data = this.getExportData();
719+
const headers = results.head?.vars || [];
720+
const tsv = this.clipboardManager.formatAsTSV(data, headers);
721+
722+
this.clipboardManager.copyToClipboard(tsv).then((success) => {
723+
if (success) {
724+
this.showNotification('✓ Copied as TSV', 'success');
725+
this.emit('copy', { format: 'tsv', success: true });
726+
} else {
727+
console.error('Failed to copy TSV to clipboard');
728+
this.showNotification('✗ Failed to copy to clipboard', 'error');
729+
this.emit('copy', { format: 'tsv', success: false, error: 'Failed to copy to clipboard' });
730+
}
731+
}).catch((error) => {
732+
console.error('Error copying TSV to clipboard:', error);
733+
this.showNotification('✗ Failed to copy to clipboard', 'error');
734+
this.emit('copy', { format: 'tsv', success: false, error: error.message });
735+
});
736+
}
737+
708738
/**
709739
* Get export data respecting search filter
710740
*/

0 commit comments

Comments
 (0)