Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions docs/assets/guide/en/sheet/edit_control.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Edit Capability Control

In `VTableSheet`, the editing capability is enabled by default. However, in some scenarios (such as preview mode or permission control), you may need to disable editing globally or for specific sheets.

VTableSheet provides flexible configuration options to control the editing capability and keyboard shortcuts at both the global and sheet levels.

## Configuration Options

### editable

- **Type**: `boolean`
- **Default**: `true` (if not configured globally or on the sheet)
- **Description**: Controls whether the table is editable.
- When set to `false`, the table enters **Read-Only Mode**:
- Double-click editing is disabled.
- Editors are not registered.
- Modification shortcuts (Cut, Paste, etc.) are disabled.
- Context menu items related to modification (Insert/Delete rows, Merge cells, etc.) are hidden or disabled.
- The Delete/Backspace key will not clear cell content (unless configured otherwise).
- **Priority**: The configuration on a specific sheet (`ISheetDefine.editable`) takes precedence over the global configuration (`IVTableSheetOptions.editable`).

### keyboardShortcutPolicy

- **Type**: `SheetKeyboardShortcutPolicy`
- **Description**: Defines the policy for keyboard shortcuts, allowing fine-grained control over specific actions.
- **Properties**:
- `copySelected` (boolean): Enable copy shortcut (Ctrl+C). Default `true`.
- `cutSelected` (boolean): Enable cut shortcut (Ctrl+X). Default `true` (disabled in Read-Only mode).
- `pasteValueToCell` (boolean): Enable paste shortcut (Ctrl+V). Default `true` (disabled in Read-Only mode).
- `selectAllOnCtrlA` (boolean): Enable select all shortcut (Ctrl+A). Default `true`.
- `deleteRange` (boolean): Enable clearing cell content with Delete/Backspace. Default `true` (disabled in Read-Only mode).
- ... (other navigation shortcuts like `moveFocusCellOnTab`, `editCellOnEnter`, etc.)

## Usage Examples

### 1. Global Read-Only Mode

You can set the entire workbook to read-only by configuring `editable: false` in the initialization options.

```typescript
import { VTableSheet } from '@visactor/vtable-sheet';

const sheet = new VTableSheet(container, {
editable: false, // Global read-only
sheets: [
{
sheetKey: 'sheet1',
data: data1
},
{
sheetKey: 'sheet2',
data: data2
}
]
});
```

### 2. Mixed Mode (Global Read-Only with Specific Editable Sheets)

You can set the global default to read-only, and enable editing for specific sheets.

```typescript
const sheet = new VTableSheet(container, {
editable: false, // Default read-only
sheets: [
{
sheetKey: 'read_only_sheet',
sheetTitle: 'Read Only',
data: data1
// Inherits global editable: false
},
{
sheetKey: 'editable_sheet',
sheetTitle: 'Editable',
data: data2,
editable: true // Override global setting
}
]
});
```

### 3. Custom Keyboard Shortcut Policy

You can customize the keyboard behavior. For example, disable Cut and Paste but allow Copy, or disable clearing content with the Delete key.

```typescript
const sheet = new VTableSheet(container, {
// Global policy: Allow copy, disable cut/paste
keyboardShortcutPolicy: {
copySelected: true,
cutSelected: false,
pasteValueToCell: false
},
sheets: [
{
sheetKey: 'sheet1',
data: data1
},
{
sheetKey: 'sheet2',
data: data2,
// Sheet-level policy: Allow delete range
keyboardShortcutPolicy: {
deleteRange: true
}
}
]
});
```
109 changes: 109 additions & 0 deletions docs/assets/guide/zh/sheet/edit_control.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Edit Capability Control

In `VTableSheet`, the editing capability is enabled by default. However, in some scenarios (such as preview mode or permission control), you may need to disable editing globally or for specific sheets.

VTableSheet provides flexible configuration options to control the editing capability and keyboard shortcuts at both the global and sheet levels.

