From 35aff7b1687dd4fb56a96aa88bc3e584740bc133 Mon Sep 17 00:00:00 2001 From: Roman Semenov Date: Tue, 5 Sep 2023 10:46:32 +0400 Subject: [PATCH] DataGrid - fix focusing for groupFooter & footer (#25505) --- .../grids/data_grid/summary/m_summary.ts | 9 +- .../m_keyboard_navigation.ts | 3 +- .../m_keyboard_navigation_types.ts | 266 ------------------ .../scss/widgets/base/dataGrid/_index.scss | 12 + .../etalons/group-summary-focused.png | Bin 0 -> 5052 bytes .../etalons/total-summary-focused.png | Bin 0 -> 5070 bytes .../testcafe/tests/dataGrid/summary.ts | 112 ++++++++ 7 files changed, 134 insertions(+), 268 deletions(-) delete mode 100644 packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_keyboard_navigation_types.ts create mode 100644 packages/devextreme/testing/testcafe/tests/dataGrid/etalons/group-summary-focused.png create mode 100644 packages/devextreme/testing/testcafe/tests/dataGrid/etalons/total-summary-focused.png create mode 100644 packages/devextreme/testing/testcafe/tests/dataGrid/summary.ts diff --git a/packages/devextreme/js/__internal/grids/data_grid/summary/m_summary.ts b/packages/devextreme/js/__internal/grids/data_grid/summary/m_summary.ts index e0c2aeffbce0..59968149dd02 100644 --- a/packages/devextreme/js/__internal/grids/data_grid/summary/m_summary.ts +++ b/packages/devextreme/js/__internal/grids/data_grid/summary/m_summary.ts @@ -26,6 +26,7 @@ const DATAGRID_GROUP_FOOTER_CLASS = 'dx-datagrid-group-footer'; const DATAGRID_GROUP_TEXT_CONTENT_CLASS = 'dx-datagrid-group-text-content'; const DATAGRID_NOWRAP_CLASS = 'dx-datagrid-nowrap'; const DATAGRID_FOOTER_ROW_CLASS = 'dx-footer-row'; +const DATAGRID_CELL_DISABLED = 'dx-cell-focus-disabled'; const DATAGRID_GROUP_FOOTER_ROW_TYPE = 'groupFooter'; const DATAGRID_TOTAL_FOOTER_ROW_TYPE = 'totalFooter'; @@ -39,17 +40,21 @@ export const renderSummaryCell = function (cell, options) { if (!column.command && summaryItems) { for (let i = 0; i < summaryItems.length; i++) { const summaryItem = summaryItems[i]; + const text = gridCore.getSummaryText(summaryItem, options.summaryTexts); + $summaryItems.push($('
') .css('textAlign', summaryItem.alignment || column.alignment) .addClass(DATAGRID_SUMMARY_ITEM_CLASS) .addClass(DATAGRID_TEXT_CONTENT_CLASS) .addClass(summaryItem.cssClass) .toggleClass(DATAGRID_GROUP_TEXT_CONTENT_CLASS, options.rowType === 'group') - .text(gridCore.getSummaryText(summaryItem, options.summaryTexts))); + .text(text) + .attr('aria-label', `${column.caption} ${text}`)); } $cell.append($summaryItems); } }; + const getSummaryCellOptions = function (that, options) { const summaryTexts = that.option('summary.texts') || {}; @@ -148,6 +153,8 @@ export const FooterView = ColumnsView.inherit((function () { if (row.rowType === DATAGRID_TOTAL_FOOTER_ROW_TYPE) { $row.addClass(DATAGRID_FOOTER_ROW_CLASS); + $row.addClass(DATAGRID_CELL_DISABLED); + $row.attr('tabindex', 0); } return $row; 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 fc7e1c607cf0..efe24e0baee8 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 @@ -1802,7 +1802,8 @@ export class KeyboardNavigationController extends modules.ViewController { return false; } - if (row && row.rowType === 'group' && cellPosition.columnIndex > 0) { + const isFullRowFocus = row?.rowType === 'group' || row?.rowType === 'groupFooter'; + if (isFullRowFocus && cellPosition.columnIndex > 0) { return true; } diff --git a/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_keyboard_navigation_types.ts b/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_keyboard_navigation_types.ts deleted file mode 100644 index 86b0a810e981..000000000000 --- a/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_keyboard_navigation_types.ts +++ /dev/null @@ -1,266 +0,0 @@ -import { Controllers, ViewController, Views } from '../m_types'; - -interface State { - _updateFocusTimeout: any; - _fastEditingStarted: any; - _focusedCellPosition: any; - _canceledCellPosition: any; - _isNeedScroll: any; - _focusedView: any; - _isNeedFocus: any; - _isHiddenFocus: any; - _documentClickHandler: any; - _pointerEventAction: any; - _keyDownListener: any; - focusType: any; - _testInteractiveElement: any; - - _dataController: Controllers['data']; - _selectionController: Controllers['selection']; - _editingController: Controllers['editing']; - _headerPanel: Views['headerPanel']; - _rowsView: Views['rowsView']; - _columnsController: Controllers['columns']; - _editorFactory: Controllers['editorFactory']; - _adaptiveController: Controllers['adaptiveColumns']; -} - -export interface KeyboardNavigationController extends ViewController, State { - _initViewHandlers: (this: this, ...args: any[]) => any; - - _initDocumentHandlers: (this: this, ...args: any[]) => any; - - _setRowsViewAttributes: (this: this, ...args: any[]) => any; - - _initPointerEventHandler: (this: this, ...args: any[]) => any; - - _initKeyDownHandler: (this: this, ...args: any[]) => any; - - isRowFocusType: (this: this, ...args: any[]) => any; - - isCellFocusType: (this: this, ...args: any[]) => any; - - setRowFocusType: (this: this, ...args: any[]) => any; - - setCellFocusType: (this: this, ...args: any[]) => any; - - _keyDownHandler: (this: this, ...args: any[]) => any; - - _processOnKeyDown: (this: this, ...args: any[]) => any; - - _closeEditCell: (this: this, ...args: any[]) => any; - - _leftRightKeysHandler: (this: this, ...args: any[]) => any; - - _upDownKeysHandler: (this: this, ...args: any[]) => any; - - _pageUpDownKeyHandler: (this: this, ...args: any[]) => any; - - _spaceKeyHandler: (this: this, ...args: any[]) => any; - - _ctrlAKeyHandler: (this: this, ...args: any[]) => any; - - _tabKeyHandler: (this: this, ...args: any[]) => any; - - _getMaxHorizontalOffset: (this: this, ...args: any[]) => any; - - _isColumnRendered: (this: this, ...args: any[]) => any; - - _isFixedColumn: (this: this, ...args: any[]) => any; - - _isColumnVirtual: (this: this, ...args: any[]) => any; - - _processVirtualHorizontalPosition: (this: this, ...args: any[]) => any; - - _getHorizontalScrollPositionOffset: (this: this, ...args: any[]) => any; - - _editingCellTabHandler: (this: this, ...args: any[]) => any; - - _targetCellTabHandler: (this: this, ...args: any[]) => any; - - _getNextCellByTabKey: (this: this, ...args: any[]) => any; - - _checkNewLineTransition: (this: this, ...args: any[]) => any; - - _enterKeyHandler: (this: this, ...args: any[]) => any; - - _processEnterKeyForDataCell: (this: this, ...args: any[]) => any; - - _getEnterKeyDirection: (this: this, ...args: any[]) => any; - - _handleEnterKeyEditingCell: (this: this, ...args: any[]) => any; - - _escapeKeyHandler: (this: this, ...args: any[]) => any; - - _ctrlFKeyHandler: (this: this, ...args: any[]) => any; - - _f2KeyHandler: (this: this, ...args: any[]) => any; - - _navigateNextCell: (this: this, ...args: any[]) => any; - - _arrowKeysHandlerFocusCell: (this: this, ...args: any[]) => any; - - _beginFastEditing: (this: this, ...args: any[]) => any; - - _pointerEventHandler: (this: this, ...args: any[]) => any; - - _clickTargetCellHandler: (this: this, ...args: any[]) => any; - - _allowRowUpdating: (this: this, ...args: any[]) => any; - - focus: (this: this, ...args: any[]) => any; - - getFocusedView: (this: this, ...args: any[]) => any; - - setupFocusedView: (this: this, ...args: any[]) => any; - - _focusElement: (this: this, ...args: any[]) => any; - - _getFocusedViewByElement: (this: this, ...args: any[]) => any; - - _focusView: (this: this, ...args: any[]) => any; - - _resetFocusedView: (this: this, ...args: any[]) => any; - - _focusInteractiveElement: (this: this, ...args: any[]) => any; - - _focus: (this: this, ...args: any[]) => any; - - _updateFocus: (this: this, ...args: any[]) => any; - - _getFocusedCell: (this: this, ...args: any[]) => any; - - _updateFocusedCellPositionByTarget: (this: this, ...args: any[]) => any; - - _updateFocusedCellPosition: (this: this, ...args: any[]) => any; - - _getFocusedColumnIndexOffset: (this: this, ...args: any[]) => any; - - _getFixedColumnIndexOffset: (this: this, ...args: any[]) => any; - - _getCellPosition: (this: this, ...args: any[]) => any; - - _focusCell: (this: this, ...args: any[]) => any; - - _focusEditFormCell: (this: this, ...args: any[]) => any; - - _resetFocusedCell: (this: this, ...args: any[]) => any; - - restoreFocusableElement: (this: this, ...args: any[]) => any; - - _getNewPositionByCode: (this: this, ...args: any[]) => any; - - setFocusedCellPosition: (this: this, ...args: any[]) => any; - - setFocusedRowIndex: (this: this, ...args: any[]) => any; - - setFocusedColumnIndex: (this: this, ...args: any[]) => any; - - getRowIndex: (this: this, ...args: any[]) => any; - - getColumnIndex: (this: this, ...args: any[]) => any; - - getVisibleRowIndex: (this: this, ...args: any[]) => any; - - getVisibleColumnIndex: (this: this, ...args: any[]) => any; - - _applyColumnIndexBoundaries: (this: this, ...args: any[]) => any; - - _isCellByPositionValid: (this: this, ...args: any[]) => any; - - _isLastRow: (this: this, ...args: any[]) => any; - - _isFirstValidCell: (this: this, ...args: any[]) => any; - - _hasValidCellBeforePosition: (this: this, ...args: any[]) => any; - - _hasValidCellAfterPosition: (this: this, ...args: any[]) => any; - - _isLastValidCell: (this: this, ...args: any[]) => any; - - _isCellValid: (this: this, ...args: any[]) => any; - - getFirstValidCellInRow: (this: this, ...args: any[]) => any; - - _getNextCell: (this: this, ...args: any[]) => any; - - _startEditing: (this: this, ...args: any[]) => any; - - _isAllowEditing: (this: this, ...args: any[]) => any; - - _editFocusedCell: (this: this, ...args: any[]) => any; - - _startEditCell: (this: this, ...args: any[]) => any; - - _editingCellHandler: (this: this, ...args: any[]) => any; - - _fireFocusChangingEvents: (this: this, ...args: any[]) => any; - - _fireFocusedCellChanging: (this: this, ...args: any[]) => any; - - _fireFocusedCellChanged: (this: this, ...args: any[]) => any; - - _fireFocusedRowChanging: (this: this, ...args: any[]) => any; - - _fireFocusedRowChanged: (this: this, ...args: any[]) => any; - - _isEventInCurrentGrid: (this: this, ...args: any[]) => any; - - _isRowEditMode: (this: this, ...args: any[]) => any; - - _isCellEditMode: (this: this, ...args: any[]) => any; - - _isFastEditingAllowed: (this: this, ...args: any[]) => any; - - _getInteractiveElement: (this: this, ...args: any[]) => any; - - _applyTabIndexToElement: (this: this, ...args: any[]) => any; - - _getCell: (this: this, ...args: any[]) => any; - - _getRowIndex: (this: this, ...args: any[]) => any; - - _hasSkipRow: (this: this, ...args: any[]) => any; - - _allowEditingOnEnterKey: (this: this, ...args: any[]) => any; - - _isLegacyNavigation: (this: this, ...args: any[]) => any; - - _getDirectionCodeByKey: (this: this, ...args: any[]) => any; - - _isVirtualScrolling: (this: this, ...args: any[]) => any; - - _isVirtualRowRender: (this: this, ...args: any[]) => any; - - _isVirtualColumnRender: (this: this, ...args: any[]) => any; - - _scrollBy: (this: this, ...args: any[]) => any; - - _isInsideEditForm: (this: this, ...args: any[]) => any; - - _isMasterDetailCell: (this: this, ...args: any[]) => any; - - _processNextCellInMasterDetail: (this: this, ...args: any[]) => any; - - _handleTabKeyOnMasterDetailCell: (this: this, ...args: any[]) => any; - - _getElementType: (this: this, ...args: any[]) => any; - - _isFastEditingStarted: (this: this, ...args: any[]) => any; - - _getVisibleColumnCount: (this: this, ...args: any[]) => any; - - _isCellInRow: (this: this, ...args: any[]) => any; - - _getCellElementFromTarget: (this: this, ...args: any[]) => any; - - _getRowsViewElement: (this: this, ...args: any[]) => any; - - isKeyboardEnabled: (this: this, ...args: any[]) => any; - - _processCanceledEditCellPosition: (this: this, ...args: any[]) => any; - - updateFocusedRowIndex: (this: this, ...args: any[]) => any; - - _isCellElement: (this: this, ...args: any[]) => any; -} diff --git a/packages/devextreme/scss/widgets/base/dataGrid/_index.scss b/packages/devextreme/scss/widgets/base/dataGrid/_index.scss index 99bd7d2221c2..c21a589b1c9f 100644 --- a/packages/devextreme/scss/widgets/base/dataGrid/_index.scss +++ b/packages/devextreme/scss/widgets/base/dataGrid/_index.scss @@ -331,3 +331,15 @@ $datagrid-text-stub-background-image-path: null !default; background-color: color.change($datagrid-base-color, $alpha: 0.08); } } + +.dx-datagrid-total-footer { + tr { + outline: none; + } + + &:focus-within { + outline: 2px solid $datagrid-focused-border-color; + outline-offset: -2px; + } +} + diff --git a/packages/devextreme/testing/testcafe/tests/dataGrid/etalons/group-summary-focused.png b/packages/devextreme/testing/testcafe/tests/dataGrid/etalons/group-summary-focused.png new file mode 100644 index 0000000000000000000000000000000000000000..7c4d82ea285004314ff7b8e269f7f09d954567ed GIT binary patch literal 5052 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 BTV((M literal 0 HcmV?d00001 diff --git a/packages/devextreme/testing/testcafe/tests/dataGrid/etalons/total-summary-focused.png b/packages/devextreme/testing/testcafe/tests/dataGrid/etalons/total-summary-focused.png new file mode 100644 index 0000000000000000000000000000000000000000..325862083ac9f8a19518de88e1a137e9c05b574b GIT binary patch literal 5070 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 LeqZsIC%^kUJ5#$L literal 0 HcmV?d00001 diff --git a/packages/devextreme/testing/testcafe/tests/dataGrid/summary.ts b/packages/devextreme/testing/testcafe/tests/dataGrid/summary.ts new file mode 100644 index 000000000000..97429142a983 --- /dev/null +++ b/packages/devextreme/testing/testcafe/tests/dataGrid/summary.ts @@ -0,0 +1,112 @@ +import { createScreenshotsComparer } from 'devextreme-screenshot-comparer'; +import DataGrid from '../../model/dataGrid'; +import url from '../../helpers/getPageUrl'; +import createWidget from '../../helpers/createWidget'; + +fixture.disablePageReloads`Summary` + .page(url(__dirname, '../container.html')); + +test('Group footer summary should be focusable', async (t) => { + const dataGrid = new DataGrid('#container'); + const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + + await t.click(dataGrid.getDataRow(4).getDataCell(1).element); + await t + .pressKey('tab'); + + await t + .expect(await takeScreenshot('group-summary-focused.png', dataGrid.element)).ok() + .expect(compareResults.isValid()).ok(compareResults.errorMessages()); +}).before(async () => createWidget('dxDataGrid', { + dataSource: [ + { id: 1, value: 1 }, + { id: 2, value: 1 }, + { id: 3, value: 1 }, + { id: 4, value: 1 }, + ], + columns: [ + 'id', + { + dataField: 'value', + groupIndex: 0, + }, + ], + summary: { + groupItems: [ + { + column: 'id', + summaryType: 'count', + showInGroupFooter: true, + }, + ], + }, +})); + +test('Total summary should be focusable', async (t) => { + const dataGrid = new DataGrid('#container'); + const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + + await t.click(dataGrid.getDataRow(3).element); + await t + .pressKey('tab'); + + await t + .expect(await takeScreenshot('total-summary-focused.png', dataGrid.element)).ok() + .expect(compareResults.isValid()).ok(compareResults.errorMessages()); +}).before(async () => createWidget('dxDataGrid', { + dataSource: [ + { id: 1, value: 1 }, + { id: 2, value: 1 }, + { id: 3, value: 1 }, + { id: 4, value: 1 }, + ], + summary: { + totalItems: [ + { + column: 'id', + summaryType: 'count', + }, + ], + }, +})); + +test('Group footer navigation should work without keyboard trap', async (t) => { + const dataGrid = new DataGrid('#container'); + + await t.click(dataGrid.getDataRow(4).getDataCell(1).element); + await t + .pressKey('down') + .pressKey('tab'); + + await t.expect(dataGrid.getFooterRow().focused).ok(); +}).before(async () => createWidget('dxDataGrid', { + dataSource: [ + { id: 1, value1: 1, value2: 1 }, + { id: 2, value1: 1, value2: 1 }, + { id: 3, value1: 1, value2: 1 }, + { id: 4, value1: 1, value2: 1 }, + ], + columns: [ + 'id', + { + dataField: 'value1', + groupIndex: 0, + }, + 'value2', + ], + summary: { + groupItems: [ + { + column: 'id', + summaryType: 'count', + showInGroupFooter: true, + }, + ], + totalItems: [ + { + column: 'id', + summaryType: 'count', + }, + ], + }, +}));