diff --git a/apps/react-storybook/stories/examples/datagrid/DataGrid.stories.tsx b/apps/react-storybook/stories/examples/datagrid/DataGrid.stories.tsx index 2616109bcc90..350f9ab97f42 100644 --- a/apps/react-storybook/stories/examples/datagrid/DataGrid.stories.tsx +++ b/apps/react-storybook/stories/examples/datagrid/DataGrid.stories.tsx @@ -53,7 +53,6 @@ const columnOptions = { dataField: 'Country', fixed: true, }, - 'Country', 'Area', 'Population_Urban', 'Population_Rural', @@ -118,6 +117,24 @@ const columnOptions = { }], }], }], + groupColumns: [ + 'ID', + { + dataField: 'Country', + groupIndex: 0, + }, + { + dataField: 'Area', + groupIndex: 1, + }, + 'Population_Urban', + 'Population_Rural', + 'Population_Total', + 'GDP_Agriculture', + 'GDP_Industry', + 'GDP_Services', + 'GDP_Total', + ], }; const meta: Meta = { @@ -227,5 +244,8 @@ export const ColumnReordering: Story = { columnFixing: { enabled: false }, + groupPanel: { + visible: true, + }, } } diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/columnReordering.visual.ts b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/columnReordering.visual.ts index 51ebc9d09e36..f3164c068582 100644 --- a/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/columnReordering.visual.ts +++ b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/columnReordering.visual.ts @@ -139,6 +139,38 @@ test('The column should not be reordered when it has allowReordering set to fals }); }); +test('The column should not be reordered when allowColumnReordering is false and group panel is visible', async (t) => { + const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + const dataGrid = new DataGrid(DATA_GRID_SELECTOR); + const firstHeaderCell = dataGrid.getHeaders().getHeaderRow(0).getHeaderCell(0); + + await t + .click(firstHeaderCell.element) + .pressKey('ctrl+right'); + + await takeScreenshot( + 'reorder_column_when_allowColumnReordering_is_false_and_group_panel_is_visible', + dataGrid.element, + ); + + await t.expect(compareResults.isValid()) + .ok(compareResults.errorMessages()); +}).before(async () => { + await createWidget('dxDataGrid', { + allowColumnReordering: false, + groupPanel: { + visible: true, + allowColumnDragging: true, + }, + dataSource: [{ + field1: 'test1', + field2: 'test2', + field3: 'test3', + field4: 'test4', + }], + }); +}); + // Fixed columns test('reorder fixed left column to right', async (t) => { const { takeScreenshot, compareResults } = createScreenshotsComparer(t); @@ -386,6 +418,118 @@ test('reorder sticky column to right when there are fixed columns', async (t) => }); }); +test('reorder fixed right column to right when there is a command column on the right', async (t) => { + const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + const dataGrid = new DataGrid(DATA_GRID_SELECTOR); + const firstFixedRightHeader = dataGrid.getHeaders().getHeaderRow(0).getHeaderCell(6); + + await t + .click(firstFixedRightHeader.element) + .pressKey('ctrl+right') + .pressKey('ctrl+right'); + + await takeScreenshot( + 'reorder_fixed_right_column_to_right_when_there_is_command_column_on_right', + dataGrid.element, + ); + + await t.expect(compareResults.isValid()) + .ok(compareResults.errorMessages()); +}).before(async () => { + await createWidget('dxDataGrid', { + columnWidth: 100, + allowColumnReordering: true, + editing: { + mode: 'row', + allowUpdating: true, + }, + dataSource: [{ + field1: 'test1', + field2: 'test2', + field3: 'test3', + field4: 'test4', + field5: 'test5', + field6: 'test6', + field7: 'test7', + field8: 'test8', + }], + customizeColumns: (columns) => { + columns[0].fixed = true; + columns[0].fixedPosition = 'right'; + columns[7].fixed = true; + columns[7].fixedPosition = 'right'; + }, + }); +}); + +test('reorder fixed right column to right when there is a custom command column on the right', async (t) => { + const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + const dataGrid = new DataGrid(DATA_GRID_SELECTOR); + const firstFixedRightHeader = dataGrid.getHeaders().getHeaderRow(0).getHeaderCell(6); + + await t + .click(firstFixedRightHeader.element) + .pressKey('ctrl+right') + .pressKey('ctrl+right') + .pressKey('ctrl+right'); + + await takeScreenshot( + 'reorder_fixed_right_column_to_right_when_there_is_custom_command_column_on_right', + dataGrid.element, + ); + + await t.expect(compareResults.isValid()) + .ok(compareResults.errorMessages()); +}).before(async () => { + await createWidget('dxDataGrid', { + columnWidth: 100, + allowColumnReordering: true, + editing: { + mode: 'row', + allowUpdating: true, + }, + dataSource: [{ + field1: 'test1', + field2: 'test2', + field3: 'test3', + field4: 'test4', + field5: 'test5', + field6: 'test6', + field7: 'test7', + field8: 'test8', + }], + columns: [ + { + dataField: 'field1', + fixed: true, + fixedPosition: 'right', + }, + 'field2', + 'field3', + 'field4', + 'field5', + 'field6', + 'field7', + { + dataField: 'field8', + fixed: true, + fixedPosition: 'right', + }, + { + type: 'buttons', + fixed: true, + fixedPosition: 'right', + }, + ], + customizeColumns: (columns) => { + columns[0].fixed = true; + columns[0].fixedPosition = 'right'; + columns[7].fixed = true; + columns[7].fixedPosition = 'right'; + }, + }); +}); + // Band columns test('reorder band column to right', async (t) => { const { takeScreenshot, compareResults } = createScreenshotsComparer(t); diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_column_to_left_when_there_are_hidden_columns.png b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_column_to_left_when_there_are_hidden_columns.png index 2faee43a0491..0e2e80188659 100644 Binary files a/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_column_to_left_when_there_are_hidden_columns.png and b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_column_to_left_when_there_are_hidden_columns.png differ diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_column_when_allowColumnReordering_is_false_and_group_panel_is_visible.png b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_column_when_allowColumnReordering_is_false_and_group_panel_is_visible.png new file mode 100644 index 000000000000..429bd97a719e Binary files /dev/null and b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_column_when_allowColumnReordering_is_false_and_group_panel_is_visible.png differ diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_fixed_right_column_to_right_when_there_is_command_column_on_right.png b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_fixed_right_column_to_right_when_there_is_command_column_on_right.png new file mode 100644 index 000000000000..a85febe87ca5 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_fixed_right_column_to_right_when_there_is_command_column_on_right.png differ diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_fixed_right_column_to_right_when_there_is_custom_command_column_on_right.png b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_fixed_right_column_to_right_when_there_is_custom_command_column_on_right.png new file mode 100644 index 000000000000..85ccbdae09b1 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_fixed_right_column_to_right_when_there_is_custom_command_column_on_right.png differ diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_to_left_when_rtlEnabled_=_false.png b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_to_left_when_rtlEnabled_=_false.png new file mode 100644 index 000000000000..1a1555980122 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_to_left_when_rtlEnabled_=_false.png differ diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_to_left_when_rtlEnabled_=_true.png b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_to_left_when_rtlEnabled_=_true.png new file mode 100644 index 000000000000..6c04d3181fec Binary files /dev/null and b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_to_left_when_rtlEnabled_=_true.png differ diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_to_right_when_rtlEnabled_=_false.png b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_to_right_when_rtlEnabled_=_false.png new file mode 100644 index 000000000000..535a218ed093 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_to_right_when_rtlEnabled_=_false.png differ diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_to_right_when_rtlEnabled_=_true.png b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_to_right_when_rtlEnabled_=_true.png new file mode 100644 index 000000000000..e7ba19636f90 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_to_right_when_rtlEnabled_=_true.png differ diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_when_group_panel_allowColumnDragging_is_false.png b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_when_group_panel_allowColumnDragging_is_false.png new file mode 100644 index 000000000000..d04a0b4d6ee7 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_when_group_panel_allowColumnDragging_is_false.png differ diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_when_onKeyDown_args_handled_=_true.png b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_when_onKeyDown_args_handled_=_true.png new file mode 100644 index 000000000000..d04a0b4d6ee7 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_when_onKeyDown_args_handled_=_true.png differ diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_with_allowGrouping_is_false.png b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_with_allowGrouping_is_false.png new file mode 100644 index 000000000000..d04a0b4d6ee7 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_with_allowGrouping_is_false.png differ diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/groupColumnReordering.visual.ts b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/groupColumnReordering.visual.ts new file mode 100644 index 000000000000..14daeb2801f5 --- /dev/null +++ b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/groupColumnReordering.visual.ts @@ -0,0 +1,235 @@ +import { createScreenshotsComparer } from 'devextreme-screenshot-comparer'; +import DataGrid from 'devextreme-testcafe-models/dataGrid'; +import url from '../../../../helpers/getPageUrl'; +import { createWidget } from '../../../../helpers/createWidget'; + +fixture + .disablePageReloads`Keyboard Navigation - Group Column Reordering` + .page(url(__dirname, '../../../container.html')); + +const DATA_GRID_SELECTOR = '#container'; + +// Group columns +[true, false].forEach((rtlEnabled) => { + test(`reorder group column when ${rtlEnabled ? 'left' : 'right'} arrow is pressed when rtlEnabled = ${rtlEnabled}`, async (t) => { + const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + const dataGrid = new DataGrid(DATA_GRID_SELECTOR); + const firstGroupHeader = dataGrid.getGroupPanel().getHeader(0); + const shortcut = rtlEnabled ? 'ctrl+left' : 'ctrl+right'; + + await t + .click(firstGroupHeader.element) + .pressKey(shortcut); + + await takeScreenshot( + `reorder_group_column_to_${rtlEnabled ? 'left' : 'right'}_when_rtlEnabled_=_${rtlEnabled}`, + dataGrid.element, + ); + + await t.expect(compareResults.isValid()) + .ok(compareResults.errorMessages()); + }).before(async () => { + await createWidget('dxDataGrid', { + rtlEnabled, + dataSource: [{ + field1: 'test1', + field2: 'test2', + field3: 'test3', + field4: 'test4', + }], + groupPanel: { + visible: true, + }, + columns: [ + { + dataField: 'field1', + groupIndex: 1, + }, + 'field2', + 'field3', + { + dataField: 'field4', + groupIndex: 0, + }, + ], + }); + }); + + test(`reorder group column when ${rtlEnabled ? 'right' : 'left'} arrow is pressed when rtlEnabled = ${rtlEnabled}`, async (t) => { + const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + const dataGrid = new DataGrid(DATA_GRID_SELECTOR); + const lastGroupHeader = dataGrid.getGroupPanel().getHeader(1); + const shortcut = rtlEnabled ? 'ctrl+right' : 'ctrl+left'; + + await t + .click(lastGroupHeader.element) + .pressKey(shortcut); + + await takeScreenshot( + `reorder_group_column_to_${rtlEnabled ? 'right' : 'left'}_when_rtlEnabled_=_${rtlEnabled}`, + dataGrid.element, + ); + + await t.expect(compareResults.isValid()) + .ok(compareResults.errorMessages()); + }).before(async () => { + await createWidget('dxDataGrid', { + rtlEnabled, + dataSource: [{ + field1: 'test1', + field2: 'test2', + field3: 'test3', + field4: 'test4', + }], + groupPanel: { + visible: true, + }, + columns: [ + { + dataField: 'field1', + groupIndex: 1, + }, + 'field2', + 'field3', + { + dataField: 'field4', + groupIndex: 0, + }, + ], + }); + }); +}); + +test('Reordering of grouping column should not work when onKeyDown.args.handled = true', async (t) => { + const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + const dataGrid = new DataGrid(DATA_GRID_SELECTOR); + const firstGroupHeader = dataGrid.getGroupPanel().getHeader(0); + + await t + .click(firstGroupHeader.element) + .pressKey('ctrl+right'); + + await takeScreenshot( + 'reorder_group_column_when_onKeyDown_args_handled_=_true', + dataGrid.element, + ); + + await t.expect(compareResults.isValid()) + .ok(compareResults.errorMessages()); +}).before(async () => { + await createWidget('dxDataGrid', { + onKeyDown: (e) => { + e.handled = true; + }, + dataSource: [{ + field1: 'test1', + field2: 'test2', + field3: 'test3', + field4: 'test4', + }], + groupPanel: { + visible: true, + }, + columns: [ + { + dataField: 'field1', + groupIndex: 1, + }, + 'field2', + 'field3', + { + dataField: 'field4', + groupIndex: 0, + }, + ], + }); +}); + +test('The group column should not be reordered when groupPanel.allowColumnDragging = false', async (t) => { + const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + const dataGrid = new DataGrid(DATA_GRID_SELECTOR); + const firstGroupHeader = dataGrid.getGroupPanel().getHeader(0); + + await t + .click(firstGroupHeader.element) + .pressKey('ctrl+right'); + + await takeScreenshot( + 'reorder_group_column_when_group_panel_allowColumnDragging_is_false', + dataGrid.element, + ); + + await t.expect(compareResults.isValid()) + .ok(compareResults.errorMessages()); +}).before(async () => { + await createWidget('dxDataGrid', { + dataSource: [{ + field1: 'test1', + field2: 'test2', + field3: 'test3', + field4: 'test4', + }], + allowColumnReordering: true, + groupPanel: { + visible: true, + allowColumnDragging: false, + }, + columns: [ + { + dataField: 'field1', + groupIndex: 1, + }, + 'field2', + 'field3', + { + dataField: 'field4', + groupIndex: 0, + }, + ], + }); +}); + +test('The group column should not be reordered when it has allowGrouping set to false', async (t) => { + const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + const dataGrid = new DataGrid(DATA_GRID_SELECTOR); + const firstGroupHeader = dataGrid.getGroupPanel().getHeader(0); + + await t + .click(firstGroupHeader.element) + .pressKey('ctrl+right'); + + await takeScreenshot( + 'reorder_group_column_with_allowGrouping_is_false', + dataGrid.element, + ); + + await t.expect(compareResults.isValid()) + .ok(compareResults.errorMessages()); +}).before(async () => { + await createWidget('dxDataGrid', { + dataSource: [{ + field1: 'test1', + field2: 'test2', + field3: 'test3', + field4: 'test4', + }], + allowColumnReordering: true, + groupPanel: { + visible: true, + allowColumnDragging: true, + }, + columns: [ + { + dataField: 'field1', + groupIndex: 1, + }, + 'field2', + 'field3', + { + dataField: 'field4', + groupIndex: 0, + allowGrouping: false, + }, + ], + }); +}); diff --git a/packages/devextreme/js/__internal/grids/data_grid/grouping/const.ts b/packages/devextreme/js/__internal/grids/data_grid/grouping/const.ts new file mode 100644 index 000000000000..62c10872d571 --- /dev/null +++ b/packages/devextreme/js/__internal/grids/data_grid/grouping/const.ts @@ -0,0 +1,7 @@ +export const CLASSES = { + groupPanel: 'dx-datagrid-group-panel', + groupPanelMessage: 'dx-group-panel-message', + groupPanelItem: 'dx-group-panel-item', + groupPanelLabel: 'dx-toolbar-label', + groupPanelContainer: 'dx-toolbar-item', +}; diff --git a/packages/devextreme/js/__internal/grids/data_grid/grouping/m_grouping.ts b/packages/devextreme/js/__internal/grids/data_grid/grouping/m_grouping.ts index 63a72deff0bb..747e66d1501f 100644 --- a/packages/devextreme/js/__internal/grids/data_grid/grouping/m_grouping.ts +++ b/packages/devextreme/js/__internal/grids/data_grid/grouping/m_grouping.ts @@ -20,14 +20,10 @@ import type { HeaderPanel } from '../../grid_core/header_panel/m_header_panel'; import type { RowsView } from '../../grid_core/views/m_rows_view'; import gridCore from '../m_core'; import dataSourceAdapterProvider from '../m_data_source_adapter'; +import { CLASSES } from './const'; import { GroupingHelper as CollapsedGroupingHelper } from './m_grouping_collapsed'; import { GroupingHelper as ExpandedGroupingHelper } from './m_grouping_expanded'; -const DATAGRID_GROUP_PANEL_CLASS = 'dx-datagrid-group-panel'; -const DATAGRID_GROUP_PANEL_MESSAGE_CLASS = 'dx-group-panel-message'; -const DATAGRID_GROUP_PANEL_ITEM_CLASS = 'dx-group-panel-item'; -const DATAGRID_GROUP_PANEL_LABEL_CLASS = 'dx-toolbar-label'; -const DATAGRID_GROUP_PANEL_CONTAINER_CLASS = 'dx-toolbar-item'; const DATAGRID_EXPAND_CLASS = 'dx-datagrid-expand'; const DATAGRID_GROUP_ROW_CLASS = 'dx-group-row'; const HEADER_FILTER_CLASS_SELECTOR = '.dx-header-filter'; @@ -102,7 +98,7 @@ const dataSourceAdapterExtender = (Base: ModuleType) => class for (let i = 0; i < groups.length; i++) { if (groupIndex === undefined || groupIndex === i) { groups[i].isExpanded = isExpand; - } else if (group && group[i]) { + } else if (group?.[i]) { groups[i].isExpanded = group[i].isExpanded; } } @@ -404,7 +400,7 @@ const isGroupPanelVisible = (groupPanelOptions): boolean => { const allowDragging = (groupPanelOptions, column): boolean => { const isVisible = isGroupPanelVisible(groupPanelOptions); - const canDrag = groupPanelOptions?.allowColumnDragging && column.allowGrouping; + const canDrag = groupPanelOptions?.allowColumnDragging && column?.allowGrouping; return isVisible && !!canDrag; }; @@ -421,7 +417,7 @@ export const GroupingHeaderPanelExtender = (Base: ModuleType) => cl let isRendered = false; const toolbarItem = { template: () => { - const $groupPanel = $('
').addClass(DATAGRID_GROUP_PANEL_CLASS); + const $groupPanel = $('
').addClass(CLASSES.groupPanel); this._updateGroupPanelContent($groupPanel); registerKeyboardAction('groupPanel', this, $groupPanel, undefined, this._handleActionKeyDown.bind(this)); return $groupPanel; @@ -446,7 +442,7 @@ export const GroupingHeaderPanelExtender = (Base: ModuleType) => cl private _handleActionKeyDown(args) { const { event } = args; const $target = $(event.target); - const groupColumnIndex = $target.closest(`.${DATAGRID_GROUP_PANEL_ITEM_CLASS}`).index(); + const groupColumnIndex = $target.closest(`.${CLASSES.groupPanelItem}`).index(); const column = this._columnsController.getGroupColumns()[groupColumnIndex]; const columnIndex = column && column.index; @@ -479,7 +475,7 @@ export const GroupingHeaderPanelExtender = (Base: ModuleType) => cl private _createGroupPanelItem($rootElement, groupColumn) { const $groupPanelItem = $('
') .addClass(groupColumn.cssClass) - .addClass(DATAGRID_GROUP_PANEL_ITEM_CLASS) + .addClass(CLASSES.groupPanelItem) .data('columnData', groupColumn) .appendTo($rootElement) .text(groupColumn.caption); @@ -492,7 +488,7 @@ export const GroupingHeaderPanelExtender = (Base: ModuleType) => cl protected _columnOptionChanged(e?) { if (!this._requireReady && !gridCore.checkChanges(e.optionNames, ['width', 'visibleWidth'])) { const $toolbarElement = this.element(); - const $groupPanel = $toolbarElement && $toolbarElement.find(`.${DATAGRID_GROUP_PANEL_CLASS}`); + const $groupPanel = $toolbarElement?.find(`.${CLASSES.groupPanel}`); if ($groupPanel && $groupPanel.length) { this._updateGroupPanelContent($groupPanel); @@ -511,16 +507,16 @@ export const GroupingHeaderPanelExtender = (Base: ModuleType) => cl if (groupPanelOptions.allowColumnDragging && !groupColumns.length) { $('
') - .addClass(DATAGRID_GROUP_PANEL_MESSAGE_CLASS) + .addClass(CLASSES.groupPanelMessage) .text(groupPanelOptions.emptyPanelText) .appendTo($groupPanel); - $groupPanel.closest(`.${DATAGRID_GROUP_PANEL_CONTAINER_CLASS}`).addClass(DATAGRID_GROUP_PANEL_LABEL_CLASS); - $groupPanel.closest(`.${DATAGRID_GROUP_PANEL_LABEL_CLASS}`).css('maxWidth', 'none'); + $groupPanel.closest(`.${CLASSES.groupPanelContainer}`).addClass(CLASSES.groupPanelLabel); + $groupPanel.closest(`.${CLASSES.groupPanelLabel}`).css('maxWidth', 'none'); } } - protected allowDragging(column?): boolean { + public allowDragging(column): boolean { const groupPanelOptions = this.option('groupPanel'); return allowDragging(groupPanelOptions, column); @@ -528,7 +524,7 @@ export const GroupingHeaderPanelExtender = (Base: ModuleType) => cl public getColumnElements() { const $element = this.element(); - return $element && $element.find(`.${DATAGRID_GROUP_PANEL_ITEM_CLASS}`); + return $element?.find(`.${CLASSES.groupPanelItem}`); } public getColumns() { @@ -539,7 +535,7 @@ export const GroupingHeaderPanelExtender = (Base: ModuleType) => cl const that = this; const $element = that.element(); - if ($element && $element.find(`.${DATAGRID_GROUP_PANEL_CLASS}`).length) { + if ($element?.find(`.${CLASSES.groupPanel}`).length) { const offset = $element.offset(); return { @@ -557,7 +553,7 @@ export const GroupingHeaderPanelExtender = (Base: ModuleType) => cl private getContextMenuItems(options) { const that = this; const contextMenuEnabled = that.option('grouping.contextMenuEnabled'); - const $groupedColumnElement = $(options.targetElement).closest(`.${DATAGRID_GROUP_PANEL_ITEM_CLASS}`); + const $groupedColumnElement = $(options.targetElement).closest(`.${CLASSES.groupPanelItem}`); let items; if ($groupedColumnElement.length) { diff --git a/packages/devextreme/js/__internal/grids/data_grid/keyboard_navigation/m_group_panel_keyboard_navigation.ts b/packages/devextreme/js/__internal/grids/data_grid/keyboard_navigation/m_group_panel_keyboard_navigation.ts new file mode 100644 index 000000000000..22b9bcb7bff2 --- /dev/null +++ b/packages/devextreme/js/__internal/grids/data_grid/keyboard_navigation/m_group_panel_keyboard_navigation.ts @@ -0,0 +1,163 @@ +import { name as clickEventName } from '@js/common/core/events/click'; +import eventsEngine from '@js/common/core/events/core/events_engine'; +import { + isCommandKeyPressed, +} from '@js/common/core/events/utils/index'; +import $ from '@js/core/renderer'; +import { hiddenFocus } from '@js/ui/shared/accessibility'; +import { Direction } from '@ts/grids/grid_core/keyboard_navigation/const'; +import { KeyboardNavigationController as KeyboardNavigationControllerCore } from '@ts/grids/grid_core/keyboard_navigation/m_keyboard_navigation_core'; +import type { Views } from '@ts/grids/grid_core/m_types'; + +import { CLASSES as GROUPING_CLASSES } from '../grouping/const'; +import gridCore from '../m_core'; + +export class GroupPanelKeyboardNavigationController extends KeyboardNavigationControllerCore { + private isNeedToHiddenFocusAfterClick = false; + + private groupItemClickHandlerContext!: (event: any) => void; + + private headerPanel!: Views['headerPanel']; + + private isGroupColumnValidForReordering(groupColumn, direction: Direction): boolean { + const allowDragging = this.headerPanel.allowDragging(groupColumn); + + if (!allowDragging) { + return false; + } + + const groupedColumns = this._columnsController.getGroupColumns(); + + return direction === Direction.Next + ? groupColumn.groupIndex !== groupedColumns.length - 1 + : groupColumn.groupIndex !== 0; + } + + private groupItemClickHandler(e) { + const groupColumn: any = $(e.originalEvent.target).data('columnData'); + + this.isNeedToHiddenFocusAfterClick = this._columnsController?.allowColumnSorting(groupColumn); + } + + private unsubscribeFromGroupItemClick() { + const $focusedView = this.getFocusedViewElement(); + + if ($focusedView) { + eventsEngine.off($focusedView, clickEventName, this.groupItemClickHandlerContext); + } + } + + private subscribeToGroupItemClick() { + const $focusedView = this.getFocusedViewElement(); + + if ($focusedView) { + eventsEngine.on($focusedView, clickEventName, `.${GROUPING_CLASSES.groupPanelItem}`, this.groupItemClickHandlerContext); + } + } + + private leftRightKeysHandler(e): void { + const { originalEvent } = e; + + if (isCommandKeyPressed(originalEvent)) { + const groupColumn: any = $(originalEvent.target).data('columnData'); + const direction = this.getDirectionByKeyName(e.keyName); + + if (this.isGroupColumnValidForReordering(groupColumn, direction)) { + /* + We need to add 2 to the index instead of 1, + because that's how normalization of these indexes works. + + For example, we have columns with the following indexes: + 0 1 2 3 + + We drag 1 to the right. Its index becomes 3. + 0 2 3(1) 3(3) + + After normalization of the indexes: + 0 1(2) 2(1) 3(3) + */ + const newGroupIndex = direction === Direction.Next + ? groupColumn.groupIndex + 2 + : groupColumn.groupIndex - 1; + const newFocusedGroupColumnIndex = direction === Direction.Next + ? groupColumn.groupIndex + 1 + : groupColumn.groupIndex - 1; + + this.isNeedToFocus = true; + this.setFocusedCellPosition(0, newFocusedGroupColumnIndex); + this._columnsController.columnOption( + groupColumn.index, + 'groupIndex', + newGroupIndex, + ); + } + + originalEvent?.preventDefault(); + } + } + + protected _getCell(cellPosition): any { + const $groupColumnElements = this.headerPanel?.getColumnElements(); + + return $groupColumnElements?.eq(cellPosition.columnIndex); + } + + protected getFocusedView() { + return this.getView('headerPanel'); + } + + protected getFocusedViewElement() { + return this.headerPanel?.element()?.find(`.${GROUPING_CLASSES.groupPanel}`); + } + + protected getFocusinSelector(): string { + return `.${GROUPING_CLASSES.groupPanelItem}`; + } + + protected focusinHandler(e: any): void { + this.setFocusedCellPosition(0, $(e.target).index()); + } + + protected keyDownHandler(e): void { + const isHandled = this.processOnKeyDown(e); + + if (isHandled) { + return; + } + + if (e.keyName === 'leftArrow' || e.keyName === 'rightArrow') { + this.leftRightKeysHandler(e); + } + } + + protected renderCompleted(e: any) { + const { isNeedToFocus } = this; + + super.renderCompleted(e); + this.unsubscribeFromGroupItemClick(); + this.subscribeToGroupItemClick(); + + if (!isNeedToFocus && this.isNeedToHiddenFocusAfterClick) { + const $focusElement = this._getFocusedCell(); + + if ($focusElement?.length) { + hiddenFocus($focusElement.get(0)); + } + + this.isNeedToHiddenFocusAfterClick = false; + } + } + + public init(): void { + this.headerPanel = this.getView('headerPanel'); + this.groupItemClickHandlerContext = this.groupItemClickHandlerContext + ?? this.groupItemClickHandler.bind(this); + super.init(); + } +} + +gridCore.registerModule('groupPanelKeyboardNavigation', { + controllers: { + groupPanelKeyboardNavigation: GroupPanelKeyboardNavigationController, + }, +}); diff --git a/packages/devextreme/js/__internal/grids/data_grid/m_widget.ts b/packages/devextreme/js/__internal/grids/data_grid/m_widget.ts index 1a43168a8308..5c751e7e0792 100644 --- a/packages/devextreme/js/__internal/grids/data_grid/m_widget.ts +++ b/packages/devextreme/js/__internal/grids/data_grid/m_widget.ts @@ -23,6 +23,7 @@ import './module_not_extended/pager'; import './module_not_extended/columns_resizing_reordering'; import './module_not_extended/keyboard_navigation'; import './module_not_extended/headers_keyboard_navigation'; +import './keyboard_navigation/m_group_panel_keyboard_navigation'; import './summary/m_summary'; import './module_not_extended/sticky_columns'; import './module_not_extended/column_fixing'; diff --git a/packages/devextreme/js/__internal/grids/data_grid/m_widget_base.ts b/packages/devextreme/js/__internal/grids/data_grid/m_widget_base.ts index a1cf8e911c9b..802ef0d68cf2 100644 --- a/packages/devextreme/js/__internal/grids/data_grid/m_widget_base.ts +++ b/packages/devextreme/js/__internal/grids/data_grid/m_widget_base.ts @@ -51,6 +51,7 @@ gridCore.registerModulesOrder([ 'contextMenu', 'keyboardNavigation', 'headersKeyboardNavigation', + 'groupPanelKeyboardNavigation', 'errorHandling', 'summary', 'columnFixing', diff --git a/packages/devextreme/js/__internal/grids/grid_core/adaptivity/m_adaptivity.ts b/packages/devextreme/js/__internal/grids/grid_core/adaptivity/m_adaptivity.ts index e048cbf5f10e..89726f17c5de 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/adaptivity/m_adaptivity.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/adaptivity/m_adaptivity.ts @@ -1263,11 +1263,6 @@ const columns = ( return super.getVisibleDataColumnsByBandColumn(bandColumnIndex) .filter((column) => column.visibleWidth !== HIDDEN_COLUMNS_WIDTH); } - - public getUnfixedAndStickyColumns(rowIndex: number, ownerBand: number): any[] { - return super.getUnfixedAndStickyColumns(rowIndex, ownerBand) - .filter((col) => col.visibleWidth !== HIDDEN_COLUMNS_WIDTH); - } }; const resizing = (Base: ModuleType) => class AdaptivityResizingControllerExtender extends Base { @@ -1316,8 +1311,8 @@ const headersKeyboardNavigation = (Base: ModuleType col.visibleWidth !== HIDDEN_COLUMNS_WIDTH); + } }; export const adaptivityModule: Module = { diff --git a/packages/devextreme/js/__internal/grids/grid_core/column_headers/m_column_headers.ts b/packages/devextreme/js/__internal/grids/grid_core/column_headers/m_column_headers.ts index 2af9ab1d909d..8d9d27d9e679 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/column_headers/m_column_headers.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/column_headers/m_column_headers.ts @@ -520,13 +520,16 @@ export class ColumnHeadersView extends ColumnsView { /** * @extended: column_chooser */ + public isReorderingEnabled(column): boolean { + return column.allowReordering + && (this.option('allowColumnReordering') ?? this._columnsController.isColumnOptionUsed('allowReordering')); + } + public allowDragging(column) { const rowIndex = column && this._columnsController.getRowIndex(column.index); const columns = this.getColumns(rowIndex); - const isReorderingEnabled = this.option('allowColumnReordering') ?? this._columnsController.isColumnOptionUsed('allowReordering'); - - return isReorderingEnabled && column.allowReordering && columns.length > 1; + return this.isReorderingEnabled(column) && columns.length > 1; } protected getBoundingRect() { diff --git a/packages/devextreme/js/__internal/grids/grid_core/columns_controller/m_columns_controller.ts b/packages/devextreme/js/__internal/grids/grid_core/columns_controller/m_columns_controller.ts index d4eb074de4f6..e5d6dadca02a 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/columns_controller/m_columns_controller.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/columns_controller/m_columns_controller.ts @@ -509,15 +509,6 @@ export class ColumnsController extends modules.Controller { return visibleColumns.filter((column) => column.fixed); } - public getUnfixedAndStickyColumns(rowIndex: number, ownerBand: number): any[] { - const visibleColumns = this.getVisibleColumns(rowIndex, true); - - return visibleColumns - .filter((column) => column.ownerBand === ownerBand - && (!isDefined(column.type) || this.isCustomCommandColumn(column)) - && (!column.fixed || column.fixedPosition === StickyPosition.Sticky)); - } - private _getFixedColumnsCore() { const that = this; const result: any = []; @@ -957,13 +948,19 @@ export class ColumnsController extends modules.Controller { } } + public allowColumnSorting(column) { + const sortingOptions = this.option('sorting'); + const allowSorting = sortingOptions?.mode === 'single' || sortingOptions?.mode === 'multiple'; + + return allowSorting && column?.allowSorting; + } + public changeSortOrder(columnIndex, sortOrder) { const that = this; const options: any = {}; const sortingOptions = that.option('sorting'); - const sortingMode = sortingOptions && sortingOptions.mode; + const sortingMode = sortingOptions?.mode; const needResetSorting = sortingMode === 'single' || !sortOrder; - const allowSorting = sortingMode === 'single' || sortingMode === 'multiple'; const column = that._columns[columnIndex]; const nextSortOrder = function (column) { if (sortOrder === 'ctrl') { @@ -982,7 +979,7 @@ export class ColumnsController extends modules.Controller { return true; }; - if (allowSorting && column && column.allowSorting) { + if (this.allowColumnSorting(column)) { if (needResetSorting && !isDefined(column.groupIndex)) { each(that._columns, function (index) { if (index !== columnIndex && this.sortOrder) { diff --git a/packages/devextreme/js/__internal/grids/grid_core/header_panel/m_header_panel.ts b/packages/devextreme/js/__internal/grids/grid_core/header_panel/m_header_panel.ts index c4682b9c663d..917f934bed07 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/header_panel/m_header_panel.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/header_panel/m_header_panel.ts @@ -242,7 +242,9 @@ export class HeaderPanel extends ColumnsView { /** * @extended: DataGrid's grouping */ - protected allowDragging() { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public allowDragging(column): boolean { + return false; } public hasGroupedColumns(): any {} diff --git a/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/const.ts b/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/const.ts index f4c3cf0901c6..712c75b81c6a 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/const.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/const.ts @@ -52,3 +52,8 @@ export const FOCUS_TYPE_CELL = 'cell'; export const COLUMN_HEADERS_VIEW = 'columnHeadersView'; export const ROWS_VIEW = 'rowsView'; export const FUNCTIONAL_KEYS = ['shift', 'control', 'alt']; + +export enum Direction { + Next = 'next', + Previous = 'previous', +} diff --git a/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_headers_keyboard_navigation.ts b/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_headers_keyboard_navigation.ts index 67cb25f298d6..63e77415dd51 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_headers_keyboard_navigation.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_headers_keyboard_navigation.ts @@ -1,5 +1,3 @@ -import eventsEngine from '@js/common/core/events/core/events_engine'; -import { keyboard } from '@js/common/core/events/short'; import { isCommandKeyPressed, } from '@js/common/core/events/utils/index'; @@ -9,98 +7,23 @@ import { isDefined } from '@js/core/utils/type'; import type { Views } from '../m_types'; import { StickyPosition } from '../sticky_columns/const'; -import { getColumnFixedPosition, isFirstFixedColumn, isLastFixedColumn } from '../sticky_columns/utils'; +import { getColumnFixedPosition } from '../sticky_columns/utils'; +import { Direction } from './const'; import { KeyboardNavigationController as KeyboardNavigationControllerCore } from './m_keyboard_navigation_core'; -enum Direction { - Next = 'next', - Previous = 'previous', -} - export class HeadersKeyboardNavigationController extends KeyboardNavigationControllerCore { - private renderCompletedWithContext!: (e: any) => void; - - private keyDownListener: any; - - private isNeedToFocusHeader = false; - - private focusinHandlerContext!: (event: any) => void; - protected _columnHeadersView!: Views['columnHeadersView']; - private initHandlers(): void { - this.unsubscribeFromKeyDownEvent(); - - this._columnHeadersView?.renderCompleted?.remove(this.renderCompletedWithContext); - - if (this.isKeyboardEnabled()) { - this._columnHeadersView?.renderCompleted?.add(this.renderCompletedWithContext); - } - } - - private unsubscribeFromKeyDownEvent(): void { - if (this.keyDownListener) { - keyboard.off(this.keyDownListener); - } - } - - private subscribeToKeyDownEvent(): void { - const $columnHeadersView = this._columnHeadersView.element(); - - this.keyDownListener = keyboard.on($columnHeadersView, null, (e) => this.keyDownHandler(e)); - } - - private initKeyDownHandler(): void { - this.unsubscribeFromKeyDownEvent(); - this.subscribeToKeyDownEvent(); - } - - private getDirectionByKeyName(keyName): Direction { - const rtlEnabled = this.option('rtlEnabled'); - - switch (keyName) { - case 'leftArrow': { - return rtlEnabled ? Direction.Next : Direction.Previous; - } - case 'rightArrow': { - return rtlEnabled ? Direction.Previous : Direction.Next; - break; - } - default: { - return Direction.Next; - } - } - } - private isHeaderValidForReordering(column, direction, rowIndex): boolean { - const columnsController = this._columnsController; - const allowReordering = this._columnHeadersView.allowDragging(column); + const allowReordering = this._columnHeadersView.isReorderingEnabled(column); if (!allowReordering) { return false; } - if (column.fixed && column.fixedPosition !== StickyPosition.Sticky) { - const fixedPosition = getColumnFixedPosition(columnsController, column); - - return direction === Direction.Next ? !isLastFixedColumn( - columnsController, - column, - rowIndex, - isDefined(column.ownerBand), - fixedPosition, - ) : !isFirstFixedColumn( - columnsController, - column, - rowIndex, - isDefined(column.ownerBand), - fixedPosition, - ); - } - - const unfixedColumns = columnsController.getUnfixedAndStickyColumns(rowIndex, column.ownerBand); - const isFirstColumn = column.index === unfixedColumns[0].index; - const isLastColumn = column.index === unfixedColumns[unfixedColumns.length - 1].index; + const draggableColumns = this.getDraggableColumns(column, rowIndex); + const isFirstColumn = column.index === draggableColumns[0].index; + const isLastColumn = column.index === draggableColumns[draggableColumns.length - 1].index; return direction === Direction.Next ? !isLastColumn : !isFirstColumn; } @@ -117,9 +40,11 @@ export class HeadersKeyboardNavigationController extends KeyboardNavigationContr if (this.isHeaderValidForReordering(column, direction, rowIndex)) { const visibleIndex = this._columnsController.getVisibleIndex(column.index, rowIndex); const newVisibleIndex = this.getNewVisibleIndex(visibleIndex, direction); - const newFocusedColumnIndex = direction === 'next' ? newVisibleIndex - 1 : newVisibleIndex; + const newFocusedColumnIndex = direction === Direction.Next + ? newVisibleIndex - 1 + : newVisibleIndex; - this.isNeedToFocusHeader = true; + this.isNeedToFocus = true; this.setFocusedCellPosition(rowIndex, newFocusedColumnIndex); this._columnsController.moveColumn( { columnIndex: visibleIndex, rowIndex }, @@ -132,7 +57,29 @@ export class HeadersKeyboardNavigationController extends KeyboardNavigationContr } } - private keyDownHandler(e): void { + protected getDraggableColumns( + column, + rowIndex: number, + ): any[] { + const columnsController = this._columnsController; + const visibleColumns = columnsController.getVisibleColumns(rowIndex, true) + ?.filter((col) => col.ownerBand === column?.ownerBand + && (!isDefined(col.type) || columnsController.isCustomCommandColumn(col))); + + if (column?.fixed) { + const fixedPosition = getColumnFixedPosition(columnsController, column); + + if (fixedPosition !== StickyPosition.Sticky) { + return visibleColumns + .filter((col) => col.fixed + && getColumnFixedPosition(columnsController, col) === fixedPosition); + } + } + + return visibleColumns.filter((column) => !column.fixed || column.fixedPosition === StickyPosition.Sticky); + } + + protected keyDownHandler(e): void { const isHandled = this.processOnKeyDown(e); if (isHandled) { @@ -152,23 +99,20 @@ export class HeadersKeyboardNavigationController extends KeyboardNavigationContr } } - private focusinHandler(e): void { - this._updateFocusedCellPosition($(e.target)); - } - - private unsubscribeFromFocusinEvent(): void { - const $columnHeadersView = this._columnHeadersView?.element(); - - eventsEngine.off($columnHeadersView, 'focusin', this.focusinHandlerContext); - } + protected getNewVisibleIndex(visibleIndex, direction) { + /* + We need to add 2 to the index instead of 1, + because that's how normalization of these indexes works. - private subscribeToFocusinEvent(): void { - const $columnHeadersView = this._columnHeadersView?.element(); + For example, we have columns with the following indexes: + 0 1 2 3 - eventsEngine.on($columnHeadersView, 'focusin', '.dx-header-row > td', this.focusinHandlerContext); - } + We drag 1 to the right. Its index becomes 3. + 0 2 3(1) 3(3) - protected getNewVisibleIndex(visibleIndex, direction) { + After normalization of the indexes: + 0 1(2) 2(1) 3(3) + */ return direction === 'previous' ? visibleIndex - 1 : visibleIndex + 2; } @@ -183,34 +127,21 @@ export class HeadersKeyboardNavigationController extends KeyboardNavigationContr return this._columnHeadersView?.getCell(cellPosition); } - protected renderCompleted(): void { - this.initKeyDownHandler(); - - this.unsubscribeFromFocusinEvent(); - this.subscribeToFocusinEvent(); + protected getFocusedView(): any { + return this.getView('columnHeadersView'); + } - if (this.isNeedToFocusHeader) { - const $focusElement = this._getFocusedCell(); + protected focusinHandler(e): void { + this._updateFocusedCellPosition($(e.target)); + } - this.isNeedToFocusHeader = false; - // @ts-expect-error - eventsEngine.trigger($focusElement, 'focus'); - } + protected getFocusinSelector(): string { + return '.dx-header-row > td'; } public init(): void { super.init(); this._columnHeadersView = this.getView('columnHeadersView'); - - this.renderCompletedWithContext = this.renderCompletedWithContext - ?? this.renderCompleted.bind(this); - this.focusinHandlerContext = this.focusinHandlerContext ?? this.focusinHandler.bind(this); - - this.initHandlers(); - } - - public dispose(): void { - keyboard.off(this.keyDownListener); } } diff --git a/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_keyboard_navigation.ts b/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_keyboard_navigation.ts index 9954e01f8c84..a5d7f5e09df0 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_keyboard_navigation.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_keyboard_navigation.ts @@ -2,7 +2,6 @@ import { name as clickEventName } from '@js/common/core/events/click'; import eventsEngine from '@js/common/core/events/core/events_engine'; import pointerEvents from '@js/common/core/events/pointer'; -import { keyboard } from '@js/common/core/events/short'; import { addNamespace, createEvent, @@ -100,11 +99,7 @@ export class KeyboardNavigationController extends KeyboardNavigationControllerCo private focusedHandlerWithContext!: ($element: dxElementWrapper) => void; - private rowsViewRenderCompletedWithContext!: (e: any) => void; - - private rowsViewFocusHandlerContext!: (event: any) => void; - - private rowsViewFocusOutHandlerContext!: (event: Event) => void; + private focusOutHandlerContext!: (event: Event) => void; public _isNeedScroll: any; @@ -118,8 +113,6 @@ export class KeyboardNavigationController extends KeyboardNavigationControllerCo private _pointerEventAction: any; - private _rowsViewKeyDownListener: any; - private focusType: any; private _testInteractiveElement: any; @@ -144,8 +137,6 @@ export class KeyboardNavigationController extends KeyboardNavigationControllerCo // #region Initialization public init() { - super.init(); - this._dataController = this.getController('data'); this._selectionController = this.getController('selection'); this._editingController = this.getController('editing'); @@ -156,14 +147,14 @@ export class KeyboardNavigationController extends KeyboardNavigationControllerCo this._columnResizerController = this.getController('columnsResizer'); this._rowsView = this.getView('rowsView'); + super.init(); + this._memoFireFocusedCellChanged = memoize(this._memoFireFocusedCellChanged.bind(this), { compareType: 'value' }); this._memoFireFocusedRowChanged = memoize(this._memoFireFocusedRowChanged.bind(this), { compareType: 'value' }); this.focusedHandlerWithContext = this.focusedHandlerWithContext || this.focusedHandler.bind(this); - this.rowsViewRenderCompletedWithContext = this.rowsViewRenderCompletedWithContext || this.rowsViewRenderCompleted.bind(this); - this.rowsViewFocusHandlerContext = this.rowsViewFocusHandlerContext || this.rowsViewFocusHandler.bind(this); - this.rowsViewFocusOutHandlerContext = this.rowsViewFocusOutHandlerContext - ?? this.rowsViewFocusOutHandler.bind(this); + this.focusOutHandlerContext = this.focusOutHandlerContext + ?? this.focusOutHandler.bind(this); this._updateFocusTimeout = null; this._fastEditingStarted = false; @@ -177,14 +168,12 @@ export class KeyboardNavigationController extends KeyboardNavigationControllerCo this._editorFactory?.focused.remove(this.focusedHandlerWithContext); } - this.initRowsViewHandlers(); this.initDocumentHandlers(); } public dispose() { super.dispose(); this._resetFocusedView(); - keyboard.off(this._rowsViewKeyDownListener); eventsEngine.off( domAdapter.getDocument(), addNamespace(pointerEvents.down, 'dxDataGridKeyboardNavigation'), @@ -209,7 +198,7 @@ export class KeyboardNavigationController extends KeyboardNavigationControllerCo } } - protected rowsViewFocusHandler(event: any): void { + protected focusinHandler(event: any): void { const $element = $(event.target); const isRelatedTargetInRowsView = $(event.relatedTarget).closest( this._rowsView.element(), @@ -242,25 +231,25 @@ export class KeyboardNavigationController extends KeyboardNavigationControllerCo } } - protected rowsViewFocusOutHandler(): void { + protected focusOutHandler(): void { this._toggleInertAttr(false); } protected subscribeToRowsViewFocusEvent(): void { const $rowsView = this._rowsView?.element(); - eventsEngine.on($rowsView, 'focusin', this.rowsViewFocusHandlerContext); - eventsEngine.on($rowsView, 'focusout', this.rowsViewFocusOutHandlerContext); + eventsEngine.on($rowsView, 'focusin', this.focusinHandlerContext); + eventsEngine.on($rowsView, 'focusout', this.focusOutHandlerContext); } protected unsubscribeFromRowsViewFocusEvent(): void { const $rowsView = this._rowsView?.element(); - eventsEngine.off($rowsView, 'focusin', this.rowsViewFocusHandlerContext); - eventsEngine.off($rowsView, 'focusout', this.rowsViewFocusOutHandlerContext); + eventsEngine.off($rowsView, 'focusin', this.focusinHandlerContext); + eventsEngine.off($rowsView, 'focusout', this.focusOutHandlerContext); } - protected rowsViewRenderCompleted(e: any): void { + protected renderCompleted(e: any): void { const $rowsView = this._rowsView.element(); const isFullUpdate = !e || e.changeType === 'refresh'; const isFocusedViewCorrect = this._focusedView && this._focusedView.name === this._rowsView.name; @@ -275,7 +264,7 @@ export class KeyboardNavigationController extends KeyboardNavigationControllerCo this.subscribeToRowsViewFocusEvent(); this.initPointerEventHandler(); - this.initRowsViewKeyDownHandler(); + this.initKeyDownHandler(); this._setRowsViewAttributes(); if (isFocusedViewCorrect && isFocusedElementCorrect) { @@ -303,16 +292,10 @@ export class KeyboardNavigationController extends KeyboardNavigationControllerCo return true; } - private initRowsViewHandlers(): void { + protected initHandlers(): void { this.unsubscribeFromRowsViewFocusEvent(); this.unsubscribeFromPointerEvent(); - this.unsubscribeFromRowsViewKeyDownEvent(); - - this._rowsView?.renderCompleted?.remove(this.rowsViewRenderCompletedWithContext); - - if (this.isKeyboardEnabled()) { - this._rowsView.renderCompleted.add(this.rowsViewRenderCompletedWithContext); - } + super.initHandlers(); } private initDocumentHandlers(): void { @@ -403,21 +386,6 @@ export class KeyboardNavigationController extends KeyboardNavigationControllerCo this.subscribeToPointerEvent(); } - private unsubscribeFromRowsViewKeyDownEvent(): void { - keyboard.off(this._rowsViewKeyDownListener); - } - - private subscribeToRowsViewKeyDownEvent(): void { - const $rowsView = this._getRowsViewElement(); - - this._rowsViewKeyDownListener = keyboard.on($rowsView, null, (e) => this._rowsViewKeyDownHandler(e)); - } - - private initRowsViewKeyDownHandler(): void { - this._rowsViewKeyDownListener && this.unsubscribeFromRowsViewKeyDownEvent(); - this.subscribeToRowsViewKeyDownEvent(); - } - // #endregion Initialization // #region Options @@ -442,7 +410,7 @@ export class KeyboardNavigationController extends KeyboardNavigationControllerCo // #region Key_Handlers - private _rowsViewKeyDownHandler(e) { + protected keyDownHandler(e) { let needStopPropagation = true; this._isNeedFocus = true; this._isNeedScroll = true; @@ -1344,8 +1312,8 @@ export class KeyboardNavigationController extends KeyboardNavigationControllerCo element && this._focusElement($(element), isHighlighted); } - private getFocusedView() { - return this._focusedView; + protected getFocusedView(): any { + return this.getView('rowsView'); } public setupFocusedView() { @@ -1392,9 +1360,9 @@ export class KeyboardNavigationController extends KeyboardNavigationControllerCo } private _getFocusedViewByElement($element) { - const view = this.getFocusedView(); - const $view = view && $(view.element()); - return $element && $element.closest($view).length !== 0; + const $view = $(this._focusedView?.element()); + + return $element?.closest($view).length !== 0; } private _focusView() { diff --git a/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_keyboard_navigation_core.ts b/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_keyboard_navigation_core.ts index 8c745615f776..4266cd8aad3a 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_keyboard_navigation_core.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_keyboard_navigation_core.ts @@ -1,10 +1,21 @@ +import eventsEngine from '@js/common/core/events/core/events_engine'; +import { keyboard } from '@js/common/core/events/short'; import $ from '@js/core/renderer'; import modules from '../m_modules'; import type { Controllers, OptionChanged } from '../m_types'; +import { Direction } from './const'; import { isElementDefined, isFixedColumnIndexOffsetRequired } from './m_keyboard_navigation_utils'; export class KeyboardNavigationController extends modules.ViewController { + private keyDownListener: any; + + protected isNeedToFocus = false; + + protected renderCompletedWithContext!: (e: any) => void; + + protected focusinHandlerContext!: (event: any) => void; + protected _columnsController!: Controllers['columns']; public _focusedCellPosition: any; @@ -34,6 +45,87 @@ export class KeyboardNavigationController extends modules.ViewController { return columnIndex; } + private unsubscribeFromKeyDownEvent(): void { + if (this.keyDownListener) { + keyboard.off(this.keyDownListener); + } + } + + private subscribeToKeyDownEvent(): void { + const $focusedViewElement = this.getFocusedViewElement(); + + if ($focusedViewElement) { + this.keyDownListener = keyboard.on($focusedViewElement, null, (e) => this.keyDownHandler(e)); + } + } + + protected getDirectionByKeyName(keyName: string): Direction { + const rtlEnabled = this.option('rtlEnabled'); + + switch (keyName) { + case 'leftArrow': { + return rtlEnabled ? Direction.Next : Direction.Previous; + } + case 'rightArrow': { + return rtlEnabled ? Direction.Previous : Direction.Next; + break; + } + default: { + return Direction.Next; + } + } + } + + protected getFocusedViewElement() { + return this.getFocusedView()?.element(); + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + protected keyDownHandler(e): void {} + + protected initKeyDownHandler(): void { + this.unsubscribeFromKeyDownEvent(); + this.subscribeToKeyDownEvent(); + } + + private unsubscribeFromFocusinEvent(): void { + const $focusedView = this.getFocusedViewElement(); + + if ($focusedView) { + eventsEngine.off($focusedView, 'focusin', this.focusinHandlerContext); + } + } + + private subscribeToFocusinEvent(): void { + const $focusedView = this.getFocusedViewElement(); + const focusinSelector = this.getFocusinSelector(); + + if ($focusedView) { + eventsEngine.on($focusedView, 'focusin', focusinSelector, this.focusinHandlerContext); + } + } + + protected getFocusinSelector(): string { + return ''; + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + protected focusinHandler(e): void {} + + protected initHandlers(): void { + const focusedView = this.getFocusedView(); + this.unsubscribeFromKeyDownEvent(); + + focusedView?.renderCompleted?.remove(this.renderCompletedWithContext); + + if (this.isKeyboardEnabled()) { + focusedView?.renderCompleted?.add(this.renderCompletedWithContext); + } + } + + // eslint-disable-next-line class-methods-use-this + protected getFocusedView(): any {} + // eslint-disable-next-line @typescript-eslint/no-unused-vars protected _getCell(cellPosition): any {} @@ -133,6 +225,22 @@ export class KeyboardNavigationController extends modules.ViewController { return position; } + // eslint-disable-next-line @typescript-eslint/no-unused-vars + protected renderCompleted(e: any): void { + this.initKeyDownHandler(); + + this.unsubscribeFromFocusinEvent(); + this.subscribeToFocusinEvent(); + + if (this.isNeedToFocus) { + const $focusElement = this._getFocusedCell(); + + this.isNeedToFocus = false; + // @ts-expect-error + eventsEngine.trigger($focusElement, 'focus'); + } + } + public init() { this._columnsController = this.getController('columns'); this._focusedCellPosition = {}; @@ -140,6 +248,16 @@ export class KeyboardNavigationController extends modules.ViewController { if (this.isKeyboardEnabled()) { this.createAction('onKeyDown'); } + + this.renderCompletedWithContext = this.renderCompletedWithContext + ?? this.renderCompleted.bind(this); + this.focusinHandlerContext = this.focusinHandlerContext ?? this.focusinHandler.bind(this); + + this.initHandlers(); + } + + public dispose(): void { + keyboard.off(this.keyDownListener); } /** diff --git a/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/scrollable_a11y.ts b/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/scrollable_a11y.ts index 90bbf1391992..96cecb82cff9 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/scrollable_a11y.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/scrollable_a11y.ts @@ -20,16 +20,16 @@ import type { KeyboardNavigationController } from './m_keyboard_navigation'; export const keyboardNavigationScrollableA11yExtender = (Base: ModuleType): ModuleType => class ScrollableA11yExtender extends Base { private _$firstNotFixedCell: dxElementWrapper | undefined; - protected rowsViewFocusHandler(event: any): void { + protected focusinHandler(event: any): void { const $target = $(event.target); this.translateFocusIfNeed(event, $target); - super.rowsViewFocusHandler(event); + super.focusinHandler(event); } - protected rowsViewFocusOutHandler(): void { - super.rowsViewFocusOutHandler(); + protected focusOutHandler(): void { + super.focusOutHandler(); this.makeScrollableFocusableIfNeed(); } @@ -54,11 +54,11 @@ export const keyboardNavigationScrollableA11yExtender = (Base: ModuleType { this.clock.tick(10); const navigationController = dataGrid.getController('keyboardNavigation'); - navigationController._rowsViewKeyDownHandler({ key: 'Tab', keyName: 'tab', originalEvent: $.Event('keydown', { target: $(dataGrid.getCellElement(0, 0)) }) }); + navigationController.keyDownHandler({ key: 'Tab', keyName: 'tab', originalEvent: $.Event('keydown', { target: $(dataGrid.getCellElement(0, 0)) }) }); this.clock.tick(10); // assert @@ -3962,7 +3962,7 @@ QUnit.module('Editing', baseModuleConfig, () => { const emulateEnterKeyPress = () => { const event = $.Event('keydown', { target: $('#qunit-fixture').find(':focus').get(0) }); - navigationController._rowsViewKeyDownHandler({ key: 'Enter', keyName: 'enter', originalEvent: event }); + navigationController.keyDownHandler({ key: 'Enter', keyName: 'enter', originalEvent: event }); }; // act @@ -5295,7 +5295,7 @@ QUnit.module('API methods', baseModuleConfig, () => { // act const event = $.Event('keydown', { target: $('#qunit-fixture').find(':focus').get(0) }); - navigationController._rowsViewKeyDownHandler({ key: 'Enter', keyName: 'enter', originalEvent: event }); + navigationController.keyDownHandler({ key: 'Enter', keyName: 'enter', originalEvent: event }); this.clock.tick(10); // assert @@ -5624,7 +5624,7 @@ QUnit.module('API methods', baseModuleConfig, () => { width: 400 }); const triggerTabPress = function($target) { - dataGrid.getController('keyboardNavigation')._rowsViewKeyDownHandler({ + dataGrid.getController('keyboardNavigation').keyDownHandler({ key: 'Tab', keyName: 'tab', originalEvent: { diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/focus.integration.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/focus.integration.tests.js index eae2d8691466..e218782bedf1 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/focus.integration.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/focus.integration.tests.js @@ -657,7 +657,7 @@ QUnit.module('Initialization', baseModuleConfig, () => { $(dataGrid.getRowElement(0)).find('.dx-command-edit > .dx-link-edit').trigger(pointerEvents.up).click(); this.clock.tick(10); - navigationController._rowsViewKeyDownHandler({ key: 'Tab', keyName: 'tab', originalEvent: $.Event('keydown', { target: $(dataGrid.getCellElement(0, 0)) }) }); + navigationController.keyDownHandler({ key: 'Tab', keyName: 'tab', originalEvent: $.Event('keydown', { target: $(dataGrid.getCellElement(0, 0)) }) }); $(dataGrid.getCellElement(0, 1)).trigger(pointerEvents.up); this.clock.tick(10); @@ -1038,7 +1038,7 @@ QUnit.module('Initialization', baseModuleConfig, () => { // act dataGrid.focus(dataGrid.getCellElement(1, 2)); const keyboardController = dataGrid.getController('keyboardNavigation'); - keyboardController._rowsViewKeyDownHandler({ key: 'Tab', keyName: 'tab', originalEvent: $.Event('keydown', { target: $(':focus').get(0) }) }); + keyboardController.keyDownHandler({ key: 'Tab', keyName: 'tab', originalEvent: $.Event('keydown', { target: $(':focus').get(0) }) }); this.clock.tick(10); const $cell = $(dataGrid.element()).find('.dx-focused'); @@ -2144,7 +2144,7 @@ QUnit.module('View\'s focus', { // act const navigationController = this.dataGrid.getController('keyboardNavigation'); - navigationController._rowsViewKeyDownHandler({ key: 'Tab', keyName: 'tab', originalEvent: $.Event('keydown', { target: $(this.dataGrid.getCellElement(0, 0)) }) }); + navigationController.keyDownHandler({ key: 'Tab', keyName: 'tab', originalEvent: $.Event('keydown', { target: $(this.dataGrid.getCellElement(0, 0)) }) }); this.clock.tick(10); // assert @@ -4451,7 +4451,7 @@ QUnit.module('API methods', baseModuleConfig, () => { this.clock.tick(10); $(dataGrid.$element()).find('.dx-textbox').dxTextBox('instance').option('value', 'Test'); - navigationController._rowsViewKeyDownHandler({ key: 'Tab', keyName: 'tab', originalEvent: $.Event('keydown', { target: $(dataGrid.$element()).find('input').get(0) }) }); + navigationController.keyDownHandler({ key: 'Tab', keyName: 'tab', originalEvent: $.Event('keydown', { target: $(dataGrid.$element()).find('input').get(0) }) }); this.clock.tick(10); // assert @@ -4498,7 +4498,7 @@ QUnit.module('API methods', baseModuleConfig, () => { this.clock.tick(10); $(dataGrid.$element()).find('.dx-textbox').dxTextBox('instance').option('value', 'Test'); - navigationController._rowsViewKeyDownHandler({ key: 'Tab', keyName: 'tab', originalEvent: $.Event('keydown', { target: $(dataGrid.$element()).find('input').get(0) }) }); + navigationController.keyDownHandler({ key: 'Tab', keyName: 'tab', originalEvent: $.Event('keydown', { target: $(dataGrid.$element()).find('input').get(0) }) }); this.clock.tick(10); // assert @@ -4563,7 +4563,7 @@ QUnit.module('API methods', baseModuleConfig, () => { }); const keyboardNavigationController = dataGrid.getController('keyboardNavigation'); const triggerTabPress = function($target, isShiftPressed) { - keyboardNavigationController._rowsViewKeyDownHandler({ + keyboardNavigationController.keyDownHandler({ key: 'Tab', keyName: 'tab', shift: !!isShiftPressed, @@ -4636,7 +4636,7 @@ QUnit.module('API methods', baseModuleConfig, () => { }); const keyboardNavigationController = dataGrid.getController('keyboardNavigation'); const triggerTabPress = function($target, isShiftPressed) { - keyboardNavigationController._rowsViewKeyDownHandler({ + keyboardNavigationController.keyDownHandler({ key: 'Tab', keyName: 'tab', shift: !!isShiftPressed, @@ -4723,7 +4723,7 @@ QUnit.module('API methods', baseModuleConfig, () => { }, 'lastName'] }); const triggerTabPress = function(target) { - const keyboardListenerId = dataGrid.getController('keyboardNavigation')._rowsViewKeyDownListener; + const keyboardListenerId = dataGrid.getController('keyboardNavigation').keyDownListener; keyboard._getProcessor(keyboardListenerId).process({ key: 'Tab', diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/keyboardNavigation.keyboardController.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/keyboardNavigation.keyboardController.tests.js index 08a244fae21a..cc9955e0f323 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/keyboardNavigation.keyboardController.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/keyboardNavigation.keyboardController.tests.js @@ -497,7 +497,7 @@ QUnit.module('Keyboard controller', { }; // act - navigationController._rowsViewKeyDownHandler({ + navigationController.keyDownHandler({ keyName: 'leftArrow', originalEvent: { preventDefault: commonUtils.noop, @@ -528,7 +528,7 @@ QUnit.module('Keyboard controller', { }; // act - navigationController._rowsViewKeyDownHandler({ + navigationController.keyDownHandler({ keyName: 'leftArrow', originalEvent: { preventDefault: commonUtils.noop, @@ -563,7 +563,7 @@ QUnit.module('Keyboard controller', { navigationController._isLegacyNavigation = () => true; // act - navigationController._rowsViewKeyDownHandler({ + navigationController.keyDownHandler({ keyName: 'downArrow', originalEvent: { preventDefault: commonUtils.noop, @@ -598,7 +598,7 @@ QUnit.module('Keyboard controller', { navigationController._isLegacyNavigation = () => true; // act - navigationController._rowsViewKeyDownHandler({ + navigationController.keyDownHandler({ keyName: 'upArrow', originalEvent: { preventDefault: commonUtils.noop, @@ -750,7 +750,7 @@ QUnit.module('Keyboard controller', { assert.ok(onSpy.calledWith(document, 'visibilitychange'), 'subscribed to the "visibilitychange" event'); assert.ok(onSpy.calledWith(element, 'focusin'), 'subscribed to the "focusin" event'); assert.ok(onSpy.calledWith(element, CLICK_EVENT), 'subscribed to the "pointerdown" event'); - assert.ok(keyboard._getProcessor(navigationController._rowsViewKeyDownListener), 'subscribed to the "keydown" event'); + assert.ok(keyboard._getProcessor(navigationController.keyDownListener), 'subscribed to the "keydown" event'); // arrange onSpy.resetHistory(); @@ -767,7 +767,7 @@ QUnit.module('Keyboard controller', { assert.ok(offSpy.calledWith(document, 'visibilitychange'), 'unsubscribed from the "visibilitychange" event'); assert.ok(offSpy.calledWith(element, 'focusin'), 'unsubscribed from the "focusin" event'); assert.ok(offSpy.calledWith(element, CLICK_EVENT), 'unsubscribed from the "pointerdown" event'); - assert.notOk(keyboard._getProcessor(navigationController._rowsViewKeyDownListener), 'unsubscribed from the "keydown" event'); + assert.notOk(keyboard._getProcessor(navigationController.keyDownListener), 'unsubscribed from the "keydown" event'); }); // T1178858 @@ -797,7 +797,7 @@ QUnit.module('Keyboard controller', { assert.notOk(onSpy.calledWith(document, 'visibilitychange'), 'not subscribed to the "visibilitychange" event'); assert.notOk(onSpy.calledWith(element, 'focusin'), 'not subscribed to the "focusin" event'); assert.notOk(onSpy.calledWith(element, CLICK_EVENT), 'not subscribed to the "pointerdown" event'); - assert.notOk(keyboard._getProcessor(navigationController._rowsViewKeyDownListener), 'not subscribed to the "keydown" event'); + assert.notOk(keyboard._getProcessor(navigationController.keyDownListener), 'not subscribed to the "keydown" event'); // arrange onSpy.resetHistory(); @@ -813,7 +813,7 @@ QUnit.module('Keyboard controller', { assert.ok(onSpy.calledWith(document, 'visibilitychange'), 'subscribed to the "visibilitychange" event'); assert.ok(onSpy.calledWith(element, 'focusin'), 'subscribed to the "focusin" event'); assert.ok(onSpy.calledWith(element, CLICK_EVENT), 'subscribed to the "pointerdown" event'); - assert.ok(keyboard._getProcessor(navigationController._rowsViewKeyDownListener), 'subscribed to the "keydown" event'); + assert.ok(keyboard._getProcessor(navigationController.keyDownListener), 'subscribed to the "keydown" event'); }); QUnit.testInActiveWindow('Column headers view: Unsubscribe from events when changing the keyboardNavigation.enabled option to false', function(assert) { diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/keyboardNavigation.keyboardKeys.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/keyboardNavigation.keyboardKeys.tests.js index e5d405eace5e..2235fd0a73f6 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/keyboardNavigation.keyboardKeys.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/keyboardNavigation.keyboardKeys.tests.js @@ -1523,7 +1523,7 @@ QUnit.module('Keyboard keys', { isLeftArrow = true; }; - this.keyboardNavigationController._rowsViewKeyDownHandler({ + this.keyboardNavigationController.keyDownHandler({ keyName: 'leftArrow', originalEvent: { isDefaultPrevented: commonUtils.noop, @@ -1561,7 +1561,7 @@ QUnit.module('Keyboard keys', { this.keyboardNavigationController._leftRightKeysHandler = function() { isLeftArrow = true; }; - this.keyboardNavigationController._rowsViewKeyDownHandler({ + this.keyboardNavigationController.keyDownHandler({ keyName: 'leftArrow', originalEvent: { isDefaultPrevented: commonUtils.noop, diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.treeList/treeList.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.treeList/treeList.tests.js index aedd188026d1..1cd9592600d3 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.treeList/treeList.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.treeList/treeList.tests.js @@ -283,14 +283,14 @@ QUnit.module('Initialization', defaultModuleConfig, () => { this.clock.tick(10); // act - navigationController._rowsViewKeyDownHandler({ keyName: 'rightArrow', key: 'ArrowRight', ctrl: true, originalEvent: $.Event('keydown', { target: treeList.getCellElement(1, 0), ctrlKey: true }) }); + navigationController.keyDownHandler({ keyName: 'rightArrow', key: 'ArrowRight', ctrl: true, originalEvent: $.Event('keydown', { target: treeList.getCellElement(1, 0), ctrlKey: true }) }); this.clock.tick(10); // assert assert.ok(treeList.isRowExpanded(2), 'second row is expanded'); // act - navigationController._rowsViewKeyDownHandler({ keyName: 'leftArrow', key: 'ArrowLeft', ctrl: true, originalEvent: $.Event('keydown', { target: treeList.getCellElement(1, 0), ctrlKey: true }) }); + navigationController.keyDownHandler({ keyName: 'leftArrow', key: 'ArrowLeft', ctrl: true, originalEvent: $.Event('keydown', { target: treeList.getCellElement(1, 0), ctrlKey: true }) }); this.clock.tick(10); // assert