## Configuration Options

### editable

- **Type**: `boolean`
- **Default**: `true` (if not configured globally or on the sheet)
- **Description**: Controls whether the table is editable.
- When set to `false`, the table enters **Read-Only Mode**:
- Double-click editing is disabled.
- Editors are not registered.
- Modification shortcuts (Cut, Paste, etc.) are disabled.
- Context menu items related to modification (Insert/Delete rows, Merge cells, etc.) are hidden or disabled.
- The Delete/Backspace key will not clear cell content (unless configured otherwise).
- **Priority**: The configuration on a specific sheet (`ISheetDefine.editable`) takes precedence over the global configuration (`IVTableSheetOptions.editable`).

### keyboardShortcutPolicy

- **Type**: `SheetKeyboardShortcutPolicy`
- **Description**: Defines the policy for keyboard shortcuts, allowing fine-grained control over specific actions.
- **Properties**:
- `copySelected` (boolean): Enable copy shortcut (Ctrl+C). Default `true`.
- `cutSelected` (boolean): Enable cut shortcut (Ctrl+X). Default `true` (disabled in Read-Only mode).
- `pasteValueToCell` (boolean): Enable paste shortcut (Ctrl+V). Default `true` (disabled in Read-Only mode).
- `selectAllOnCtrlA` (boolean): Enable select all shortcut (Ctrl+A). Default `true`.
- `deleteRange` (boolean): Enable clearing cell content with Delete/Backspace. Default `true` (disabled in Read-Only mode).
- ... (other navigation shortcuts like `moveFocusCellOnTab`, `editCellOnEnter`, etc.)

## Usage Examples

### 1. Global Read-Only Mode

You can set the entire workbook to read-only by configuring `editable: false` in the initialization options.

```typescript
import { VTableSheet } from '@visactor/vtable-sheet';

const sheet = new VTableSheet(container, {
editable: false, // Global read-only
sheets: [
{
sheetKey: 'sheet1',
data: data1
},
{
sheetKey: 'sheet2',
data: data2
}
]
});
```

### 2. Mixed Mode (Global Read-Only with Specific Editable Sheets)

You can set the global default to read-only, and enable editing for specific sheets.

```typescript
const sheet = new VTableSheet(container, {
editable: false, // Default read-only
sheets: [
{
sheetKey: 'read_only_sheet',
sheetTitle: 'Read Only',
data: data1
// Inherits global editable: false
},
{
sheetKey: 'editable_sheet',
sheetTitle: 'Editable',
data: data2,
editable: true // Override global setting
}
]
});
```

### 3. Custom Keyboard Shortcut Policy

You can customize the keyboard behavior. For example, disable Cut and Paste but allow Copy, or disable clearing content with the Delete key.

```typescript
const sheet = new VTableSheet(container, {
// Global policy: Allow copy, disable cut/paste
keyboardShortcutPolicy: {
copySelected: true,
cutSelected: false,
pasteValueToCell: false
},
sheets: [
{
sheetKey: 'sheet1',
data: data1
},
{
sheetKey: 'sheet2',
data: data2,
// Sheet-level policy: Allow delete range
keyboardShortcutPolicy: {
deleteRange: true
}
}
]
});
```
33 changes: 33 additions & 0 deletions docs/assets/option/zh/table/sheet.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@

是否是当前活动工作表。

### editable(boolean)

是否允许编辑该工作表。
- `true`: 允许编辑(默认)。
- `false`: 只读模式。
**优先级**:此配置优先级高于全局 `IVTableSheetOptions.editable`。

### keyboardShortcutPolicy(SheetKeyboardShortcutPolicy)

该工作表的快捷键策略配置。可用于覆盖全局的快捷键策略。
具体配置项参考全局配置中的 `keyboardShortcutPolicy`。

### cellMerge(CustomMergeCellArray)

