From a7c00d5156aaa6b17a107e262153c2051e7d6c85 Mon Sep 17 00:00:00 2001 From: Alyar <> Date: Wed, 16 Apr 2025 03:47:01 +0400 Subject: [PATCH 01/13] Extract event subscriptions to the core part --- .../m_headers_keyboard_navigation.ts | 86 ++--------------- .../m_keyboard_navigation.ts | 74 ++++---------- .../m_keyboard_navigation_core.ts | 96 +++++++++++++++++++ .../keyboard_navigation/scrollable_a11y.ts | 12 +-- .../helpers/grid/keyboardNavigationHelper.js | 2 +- .../editing.integration.tests.js | 8 +- .../focus.integration.tests.js | 16 ++-- .../focus.tests.js | 1 + ...oardNavigation.keyboardController.tests.js | 17 ++-- .../keyboardNavigation.keyboardKeys.tests.js | 4 +- .../treeList.tests.js | 4 +- 11 files changed, 160 insertions(+), 160 deletions(-) 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..a46d3753f269 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'; @@ -18,43 +16,8 @@ enum Direction { } 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'); @@ -119,7 +82,7 @@ export class HeadersKeyboardNavigationController extends KeyboardNavigationContr const newVisibleIndex = this.getNewVisibleIndex(visibleIndex, direction); const newFocusedColumnIndex = direction === 'next' ? newVisibleIndex - 1 : newVisibleIndex; - this.isNeedToFocusHeader = true; + this.isNeedToFocus = true; this.setFocusedCellPosition(rowIndex, newFocusedColumnIndex); this._columnsController.moveColumn( { columnIndex: visibleIndex, rowIndex }, @@ -132,7 +95,7 @@ export class HeadersKeyboardNavigationController extends KeyboardNavigationContr } } - private keyDownHandler(e): void { + protected keyDownHandler(e): void { const isHandled = this.processOnKeyDown(e); if (isHandled) { @@ -152,22 +115,6 @@ 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); - } - - private subscribeToFocusinEvent(): void { - const $columnHeadersView = this._columnHeadersView?.element(); - - eventsEngine.on($columnHeadersView, 'focusin', '.dx-header-row > td', this.focusinHandlerContext); - } - protected getNewVisibleIndex(visibleIndex, direction) { return direction === 'previous' ? visibleIndex - 1 : visibleIndex + 2; } @@ -183,34 +130,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..b34386e51b9b 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,3 +1,5 @@ +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'; @@ -5,6 +7,14 @@ import type { Controllers, OptionChanged } from '../m_types'; 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 +44,66 @@ export class KeyboardNavigationController extends modules.ViewController { return columnIndex; } + private unsubscribeFromKeyDownEvent(): void { + if (this.keyDownListener) { + keyboard.off(this.keyDownListener); + } + } + + private subscribeToKeyDownEvent(): void { + const $focusedView = this.getFocusedView()?.element(); + + if ($focusedView) { + this.keyDownListener = keyboard.on($focusedView, null, (e) => this.keyDownHandler(e)); + } + } + + // 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.getFocusedView()?.element(); + + if ($focusedView) { + eventsEngine.off($focusedView, 'focusin', this.focusinHandlerContext); + } + } + + private subscribeToFocusinEvent(): void { + const $focusedView = this.getFocusedView()?.element(); + 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 +203,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 +226,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/focus.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/focus.tests.js index c98a8834c3f4..7f17a7c1165b 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/focus.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/focus.tests.js @@ -2866,6 +2866,7 @@ QUnit.module('Focused row', getModuleConfig(true), () => { mode: 'batch' }, onFocusedCellChanged: function(e) { + debugger; ++focusedCellChangedCount; assert.ok(e.row.isNewRow, 'Inserted row'); assert.equal(e.row.rowType, 'data', 'Row type'); 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..f77cf78d3b65 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 @@ -36,6 +36,7 @@ QUnit.module('Keyboard controller', { element.fake && element.on(name) || on.apply(this, Array.prototype.slice.call(arguments, 0)); }; eventsEngine.off = function(element, name) { + debugger; element.fake && element.off(name) || off.apply(this, Array.prototype.slice.call(arguments, 0)); }; const that = this; @@ -497,7 +498,7 @@ QUnit.module('Keyboard controller', { }; // act - navigationController._rowsViewKeyDownHandler({ + navigationController.keyDownHandler({ keyName: 'leftArrow', originalEvent: { preventDefault: commonUtils.noop, @@ -528,7 +529,7 @@ QUnit.module('Keyboard controller', { }; // act - navigationController._rowsViewKeyDownHandler({ + navigationController.keyDownHandler({ keyName: 'leftArrow', originalEvent: { preventDefault: commonUtils.noop, @@ -563,7 +564,7 @@ QUnit.module('Keyboard controller', { navigationController._isLegacyNavigation = () => true; // act - navigationController._rowsViewKeyDownHandler({ + navigationController.keyDownHandler({ keyName: 'downArrow', originalEvent: { preventDefault: commonUtils.noop, @@ -598,7 +599,7 @@ QUnit.module('Keyboard controller', { navigationController._isLegacyNavigation = () => true; // act - navigationController._rowsViewKeyDownHandler({ + navigationController.keyDownHandler({ keyName: 'upArrow', originalEvent: { preventDefault: commonUtils.noop, @@ -750,7 +751,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 +768,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 +798,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 +814,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 From 71d00740cfd7dee43737f23174efc45a88fa0eb4 Mon Sep 17 00:00:00 2001 From: Alyar <> Date: Wed, 16 Apr 2025 14:51:23 +0400 Subject: [PATCH 02/13] Implement reordering of group columns using keyboard --- .../groupColumnReordering.visual.ts | 101 ++++++++++++++++++ .../grids/data_grid/grouping/const.ts | 7 ++ .../grids/data_grid/grouping/m_grouping.ts | 28 +++-- .../m_group_panel_keyboard_navigation.ts | 95 ++++++++++++++++ .../js/__internal/grids/data_grid/m_widget.ts | 1 + .../grids/data_grid/m_widget_base.ts | 1 + .../grid_core/keyboard_navigation/const.ts | 5 + .../m_headers_keyboard_navigation.ts | 27 +---- .../m_keyboard_navigation_core.ts | 32 +++++- 9 files changed, 253 insertions(+), 44 deletions(-) create mode 100644 e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/groupColumnReordering.visual.ts create mode 100644 packages/devextreme/js/__internal/grids/data_grid/grouping/const.ts create mode 100644 packages/devextreme/js/__internal/grids/data_grid/keyboard_navigation/m_group_panel_keyboard_navigation.ts 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..2b46a223e125 --- /dev/null +++ b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/groupColumnReordering.visual.ts @@ -0,0 +1,101 @@ +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, + }, + ], + }); + }); +}); 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..df3b6ca6f940 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; } } @@ -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,12 +507,12 @@ 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'); } } @@ -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..77c44240e172 --- /dev/null +++ b/packages/devextreme/js/__internal/grids/data_grid/keyboard_navigation/m_group_panel_keyboard_navigation.ts @@ -0,0 +1,95 @@ +import { + isCommandKeyPressed, +} from '@js/common/core/events/utils/index'; +import $ from '@js/core/renderer'; +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 { + protected headerPanel!: Views['headerPanel']; + + private isGroupColumnValidForReordering(groupColumn, direction: Direction): boolean { + const groupedColumns = this._columnsController.getGroupColumns(); + + return direction === Direction.Next + ? groupColumn.index !== groupedColumns[groupedColumns.length - 1].index + : groupColumn.index !== groupedColumns[0].index; + } + + 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)) { + 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 keyDownHandler(e): void { + const isHandled = this.processOnKeyDown(e); + + if (isHandled) { + return; + } + + // eslint-disable-next-line default-case + switch (e.keyName) { + case 'leftArrow': + case 'rightArrow': + this.leftRightKeysHandler(e); + break; + } + } + + public init(): void { + this.headerPanel = this.getView('headerPanel'); + 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/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 a46d3753f269..7ae1be5c1c78 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 @@ -8,33 +8,12 @@ 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 { Direction } from './const'; import { KeyboardNavigationController as KeyboardNavigationControllerCore } from './m_keyboard_navigation_core'; -enum Direction { - Next = 'next', - Previous = 'previous', -} - export class HeadersKeyboardNavigationController extends KeyboardNavigationControllerCore { protected _columnHeadersView!: Views['columnHeadersView']; - 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); @@ -80,7 +59,9 @@ 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.isNeedToFocus = true; this.setFocusedCellPosition(rowIndex, newFocusedColumnIndex); 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 b34386e51b9b..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 @@ -4,6 +4,7 @@ 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 { @@ -51,13 +52,34 @@ export class KeyboardNavigationController extends modules.ViewController { } private subscribeToKeyDownEvent(): void { - const $focusedView = this.getFocusedView()?.element(); + const $focusedViewElement = this.getFocusedViewElement(); - if ($focusedView) { - this.keyDownListener = keyboard.on($focusedView, null, (e) => this.keyDownHandler(e)); + 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 {} @@ -67,7 +89,7 @@ export class KeyboardNavigationController extends modules.ViewController { } private unsubscribeFromFocusinEvent(): void { - const $focusedView = this.getFocusedView()?.element(); + const $focusedView = this.getFocusedViewElement(); if ($focusedView) { eventsEngine.off($focusedView, 'focusin', this.focusinHandlerContext); @@ -75,7 +97,7 @@ export class KeyboardNavigationController extends modules.ViewController { } private subscribeToFocusinEvent(): void { - const $focusedView = this.getFocusedView()?.element(); + const $focusedView = this.getFocusedViewElement(); const focusinSelector = this.getFocusinSelector(); if ($focusedView) { From 7a6ac08738086736cb173ade8bc2c83695054aa2 Mon Sep 17 00:00:00 2001 From: Alyar <> Date: Thu, 17 Apr 2025 01:00:53 +0400 Subject: [PATCH 03/13] Fix focus reset when clicking on grouping column --- .../groupColumnReordering.visual.ts | 45 ++++++++++++++ .../m_group_panel_keyboard_navigation.ts | 59 ++++++++++++++++++- .../m_columns_controller.ts | 12 +++- 3 files changed, 112 insertions(+), 4 deletions(-) diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/groupColumnReordering.visual.ts b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/groupColumnReordering.visual.ts index 2b46a223e125..7421adaba195 100644 --- a/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/groupColumnReordering.visual.ts +++ b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/groupColumnReordering.visual.ts @@ -99,3 +99,48 @@ const DATA_GRID_SELECTOR = '#container'; }); }); }); + +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, + }, + ], + }); +}); 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 index 77c44240e172..aa511f75057e 100644 --- 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 @@ -1,7 +1,10 @@ +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'; @@ -10,16 +13,46 @@ import { CLASSES as GROUPING_CLASSES } from '../grouping/const'; import gridCore from '../m_core'; export class GroupPanelKeyboardNavigationController extends KeyboardNavigationControllerCore { - protected headerPanel!: Views['headerPanel']; + private isNeedToHiddenFocus = false; + + private groupItemClickHandlerContext!: (event: any) => void; + + private headerPanel!: Views['headerPanel']; private isGroupColumnValidForReordering(groupColumn, direction: Direction): boolean { const groupedColumns = this._columnsController.getGroupColumns(); + if (!groupColumn) { + return false; + } + return direction === Direction.Next ? groupColumn.index !== groupedColumns[groupedColumns.length - 1].index : groupColumn.index !== groupedColumns[0].index; } + private groupItemClickHandler(e) { + const groupColumn: any = $(e.originalEvent.target).data('columnData'); + + this.isNeedToHiddenFocus = 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; @@ -66,6 +99,10 @@ export class GroupPanelKeyboardNavigationController extends KeyboardNavigationCo return `.${GROUPING_CLASSES.groupPanelItem}`; } + protected focusinHandler(e: any): void { + this.setFocusedCellPosition(0, $(e.target).index()); + } + protected keyDownHandler(e): void { const isHandled = this.processOnKeyDown(e); @@ -82,8 +119,28 @@ export class GroupPanelKeyboardNavigationController extends KeyboardNavigationCo } } + protected renderCompleted(e: any) { + const { isNeedToFocus } = this; + + super.renderCompleted(e); + this.unsubscribeFromGroupItemClick(); + this.subscribeToGroupItemClick(); + + if (!isNeedToFocus && this.isNeedToHiddenFocus) { + const $focusElement = this._getFocusedCell(); + + if ($focusElement?.length) { + hiddenFocus($focusElement.get(0)); + } + + this.isNeedToHiddenFocus = false; + } + } + public init(): void { this.headerPanel = this.getView('headerPanel'); + this.groupItemClickHandlerContext = this.groupItemClickHandlerContext + ?? this.groupItemClickHandler.bind(this); super.init(); } } 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..4b82de04dced 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 @@ -957,13 +957,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 +988,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) { From 64615afb17e857c29f60235b4b0d2ab4ca21ac1e Mon Sep 17 00:00:00 2001 From: Alyar <> Date: Thu, 17 Apr 2025 19:21:58 +0400 Subject: [PATCH 04/13] Add etalons --- ...up_column_to_left_when_rtlEnabled_=_false.png | Bin 0 -> 9546 bytes ...oup_column_to_left_when_rtlEnabled_=_true.png | Bin 0 -> 9491 bytes ...p_column_to_right_when_rtlEnabled_=_false.png | Bin 0 -> 9549 bytes ...up_column_to_right_when_rtlEnabled_=_true.png | Bin 0 -> 9492 bytes ...column_when_onKeyDown_args_handled_=_true.png | Bin 0 -> 9540 bytes 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_to_left_when_rtlEnabled_=_false.png create mode 100644 e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_to_left_when_rtlEnabled_=_true.png create mode 100644 e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_to_right_when_rtlEnabled_=_false.png create mode 100644 e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_to_right_when_rtlEnabled_=_true.png create mode 100644 e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_when_onKeyDown_args_handled_=_true.png 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 0000000000000000000000000000000000000000..1a1555980122a85b2d021d6963481916eb2983b1 GIT binary patch literal 9546 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..6c04d3181fec4459c191b58984ca495fbe8318ed GIT binary patch literal 9491 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..535a218ed093ceddde8df52483902b89e76b53e0 GIT binary patch literal 9549 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 NO<8jfefN=z{{r5@2`&Ht literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..d04a0b4d6ee71e16a504a306c3443ec5013029e0 GIT binary patch literal 9540 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 B0tNs8 literal 0 HcmV?d00001 From b8971e3d4fc2d05b2b890cb946521db46bdcec7c Mon Sep 17 00:00:00 2001 From: Alyar <> Date: Tue, 22 Apr 2025 21:32:06 +0400 Subject: [PATCH 05/13] Fix issue with fixed columns reordering when there is a command column on the right --- .../columnReordering.visual.ts | 112 ++++++++++++++++++ .../grid_core/adaptivity/m_adaptivity.ts | 17 +-- .../m_columns_controller.ts | 9 -- .../m_headers_keyboard_navigation.ts | 49 ++++---- 4 files changed, 148 insertions(+), 39 deletions(-) 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..c14a5cabd535 100644 --- a/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/columnReordering.visual.ts +++ b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/columnReordering.visual.ts @@ -386,6 +386,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/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/columns_controller/m_columns_controller.ts b/packages/devextreme/js/__internal/grids/grid_core/columns_controller/m_columns_controller.ts index 4b82de04dced..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 = []; 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 7ae1be5c1c78..4edb10123fd8 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 @@ -7,7 +7,7 @@ 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'; @@ -15,34 +15,15 @@ export class HeadersKeyboardNavigationController extends KeyboardNavigationContr protected _columnHeadersView!: Views['columnHeadersView']; private isHeaderValidForReordering(column, direction, rowIndex): boolean { - const columnsController = this._columnsController; const allowReordering = this._columnHeadersView.allowDragging(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; } @@ -76,6 +57,28 @@ export class HeadersKeyboardNavigationController extends KeyboardNavigationContr } } + 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); From 3edd6ccae2612d70674050e16a7a0129be9009a3 Mon Sep 17 00:00:00 2001 From: Alyar <> Date: Tue, 22 Apr 2025 22:08:02 +0400 Subject: [PATCH 06/13] Update the storybook example --- .../examples/datagrid/DataGrid.stories.tsx | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) 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, + }, } } From a5bc7b6f8eb2e123ccf7f6719a5865f2ce6ba636 Mon Sep 17 00:00:00 2001 From: Alyar <> Date: Tue, 22 Apr 2025 23:46:17 +0400 Subject: [PATCH 07/13] Add etalons --- ...ht_when_there_is_command_column_on_right.png | Bin 0 -> 12623 bytes ..._there_is_custom_command_column_on_right.png | Bin 0 -> 12620 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_fixed_right_column_to_right_when_there_is_command_column_on_right.png create mode 100644 e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_fixed_right_column_to_right_when_there_is_custom_command_column_on_right.png 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 0000000000000000000000000000000000000000..a85febe87ca566eca34524b807530c283841d1f9 GIT binary patch literal 12623 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�sm3Sf!@CYicf`S6lurXRV(Z<5Ac&`)^6(PQ&bu6om z$gK!)f>CxCuf?aY-@26pbPvf($DyAJ7l^9ewfI@s0R{74a)fWE<=Cg1O^OT>m+wIG zv6-t@+Y+1ewp&0$)cG@4Q!H=j)SxL#G39cs0?j(5f?!dufQoWjIFA+gM7#u^N;b9( z8+M-BN3mP$_13~0|7hCxQEs25W}hOiO`82Zo9F*& g>i-M(XsNJLj9hj=d&F<@(n`mkO6lGBKjY(wuK)l5 literal 0 HcmV?d00001 From e44b00c14fd83524ec03e74285d68d11b0c89473 Mon Sep 17 00:00:00 2001 From: Alyar <> Date: Wed, 23 Apr 2025 11:41:49 +0400 Subject: [PATCH 08/13] Update etalon --- ..._to_left_when_there_are_hidden_columns.png | Bin 8159 -> 8157 bytes 1 file changed, 0 insertions(+), 0 deletions(-) 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 2faee43a04912c742e9f44081c766d063f2f65c0..0e2e80188659b184ef2ea0eb35a6938a87486815 100644 GIT binary patch literal 8157 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 literal 8159 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 From 33605ccea2fc8d80e93bbec20540b6d50c689272 Mon Sep 17 00:00:00 2001 From: Alyar <> Date: Wed, 23 Apr 2025 14:42:42 +0400 Subject: [PATCH 09/13] Remove the debugger from tests --- .../testing/tests/DevExpress.ui.widgets.dataGrid/focus.tests.js | 1 - .../keyboardNavigation.keyboardController.tests.js | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/focus.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/focus.tests.js index 7f17a7c1165b..c98a8834c3f4 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/focus.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/focus.tests.js @@ -2866,7 +2866,6 @@ QUnit.module('Focused row', getModuleConfig(true), () => { mode: 'batch' }, onFocusedCellChanged: function(e) { - debugger; ++focusedCellChangedCount; assert.ok(e.row.isNewRow, 'Inserted row'); assert.equal(e.row.rowType, 'data', 'Row type'); 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 f77cf78d3b65..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 @@ -36,7 +36,6 @@ QUnit.module('Keyboard controller', { element.fake && element.on(name) || on.apply(this, Array.prototype.slice.call(arguments, 0)); }; eventsEngine.off = function(element, name) { - debugger; element.fake && element.off(name) || off.apply(this, Array.prototype.slice.call(arguments, 0)); }; const that = this; From 8c33a9dd6d260583262e177207e36c3455043559 Mon Sep 17 00:00:00 2001 From: Alyar <> Date: Wed, 23 Apr 2025 22:27:49 +0400 Subject: [PATCH 10/13] Fix the column reordering when allowColumnReordering is false and group panel is visible --- .../columnReordering.visual.ts | 32 +++++++++++++++++++ .../column_headers/m_column_headers.ts | 9 ++++-- .../m_headers_keyboard_navigation.ts | 2 +- 3 files changed, 39 insertions(+), 4 deletions(-) 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 c14a5cabd535..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); 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/keyboard_navigation/m_headers_keyboard_navigation.ts b/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_headers_keyboard_navigation.ts index 4edb10123fd8..f5a2c816ff07 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 @@ -15,7 +15,7 @@ export class HeadersKeyboardNavigationController extends KeyboardNavigationContr protected _columnHeadersView!: Views['columnHeadersView']; private isHeaderValidForReordering(column, direction, rowIndex): boolean { - const allowReordering = this._columnHeadersView.allowDragging(column); + const allowReordering = this._columnHeadersView.isReorderingEnabled(column); if (!allowReordering) { return false; From 9f7c3a7b2b81e9f9a46d08631e5f4f69134ddf98 Mon Sep 17 00:00:00 2001 From: Alyar <> Date: Wed, 23 Apr 2025 23:14:34 +0400 Subject: [PATCH 11/13] Make group column reordering via keyboard dependent on groupPanel.allowColumnDragging and allowGrouping options --- .../groupColumnReordering.visual.ts | 89 +++++++++++++++++++ .../grids/data_grid/grouping/m_grouping.ts | 4 +- .../m_group_panel_keyboard_navigation.ts | 6 +- .../grid_core/header_panel/m_header_panel.ts | 4 +- 4 files changed, 98 insertions(+), 5 deletions(-) diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/groupColumnReordering.visual.ts b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/groupColumnReordering.visual.ts index 7421adaba195..14daeb2801f5 100644 --- a/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/groupColumnReordering.visual.ts +++ b/e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/groupColumnReordering.visual.ts @@ -144,3 +144,92 @@ test('Reordering of grouping column should not work when onKeyDown.args.handled ], }); }); + +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/m_grouping.ts b/packages/devextreme/js/__internal/grids/data_grid/grouping/m_grouping.ts index df3b6ca6f940..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 @@ -400,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; }; @@ -516,7 +516,7 @@ export const GroupingHeaderPanelExtender = (Base: ModuleType) => cl } } - protected allowDragging(column?): boolean { + public allowDragging(column): boolean { const groupPanelOptions = this.option('groupPanel'); return allowDragging(groupPanelOptions, column); 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 index aa511f75057e..7bee7a1cbd16 100644 --- 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 @@ -20,12 +20,14 @@ export class GroupPanelKeyboardNavigationController extends KeyboardNavigationCo private headerPanel!: Views['headerPanel']; private isGroupColumnValidForReordering(groupColumn, direction: Direction): boolean { - const groupedColumns = this._columnsController.getGroupColumns(); + const allowDragging = this.headerPanel.allowDragging(groupColumn); - if (!groupColumn) { + if (!allowDragging) { return false; } + const groupedColumns = this._columnsController.getGroupColumns(); + return direction === Direction.Next ? groupColumn.index !== groupedColumns[groupedColumns.length - 1].index : groupColumn.index !== groupedColumns[0].index; 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 {} From 13cbea78e1dffbe2172c01ee793609fc82322ac8 Mon Sep 17 00:00:00 2001 From: Alyar <> Date: Wed, 23 Apr 2025 23:40:23 +0400 Subject: [PATCH 12/13] code refactoring --- .../m_group_panel_keyboard_navigation.ts | 33 ++++++++++++------- .../m_headers_keyboard_navigation.ts | 13 ++++++++ 2 files changed, 34 insertions(+), 12 deletions(-) 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 index 7bee7a1cbd16..22b9bcb7bff2 100644 --- 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 @@ -13,7 +13,7 @@ import { CLASSES as GROUPING_CLASSES } from '../grouping/const'; import gridCore from '../m_core'; export class GroupPanelKeyboardNavigationController extends KeyboardNavigationControllerCore { - private isNeedToHiddenFocus = false; + private isNeedToHiddenFocusAfterClick = false; private groupItemClickHandlerContext!: (event: any) => void; @@ -29,14 +29,14 @@ export class GroupPanelKeyboardNavigationController extends KeyboardNavigationCo const groupedColumns = this._columnsController.getGroupColumns(); return direction === Direction.Next - ? groupColumn.index !== groupedColumns[groupedColumns.length - 1].index - : groupColumn.index !== groupedColumns[0].index; + ? groupColumn.groupIndex !== groupedColumns.length - 1 + : groupColumn.groupIndex !== 0; } private groupItemClickHandler(e) { const groupColumn: any = $(e.originalEvent.target).data('columnData'); - this.isNeedToHiddenFocus = this._columnsController?.allowColumnSorting(groupColumn); + this.isNeedToHiddenFocusAfterClick = this._columnsController?.allowColumnSorting(groupColumn); } private unsubscribeFromGroupItemClick() { @@ -63,6 +63,19 @@ export class GroupPanelKeyboardNavigationController extends KeyboardNavigationCo 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; @@ -112,12 +125,8 @@ export class GroupPanelKeyboardNavigationController extends KeyboardNavigationCo return; } - // eslint-disable-next-line default-case - switch (e.keyName) { - case 'leftArrow': - case 'rightArrow': - this.leftRightKeysHandler(e); - break; + if (e.keyName === 'leftArrow' || e.keyName === 'rightArrow') { + this.leftRightKeysHandler(e); } } @@ -128,14 +137,14 @@ export class GroupPanelKeyboardNavigationController extends KeyboardNavigationCo this.unsubscribeFromGroupItemClick(); this.subscribeToGroupItemClick(); - if (!isNeedToFocus && this.isNeedToHiddenFocus) { + if (!isNeedToFocus && this.isNeedToHiddenFocusAfterClick) { const $focusElement = this._getFocusedCell(); if ($focusElement?.length) { hiddenFocus($focusElement.get(0)); } - this.isNeedToHiddenFocus = false; + this.isNeedToHiddenFocusAfterClick = false; } } 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 f5a2c816ff07..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 @@ -100,6 +100,19 @@ export class HeadersKeyboardNavigationController extends KeyboardNavigationContr } protected getNewVisibleIndex(visibleIndex, 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) + */ return direction === 'previous' ? visibleIndex - 1 : visibleIndex + 2; } From 5e1a2503d8ab37fe5ce6d4fa2642a31adcb4388c Mon Sep 17 00:00:00 2001 From: Alyar <> Date: Thu, 24 Apr 2025 00:27:19 +0400 Subject: [PATCH 13/13] Add etalons --- ...ring_is_false_and_group_panel_is_visible.png | Bin 0 -> 12557 bytes ...group_panel_allowColumnDragging_is_false.png | Bin 0 -> 9540 bytes ...group_column_with_allowGrouping_is_false.png | Bin 0 -> 9540 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_column_when_allowColumnReordering_is_false_and_group_panel_is_visible.png create mode 100644 e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_when_group_panel_allowColumnDragging_is_false.png create mode 100644 e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/etalons/reorder_group_column_with_allowGrouping_is_false.png 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 0000000000000000000000000000000000000000..429bd97a719e6312c81104129dc81f193ca00552 GIT binary patch literal 12557 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 B0tNs8 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..d04a0b4d6ee71e16a504a306c3443ec5013029e0 GIT binary patch literal 9540 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 B0tNs8 literal 0 HcmV?d00001