From d0123e6b5ae13eb5b75a3393fa9d87598bde9858 Mon Sep 17 00:00:00 2001 From: JayBridge <12310903@mail.sustech.edu.cn> Date: Thu, 19 Jun 2025 11:14:10 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E6=BA=90=E7=A0=81?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E5=92=8C=E7=9B=B8=E5=85=B3=E6=A0=B7=E5=BC=8F?= =?UTF-8?q?=EF=BC=8C=E6=94=AF=E6=8C=81=E5=9C=A8=E8=A1=A8=E6=A0=BC=E5=92=8C?= =?UTF-8?q?=E6=BA=90=E7=A0=81=E8=A7=86=E5=9B=BE=E4=B9=8B=E9=97=B4=E5=88=87?= =?UTF-8?q?=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/i18n/en.ts | 4 +++- src/i18n/index.ts | 3 +++ src/i18n/zh-cn.ts | 4 +++- src/view.ts | 61 +++++++++++++++++++++++++++++++++++++++++++++-- styles.css | 16 +++++++++++++ 5 files changed, 84 insertions(+), 4 deletions(-) diff --git a/src/i18n/en.ts b/src/i18n/en.ts index 2d12acf..51937b6 100644 --- a/src/i18n/en.ts +++ b/src/i18n/en.ts @@ -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...' diff --git a/src/i18n/index.ts b/src/i18n/index.ts index 69715b7..e7f76c1 100644 --- a/src/i18n/index.ts +++ b/src/i18n/index.ts @@ -85,3 +85,6 @@ export class I18n { } export const i18n = new I18n(); + +export * from "./en"; +export * from "./zh-cn"; diff --git a/src/i18n/zh-cn.ts b/src/i18n/zh-cn.ts index 9874485..59d59b3 100644 --- a/src/i18n/zh-cn.ts +++ b/src/i18n/zh-cn.ts @@ -6,7 +6,9 @@ export const zhCN = { deleteRow: '删除行', addColumn: '添加列', deleteColumn: '删除列', - resetColumnWidth: '重置列宽' + resetColumnWidth: '重置列宽', + sourceMode: '源码模式', + tableMode: '表格模式' }, editBar: { placeholder: '编辑选中单元格...' diff --git a/src/view.ts b/src/view.ts index 731eeb1..15945e7 100644 --- a/src/view.ts +++ b/src/view.ts @@ -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中创建 diff --git a/styles.css b/styles.css index 43a05b0..460c2ce 100644 --- a/styles.css +++ b/styles.css @@ -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; +}