单元格合并配置,格式为:
Expand Down Expand Up @@ -184,6 +196,27 @@ rowHeightConfig: {
## defaultColWidth(number) = 100
默认列宽。

## editable(boolean) = true

全局编辑能力开关。
- `true`: 默认所有工作表可编辑(除非工作表单独配置为只读)。
- `false`: 默认所有工作表只读(除非工作表单独配置为可编辑)。
只读模式下:
- 双击和按键无法进入编辑状态。
- 剪切、粘贴等修改性快捷键被禁用。
- Delete/Backspace 无法清空单元格。
- 右键菜单中的修改项被隐藏。

## keyboardShortcutPolicy(SheetKeyboardShortcutPolicy)

全局快捷键策略配置。定义了允许或禁用的快捷键行为。
常用属性:
- `copySelected` (boolean): 是否允许复制 (Ctrl+C)。默认 true。
- `cutSelected` (boolean): 是否允许剪切 (Ctrl+X)。只读模式下强制 false。
- `pasteValueToCell` (boolean): 是否允许粘贴 (Ctrl+V)。只读模式下强制 false。
- `selectAllOnCtrlA` (boolean): 是否允许全选 (Ctrl+A)。默认 true。
- `deleteRange` (boolean): 是否允许 Delete/Backspace 清空选区。只读模式下强制 false。

## dragOrder(Object)

拖拽列顺序和行顺序配置。
Expand Down
14 changes: 8 additions & 6 deletions packages/vtable-plugins/src/context-menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,10 @@ export class ContextMenuPlugin implements pluginsDefinition.IVTablePlugin {
if (this.pluginOptions.beforeShowAdjustMenuItems) {
menuItems = this.pluginOptions.beforeShowAdjustMenuItems(menuItems, table as ListTable, col, row);
}

// 显示右键菜单
this.showContextMenu(menuItems, mouseX, mouseY, col, row);
if (menuItems.length > 0) {
// 显示右键菜单
this.showContextMenu(menuItems, mouseX, mouseY, col, row);
}
}
};

Expand Down Expand Up @@ -175,9 +176,10 @@ export class ContextMenuPlugin implements pluginsDefinition.IVTablePlugin {
if (this.pluginOptions.beforeShowAdjustMenuItems) {
menuItems = this.pluginOptions.beforeShowAdjustMenuItems(menuItems, table as ListTable, colIndex, rowIndex);
}

// 显示右键菜单
this.showContextMenu(menuItems, mouseX, mouseY, colIndex, rowIndex);
if (menuItems.length > 0) {
// 显示右键菜单
this.showContextMenu(menuItems, mouseX, mouseY, colIndex, rowIndex);
}
}
};

