Skip to content

Commit bf9225c

Browse files
authored
Merge pull request #4852 from VisActor/refactor/keydownTriggerEditChinese
Refactor/keydown trigger edit chinese
2 parents 42ae217 + 1dbdc09 commit bf9225c

13 files changed

Lines changed: 281 additions & 68 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"changes": [
3+
{
4+
"comment": "refactor: when set editCellTrigger keydown input chinese first letter problem #4847\n\n",
5+
"type": "none",
6+
"packageName": "@visactor/vtable"
7+
}
8+
],
9+
"packageName": "@visactor/vtable",
10+
"email": "892739385@qq.com"
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"changes": [
3+
{
4+
"comment": "fix: editor support keydown chinese #4847\n\n",
5+
"type": "none",
6+
"packageName": "@visactor/vtable"
7+
}
8+
],
9+
"packageName": "@visactor/vtable",
10+
"email": "892739385@qq.com"
11+
}

packages/vtable-editors/src/input-editor.ts

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { CellAddress, EditContext, IEditor, RectProps } from './types';
1+
import type { CellAddress, EditContext, IEditor, PrepareEditContext, RectProps } from './types';
22
import type { ValidateEnum } from './types';
33

44
export interface InputEditorConfig {
@@ -14,10 +14,12 @@ export class InputEditor implements IEditor {
1414
table?: any;
1515
col?: number;
1616
row?: number;
17-
1817
constructor(editorConfig?: InputEditorConfig) {
1918
this.editorConfig = editorConfig;
2019
}
20+
getInputElement(): HTMLInputElement {
21+
return this.element;
22+
}
2123

2224
createElement() {
2325
const input = document.createElement('input');
@@ -40,9 +42,15 @@ export class InputEditor implements IEditor {
4042
input.style.outline = 'none';
4143
});
4244

43-
input.addEventListener('blur', () => {
45+
input.addEventListener('blur', e => {
4446
input.style.borderColor = '#d9d9d9';
4547
// input.style.boxShadow = 'none';
48+
if (this.table && this.element.style.opacity === '0') {
49+
const selectCell = this.table.stateManager.select.cellPos;
50+
if (selectCell.col !== this.col || selectCell.row !== this.row) {
51+
this.onEnd();
52+
}
53+
}
4654
});
4755
// #endregion
4856
this.element = input;
@@ -69,7 +77,31 @@ export class InputEditor implements IEditor {
6977
getValue() {
7078
return this.element.value;
7179
}
72-
80+
/**
81+
* 如果表格编辑时机配置editCellTrigger为keydown,则需要调用prepareEdit来准备编辑环境,否则中文输入法第一个字符会被当做英文字符
82+
* @param param0
83+
*/
84+
prepareEdit({ referencePosition, container, table, col, row }: PrepareEditContext<string>) {
85+
this.container = container;
86+
this.table = table;
87+
this.col = col;
88+
this.row = row;
89+
const selectCell = this.table.stateManager.select.cellPos;
90+
if (selectCell.col !== this.col || selectCell.row !== this.row) {
91+
return;
92+
}
93+
if (!this.element) {
94+
this.createElement();
95+
}
96+
this.element.style.opacity = '0';
97+
//这个pointerEvents = 'none'很重要,如果没有的话会引起vtable.getElement()元素和这里的element元素的focus和blur的切换,
98+
//也会引起mouseleave_table mouseleave_cell和mouseenter的切换
99+
this.element.style.pointerEvents = 'none';
100+
if (referencePosition?.rect) {
101+
this.adjustPosition(referencePosition.rect);
102+
}
103+
this.element.focus();
104+
}
73105
onStart({ value, referencePosition, container, endEdit, table, col, row }: EditContext<string>) {
74106
this.container = container;
75107
this.successCallback = endEdit;
@@ -78,14 +110,16 @@ export class InputEditor implements IEditor {
78110
this.row = row;
79111
if (!this.element) {
80112
this.createElement();
81-
82-
if (value !== undefined && value !== null) {
83-
this.setValue(value);
84-
}
85113
if (referencePosition?.rect) {
86114
this.adjustPosition(referencePosition.rect);
87115
}
88116
}
117+
if (value !== undefined && value !== null) {
118+
this.setValue(value);
119+
}
120+
//防止调用过prepareEdit 后,元素的显示和可操作性被影响
121+
this.element.style.opacity = '1';
122+
this.element.style.pointerEvents = 'auto';
89123
this.element.focus();
90124
// do nothing
91125
}
@@ -112,8 +146,8 @@ export class InputEditor implements IEditor {
112146
// do nothing
113147
if (this.container?.contains(this.element)) {
114148
this.container.removeChild(this.element);
149+
this.element = undefined;
115150
}
116-
this.element = undefined;
117151
}
118152

119153
isEditorElement(target: HTMLElement) {

packages/vtable-editors/src/types.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export interface IEditor<V = any, T = any> {
1717
*/
1818
onEnd: () => void;
1919
getInputElement?: () => HTMLElement;
20+
setElement?: (element: HTMLInputElement) => void;
2021
/**
2122
* Called when user click somewhere while editor is in edit mode.
2223
*
@@ -46,6 +47,11 @@ export interface IEditor<V = any, T = any> {
4647
* Expected to return the current value of the cell.
4748
*/
4849
getValue: () => V;
50+
/**
51+
* If the table editing trigger is configured as keydown, you need to call prepareEdit to prepare the editing environment, otherwise the first character of the Chinese input method will be treated as an English character.
52+
* @param param0
53+
*/
54+
prepareEdit?: (context: PrepareEditContext<V, T>) => void;
4955
/**
5056
* Called when cell enter edit mode.
5157
* @deprecated use `onStart` instead.
@@ -68,6 +74,7 @@ export interface IEditor<V = any, T = any> {
6874
* @deprecated callback is provided as `endEdit` in `EditContext`, use `onStart` instead.
6975
*/
7076
bindSuccessCallback?: (callback: () => void) => void;
77+
adjustPosition?: (rect: RectProps) => void;
7178
}
7279

7380
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -96,6 +103,13 @@ export interface EditContext<V = any, T = any> {
96103
row: number;
97104
}
98105

106+
export interface PrepareEditContext<V = any, T = any> {
107+
container: HTMLElement;
108+
table: T;
109+
col: number;
110+
row: number;
111+
referencePosition: ReferencePosition;
112+
}
99113
export interface RectProps {
100114
left: number;
101115
top: number;

packages/vtable/examples/editor/custom-date-editor.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ export function createTable() {
309309
container: document.getElementById(CONTAINER_ID),
310310
records,
311311
columns,
312+
editCellTrigger: ['keydown', 'doubleclick'],
312313
keyboardOptions: {
313314
copySelected: true,
314315
pasteValueToCell: true,

packages/vtable/examples/editor/date-editor.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,10 @@ export function createTable() {
179179
heightMode: 'autoHeight',
180180
autoWrapText: true,
181181
editCellTrigger: ['keydown', 'doubleclick'],
182+
182183
keyboardOptions: {
183-
moveFocusCellOnEnter: true
184+
moveFocusCellOnEnter: true,
185+
moveEditCellOnArrowKeys: true
184186
},
185187
editor(args) {
186188
return new InputEditor({});

packages/vtable/examples/editor/input-editor.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as VTable from '../../src';
22
import { InputEditor } from '@visactor/vtable-editors';
33
import { bindDebugTool } from '../../src/scenegraph/debug-tool';
4+
import { TABLE_EVENT_TYPE } from '../../src';
45
const ListTable = VTable.ListTable;
56
const CONTAINER_ID = 'vTable';
67
const input_editor = new InputEditor({});
@@ -136,6 +137,7 @@ export function createTable() {
136137
const option: VTable.ListTableConstructorOptions = {
137138
emptyTip: true,
138139
container: document.getElementById(CONTAINER_ID),
140+
editCellTrigger: 'keydown',
139141
columns: [
140142
{
141143
field: 'progress',
@@ -170,6 +172,12 @@ export function createTable() {
170172
}
171173
}
172174
],
175+
hover: {
176+
highlightMode: 'cross'
177+
},
178+
keyboardOptions: {
179+
selectAllOnCtrlA: true
180+
},
173181
showFrozenIcon: true, //显示VTable内置冻结列图标
174182
widthMode: 'standard',
175183
autoFillWidth: true,
@@ -185,10 +193,30 @@ export function createTable() {
185193
field: 'progress',
186194
order: 'desc'
187195
});
188-
189-
instance.on('change_cell_value', arg => {
190-
console.log(arg);
196+
// instance.on(TABLE_EVENT_TYPE.CLICK_CELL, e => {
197+
// console.log('click-cell', e);
198+
// });
199+
// instance.on(TABLE_EVENT_TYPE.SELECTED_CHANGED, e => {
200+
// console.log('selected_changed', e);
201+
// });
202+
instance.on(TABLE_EVENT_TYPE.DRAG_SELECT_END, e => {
203+
console.log('drag_select_end', e);
191204
});
205+
// instance.on('change_cell_value', arg => {
206+
// console.log('.....change_cell_value');
207+
// });
208+
// instance.on('mouseleave_cell', arg => {
209+
// console.log('.....mouseleave_cell');
210+
// });
211+
// instance.on('mouseenter_cell', arg => {
212+
// console.log('.....mouseenter_cell');
213+
// });
214+
// instance.on('mouseleave_table', arg => {
215+
// console.log('.....mouseleave_table');
216+
// });
217+
// instance.on('mouseenter_table', arg => {
218+
// console.log('.....mouseenter_table');
219+
// });
192220

193221
// bindDebugTool(instance.scenegraph.stage as any, {
194222
// customGrapicKeys: ['role', '_updateTag']

packages/vtable/examples/index.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@
1717
<div class="container">
1818
<div class="sidebar" id="sidebar"></div>
1919
<div class="content">
20+
<div id="input-test">
21+
<input type="text" />
22+
</div>
23+
<br />
24+
<div id="textarea-test">
25+
<textarea></textarea>
26+
</div>
2027
<div id="chartContainer">
2128
<div id="vTable" style="position: relative; height: 100%; width: 100%; overflow: hidden"></div>
2229
</div>

packages/vtable/src/ListTable.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1532,25 +1532,31 @@ export class ListTable extends BaseTable implements ListTableAPI {
15321532
}
15331533
/** 获取单元格对应的编辑器 */
15341534
getEditor(col: number, row: number) {
1535+
const lastSelectedCellEditor = this.editorManager.cacheLastSelectedCellEditor[`${col}-${row}`];
1536+
if (lastSelectedCellEditor) {
1537+
return lastSelectedCellEditor;
1538+
}
15351539
const define = this.getBodyColumnDefine(col, row);
1536-
let editorDefine = this.isHeader(col, row)
1540+
let editor = this.isHeader(col, row)
15371541
? (define as ColumnDefine)?.headerEditor ?? this.options.headerEditor
15381542
: (define as ColumnDefine)?.editor ?? this.options.editor;
15391543

1540-
if (typeof editorDefine === 'function') {
1544+
if (typeof editor === 'function') {
15411545
const arg = {
15421546
col,
15431547
row,
15441548
dataValue: this.getCellOriginValue(col, row),
15451549
value: this.getCellValue(col, row) || '',
15461550
table: this
15471551
};
1548-
editorDefine = (editorDefine as Function)(arg);
1552+
editor = (editor as Function)(arg);
15491553
}
1550-
if (typeof editorDefine === 'string') {
1551-
return editors.get(editorDefine);
1554+
if (typeof editor === 'string') {
1555+
editor = editors.get(editor);
15521556
}
1553-
return editorDefine as IEditor;
1557+
this.editorManager.cacheLastSelectedCellEditor = {};
1558+
this.editorManager.cacheLastSelectedCellEditor[`${col}-${row}`] = editor as IEditor;
1559+
return editor as IEditor;
15541560
}
15551561
/** 检查单元格是否定义过编辑器 不管编辑器是否有效 只要有定义就返回true */
15561562
isHasEditorDefine(col: number, row: number) {

packages/vtable/src/PivotTable.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1755,31 +1755,37 @@ export class PivotTable extends BaseTable implements PivotTableAPI {
17551755
}
17561756
/** 获取单元格对应的编辑器 */
17571757
getEditor(col: number, row: number) {
1758-
let editorDefine;
1758+
const lastSelectedCellEditor = this.editorManager.cacheLastSelectedCellEditor[`${col}-${row}`];
1759+
if (lastSelectedCellEditor) {
1760+
return lastSelectedCellEditor;
1761+
}
1762+
let editor;
17591763
if (this.isCornerHeader(col, row)) {
17601764
const define = this.getHeaderDefine(col, row);
1761-
editorDefine = (define as ColumnDefine)?.headerEditor ?? this.options.headerEditor;
1765+
editor = (define as ColumnDefine)?.headerEditor ?? this.options.headerEditor;
17621766
} else if (this.isHeader(col, row)) {
17631767
const define = this.getHeaderDefine(col, row);
1764-
editorDefine = (define as ColumnDefine)?.headerEditor ?? this.options.headerEditor;
1768+
editor = (define as ColumnDefine)?.headerEditor ?? this.options.headerEditor;
17651769
} else {
17661770
const define = this.getBodyColumnDefine(col, row);
1767-
editorDefine = (define as ColumnDefine)?.editor ?? this.options.editor;
1771+
editor = (define as ColumnDefine)?.editor ?? this.options.editor;
17681772
}
1769-
if (typeof editorDefine === 'function') {
1773+
if (typeof editor === 'function') {
17701774
const arg = {
17711775
col,
17721776
row,
17731777
dataValue: this.getCellOriginValue(col, row),
17741778
value: this.getCellValue(col, row) || '',
17751779
table: this
17761780
};
1777-
editorDefine = (editorDefine as Function)(arg);
1781+
editor = (editor as Function)(arg);
17781782
}
1779-
if (typeof editorDefine === 'string') {
1780-
return editors.get(editorDefine);
1783+
if (typeof editor === 'string') {
1784+
editor = editors.get(editor);
17811785
}
1782-
return editorDefine as IEditor;
1786+
this.editorManager.cacheLastSelectedCellEditor = {};
1787+
this.editorManager.cacheLastSelectedCellEditor[`${col}-${row}`] = editor as IEditor;
1788+
return editor as IEditor;
17831789
}
17841790
/** 检查单元格是否定义过编辑器 不管编辑器是否有效 只要有定义就返回true */
17851791
isHasEditorDefine(col: number, row: number) {

0 commit comments

Comments
 (0)