Skip to content

Commit 89d3587

Browse files
authored
DataGrid: Fix the focus() method that focuses the interactive element inside a cell instead of the row when focusedRowEnabled is true (T1293309) (#30947)
1 parent fb37c91 commit 89d3587

File tree

6 files changed

+148
-10
lines changed

6 files changed

+148
-10
lines changed

e2e/testcafe-devextreme/tests/dataGrid/common/focus/focus.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,3 +317,58 @@ test('DataGrid - Focused cell appearance is applied to non-editable CheckBox cel
317317
'BoolTwo',
318318
],
319319
}));
320+
321+
// T1293309
322+
test('Focus method should focus the first data cell', async (t) => {
323+
const dataGrid = new DataGrid(GRID_SELECTOR);
324+
325+
await t.expect(dataGrid.isReady()).ok();
326+
327+
await dataGrid.apiFocus();
328+
329+
await t
330+
.expect(dataGrid.getDataCell(0, 0).element.focused)
331+
.ok();
332+
}).before(async () => createWidget('dxDataGrid', {
333+
dataSource: [
334+
{ id: 1, name: 'name 1' },
335+
{ id: 2, name: 'name 2' },
336+
{ id: 3, name: 'name 3' },
337+
],
338+
keyExpr: 'id',
339+
columns: [
340+
'id',
341+
{
342+
dataField: 'name',
343+
cellTemplate: (_, options) => $('<div>').attr('tabindex', 0).text(options.text),
344+
},
345+
],
346+
}));
347+
348+
// T1293309
349+
test('Focus method should focus the first data row when focusedRowEnabled = true', async (t) => {
350+
const dataGrid = new DataGrid(GRID_SELECTOR);
351+
352+
await t.expect(dataGrid.isReady()).ok();
353+
354+
await dataGrid.apiFocus();
355+
356+
await t
357+
.expect(dataGrid.getDataRow(0).element.focused)
358+
.ok();
359+
}).before(async () => createWidget('dxDataGrid', {
360+
dataSource: [
361+
{ id: 1, name: 'name 1' },
362+
{ id: 2, name: 'name 2' },
363+
{ id: 3, name: 'name 3' },
364+
],
365+
keyExpr: 'id',
366+
focusedRowEnabled: true,
367+
columns: [
368+
'id',
369+
{
370+
dataField: 'name',
371+
cellTemplate: (_, options) => $('<div>').attr('tabindex', 0).text(options.text),
372+
},
373+
],
374+
}));
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import TreeList from 'devextreme-testcafe-models/treeList';
2+
import { createWidget } from '../../helpers/createWidget';
3+
import url from '../../helpers/getPageUrl';
4+
5+
fixture.disablePageReloads`Focus`
6+
.page(url(__dirname, '../container.html'));
7+
8+
const TREE_LIST_SELECTOR = '#container';
9+
10+
// T1294363
11+
test('Focus method should focus the first data cell', async (t) => {
12+
const treeList = new TreeList(TREE_LIST_SELECTOR);
13+
14+
await t.expect(treeList.isReady()).ok();
15+
16+
await treeList.apiFocus();
17+
18+
await t
19+
.expect(treeList.getDataCell(0, 0).element.focused)
20+
.ok();
21+
}).before(async () => createWidget('dxTreeList', {
22+
dataSource: [
23+
{ id: 1, parentId: 0, name: 'name 1' },
24+
{ id: 2, parentId: 1, name: 'name 2' },
25+
{ id: 3, parentId: 0, name: 'name 3' },
26+
],
27+
keyExpr: 'id',
28+
parentId: 'parentId',
29+
columns: [
30+
'id',
31+
{
32+
dataField: 'name',
33+
cellTemplate: (_, options) => $('<div>').attr('tabindex', 0).text(options.text),
34+
},
35+
],
36+
}));
37+
38+
// T1294363
39+
test('Focus method should focus the first data row when focusedRowEnabled = true', async (t) => {
40+
const treeList = new TreeList(TREE_LIST_SELECTOR);
41+
42+
await t.expect(treeList.isReady()).ok();
43+
44+
await treeList.apiFocus();
45+
46+
await t
47+
.expect(treeList.getDataRow(0).element.focused)
48+
.ok();
49+
}).before(async () => createWidget('dxTreeList', {
50+
dataSource: [
51+
{ id: 1, parentId: 0, name: 'name 1' },
52+
{ id: 2, parentId: 1, name: 'name 2' },
53+
{ id: 3, parentId: 0, name: 'name 3' },
54+
],
55+
keyExpr: 'id',
56+
parentId: 'parentId',
57+
focusedRowEnabled: true,
58+
columns: [
59+
'id',
60+
{
61+
dataField: 'name',
62+
cellTemplate: (_, options) => $('<div>').attr('tabindex', 0).text(options.text),
63+
},
64+
],
65+
}));

packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_keyboard_navigation.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ import {
8282
isDetailRow,
8383
isEditForm,
8484
isEditorCell,
85+
isEditRow,
8586
isElementDefined,
8687
isFixedColumnIndexOffsetRequired,
8788
isGroupFooterRow,
@@ -1430,10 +1431,10 @@ export class KeyboardNavigationController extends modules.ViewController {
14301431
const isHighlighted = this._isCellElement($(element));
14311432

14321433
if (!element) {
1433-
activeElementSelector = '.dx-datagrid-rowsview .dx-row[tabindex]';
1434+
activeElementSelector = `.${this.addWidgetPrefix(ROWS_VIEW_CLASS)} .dx-row[tabindex]`;
14341435
if (!focusedRowEnabled) {
14351436
activeElementSelector
1436-
+= ', .dx-datagrid-rowsview .dx-row > td[tabindex]';
1437+
+= `, .${this.addWidgetPrefix(ROWS_VIEW_CLASS)} .dx-row > td[tabindex]`;
14371438
}
14381439
element = this.component.$element().find(activeElementSelector).first();
14391440
}
@@ -1477,14 +1478,18 @@ export class KeyboardNavigationController extends modules.ViewController {
14771478
isHighlighted,
14781479
);
14791480
$element = args.$newCellElement;
1481+
14801482
if (isRowFocusType && !args.isHighlighted) {
14811483
this.setRowFocusType();
14821484
}
14831485
}
14841486

14851487
if (!args.cancel) {
14861488
this._focus($element, !args.isHighlighted);
1487-
this._focusInteractiveElement($element);
1489+
1490+
if (this._getElementType($element) !== 'row' || isEditRow($element)) {
1491+
this._focusInteractiveElement($element);
1492+
}
14881493
}
14891494
}
14901495

packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_keyboard_navigation_utils.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import devices from '@js/core/devices';
22
import { isDefined } from '@js/core/utils/type';
33

4-
import { EDITOR_CELL_CLASS } from '../editing/const';
4+
import { EDIT_ROW, EDITOR_CELL_CLASS } from '../editing/const';
55
import {
66
ADAPTIVE_ITEM_TEXT_CLASS,
77
COMMAND_SELECT_CLASS, DATA_ROW_CLASS, EDIT_FORM_CLASS, FREESPACE_ROW_CLASS, GROUP_ROW_CLASS, HEADER_ROW_CLASS,
@@ -24,6 +24,10 @@ export function isAdaptiveItem($element) {
2424
return $element && $element.hasClass(ADAPTIVE_ITEM_TEXT_CLASS);
2525
}
2626

27+
export function isEditRow($row) {
28+
return $row?.hasClass(EDIT_ROW);
29+
}
30+
2731
export function isEditForm($row) {
2832
return $row && $row.hasClass(MASTER_DETAIL_ROW_CLASS) && $row.hasClass(EDIT_FORM_CLASS);
2933
}

packages/devextreme/js/__internal/grids/tree_list/m_widget_base.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import './m_grid_view';
99
import './module_not_extended/header_panel';
1010

1111
import registerComponent from '@js/core/component_registrator';
12-
import { isDefined } from '@js/core/utils/type';
1312
import { isMaterialBased } from '@js/ui/themes';
1413
import type { Properties as dxTreeListOptions } from '@js/ui/tree_list';
1514
import gridCoreUtils from '@ts/grids/grid_core/m_utils';
@@ -105,11 +104,7 @@ class TreeList extends GridCoreWidget<dxTreeListOptions> {
105104
}
106105

107106
public focus(element?) {
108-
super.focus();
109-
110-
if (isDefined(element)) {
111-
this.getController('keyboardNavigation').focus(element);
112-
}
107+
this.getController('keyboardNavigation').focus(element);
113108
}
114109
}
115110

packages/testcafe-models/dataGrid/index.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,20 @@ export default class DataGrid extends Widget {
727727
)();
728728
}
729729

730+
731+
apiFocus(): Promise<void> {
732+
const { getInstance } = this;
733+
734+
return ClientFunction(
735+
() => (getInstance() as any).focus(),
736+
{
737+
dependencies: {
738+
getInstance,
739+
},
740+
},
741+
)();
742+
}
743+
730744
moveRow(rowIndex: number, x: number, y: number, isStart = false): Promise<void> {
731745
const { getInstance } = this;
732746

0 commit comments

Comments
 (0)