Expand Down
28 changes: 27 additions & 1 deletion packages/vtable-plugins/src/excel-edit-cell-keyboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,30 @@ export class ExcelEditCellKeyboardPlugin implements pluginsDefinition.IVTablePlu
// this.pluginOptions?.keyDown_before?.(event);
if (this.table?.editorManager && this.isExcelShortcutKey(event)) {
const eventKey = event.key.toLowerCase() as ExcelEditCellKeyboardResponse;
//判断是键盘触发编辑单元格的情况下,那么在编辑状态中切换方向需要选中下一个继续编辑

let editable = true;
let deleteRangeEnabled = true;

const vtableSheet = (this.table as any).__vtableSheet;
const activeSheet = vtableSheet?.getActiveSheet?.();
const sheetOptions = activeSheet?.options as
| { editable?: boolean; keyboardShortcutPolicy?: { deleteRange?: boolean } }
| undefined;

if (sheetOptions) {
editable = sheetOptions.editable !== false;
deleteRangeEnabled = sheetOptions.keyboardShortcutPolicy?.deleteRange ?? true;
}

const isDeleteKey =
eventKey === ExcelEditCellKeyboardResponse.DELETE || eventKey === ExcelEditCellKeyboardResponse.BACKSPACE;

if (isDeleteKey && (!editable || !deleteRangeEnabled)) {
event.stopPropagation();
event.preventDefault();
return;
}

if (this.table.editorManager.editingEditor && this.table.editorManager.beginTriggerEditCellMode === 'keydown') {
const { col, row } = this.table.editorManager.editCell;
if (eventKey !== ExcelEditCellKeyboardResponse.BACKSPACE && eventKey !== ExcelEditCellKeyboardResponse.DELETE) {
Expand Down Expand Up @@ -122,6 +145,9 @@ export class ExcelEditCellKeyboardPlugin implements pluginsDefinition.IVTablePlu
!this.table.editorManager.editingEditor &&
(eventKey === ExcelEditCellKeyboardResponse.DELETE || eventKey === ExcelEditCellKeyboardResponse.BACKSPACE)
) {
if (!deleteRangeEnabled) {
return;
}
//响应删除键,删除
const selectCells = this.table.getSelectedCellInfos();
if (
Expand Down
28 changes: 23 additions & 5 deletions packages/vtable-sheet/src/components/vtable-sheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as VTable from '@visactor/vtable';
import { getTablePlugins } from '../core/table-plugins';
import { DomEventManager } from '../event/dom-event-manager';
import { showSnackbar } from '../tools/ui/snackbar';
import type { IVTableSheetOptions, ISheetDefine } from '../ts-types';
import type { IVTableSheetOptions, ISheetDefine, SheetKeyboardShortcutPolicy } from '../ts-types';
import type { MultiSheetImportResult } from '@visactor/vtable-plugins/src/excel-import/types';
import type { TableEventHandlersEventArgumentMap } from '@visactor/vtable/es/ts-types/events';
import SheetTabDragManager from '../managers/tab-drag-manager';
Expand Down Expand Up @@ -478,6 +478,18 @@ export default class VTableSheet {
const contentWidth = this.contentElement.clientWidth;
const contentHeight = this.contentElement.clientHeight;
sheetDefine.dragOrder = sheetDefine.dragOrder ?? this.options.dragOrder;

const globalEditable = this.options.editable;
const sheetEditable = sheetDefine.editable;
const effectiveEditable = sheetEditable ?? (globalEditable ?? true);

const effectiveKeyboardPolicy =
(this.options.keyboardShortcutPolicy || sheetDefine.keyboardShortcutPolicy) &&
{
...(this.options.keyboardShortcutPolicy as SheetKeyboardShortcutPolicy),
...(sheetDefine.keyboardShortcutPolicy as SheetKeyboardShortcutPolicy)
};

// 创建sheet实例
const sheet = new WorkSheet(this, {
...sheetDefine,
Expand All @@ -488,8 +500,12 @@ export default class VTableSheet {
defaultColWidth: this.options.defaultColWidth,
dragOrder: sheetDefine.dragOrder,
plugins: getTablePlugins(sheetDefine, this.options, this),
headerEditor: 'formula',
editor: 'formula',
...(effectiveEditable
? {
headerEditor: 'formula',
editor: 'formula'
}
: {}),
select: {
makeSelectCellVisible: false
},
Expand All @@ -499,9 +515,11 @@ export default class VTableSheet {
borderLineDash: [null, null, null, null],
padding: [8, 8, 8, 8]
},
editCellTrigger: ['api', 'keydown', 'doubleclick'],
editCellTrigger: effectiveEditable ? ['api', 'keydown', 'doubleclick'] : ['api'],
customMergeCell: sheetDefine.cellMerge,
theme: sheetDefine.theme?.tableTheme || this.options.theme?.tableTheme
theme: sheetDefine.theme?.tableTheme || this.options.theme?.tableTheme,
editable: effectiveEditable,
keyboardShortcutPolicy: effectiveKeyboardPolicy as SheetKeyboardShortcutPolicy | undefined
} as any);

// 事件系统现在通过 TableEventRelay 自动处理,不再需要手动绑定
Expand Down
Loading
Loading