feat: 添加源码模式和相关样式,支持在表格和源码视图之间切换

This commit is contained in:
JayBridge 2025-06-19 11:14:10 +08:00
parent f2a8c03c6e
commit d0123e6b5a
5 changed files with 84 additions and 4 deletions

View file

@ -6,7 +6,9 @@ export const enUS = {
deleteRow: 'Delete row',
addColumn: 'Add column',
deleteColumn: 'Delete column',
resetColumnWidth: 'Reset column width'
resetColumnWidth: 'Reset column width',
sourceMode: 'Source Mode',
tableMode: 'Table Mode'
},
editBar: {
placeholder: 'Edit selected cell...'

View file

@ -85,3 +85,6 @@ export class I18n {
}
export const i18n = new I18n();
export * from "./en";
export * from "./zh-cn";

View file

@ -6,7 +6,9 @@ export const zhCN = {
deleteRow: '删除行',
addColumn: '添加列',
deleteColumn: '删除列',
resetColumnWidth: '重置列宽'
resetColumnWidth: '重置列宽',
sourceMode: '源码模式',
tableMode: '表格模式'
},
editBar: {
placeholder: '编辑选中单元格...'

View file

@ -50,6 +50,11 @@ export class CSVView extends TextFileView {
private searchMatches: Array<{row: number, col: number, value: string}> = [];
private currentSearchIndex: number = -1;
// 新增:源码模式相关属性
private isSourceMode: boolean = false;
private sourceTextarea: HTMLTextAreaElement | null = null;
private sourceCursorPos: { start: number, end: number } = { start: 0, end: 0 };
constructor(leaf: any) {
super(leaf);
this.historyManager = new TableHistoryManager(
@ -140,8 +145,35 @@ export class CSVView extends TextFileView {
refresh() {
// Safety check: ensure tableEl exists
if (!this.tableEl) {
console.warn("Table element not initialized in refresh()");
if (!this.contentEl) return;
this.contentEl.querySelectorAll('.csv-source-mode').forEach(el => el.remove());
if (this.isSourceMode) {
// 源码模式显示textarea
let textarea = this.sourceTextarea;
if (!textarea) {
textarea = document.createElement('textarea');
textarea.className = 'csv-source-mode';
textarea.style.width = '100%';
textarea.style.height = '60vh';
this.sourceTextarea = textarea;
}
textarea.value = CSVUtils.unparseCSV(this.tableData);
this.contentEl.appendChild(textarea);
// 恢复光标
if (this.sourceCursorPos) {
setTimeout(() => {
textarea.selectionStart = this.sourceCursorPos.start;
textarea.selectionEnd = this.sourceCursorPos.end;
textarea.focus();
}, 0);
}
// 监听内容变更
textarea.oninput = () => {
try {
this.tableData = CSVUtils.parseCSV(textarea.value, { delimiter: this.delimiter, quoteChar: this.quoteChar });
this.requestSave();
} catch (e) {}
};
return;
}
@ -674,6 +706,12 @@ export class CSVView extends TextFileView {
}
};
// 源码模式切换按钮
const sourceToggleBtn = new ButtonComponent(this.operationEl)
.setButtonText(this.isSourceMode ? i18n.t("buttons.tableMode") : i18n.t("buttons.sourceMode"))
.setIcon(this.isSourceMode ? "table" : "code")
.onClick(() => this.toggleSourceMode());
// 创建表格区域 - 只使用顶部滚动条
const tableWrapper = this.contentEl.createEl("div", {
cls: "table-wrapper",
@ -754,6 +792,25 @@ export class CSVView extends TextFileView {
}
}
private toggleSourceMode() {
this.isSourceMode = !this.isSourceMode;
// 切换到源码模式时保存当前表格选中单元格
if (this.isSourceMode) {
if (this.activeCellEl) {
this.sourceCursorPos = { start: 0, end: 0 };
}
} else {
// 切换回表格模式时保存textarea光标位置
if (this.sourceTextarea) {
this.sourceCursorPos = {
start: this.sourceTextarea.selectionStart,
end: this.sourceTextarea.selectionEnd
};
}
}
this.refresh();
}
// 新增:创建搜索容器,接受父容器参数
private createSearchContainer(parentContainer?: HTMLElement) {
// 如果提供了父容器在其中创建搜索框否则在contentEl中创建

View file

@ -437,3 +437,19 @@ td input:focus {
.csv-search-current .csv-cell-input {
background-color: var(--text-highlight-bg) !important;
}
/* 源码模式样式 */
.csv-source-mode {
font-family: var(--font-monospace, monospace);
font-size: 1em;
width: 100%;
min-height: 300px;
resize: vertical;
box-sizing: border-box;
margin: 1em 0;
padding: 0.5em;
background: var(--background-secondary);
color: var(--text-normal);
border: 1px solid var(--background-modifier-border);
border-radius: 4px;
}