⚠ This page is served via a proxy. Original site: https://github.com
This service does not collect credentials or authentication data.
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const DATAGRID_CELL_DISABLED = 'dx-cell-focus-disabled';
const DATAGRID_GROUP_FOOTER_ROW_TYPE = 'groupFooter';
const DATAGRID_TOTAL_FOOTER_ROW_TYPE = 'totalFooter';

export const renderSummaryCell = function (cell, options) {
export const renderSummaryCell = function (cell, options, setAria) {
const $cell = $(cell);
const { column } = options;
const { summaryItems } = options;
Expand All @@ -47,15 +47,16 @@ export const renderSummaryCell = function (cell, options) {
for (let i = 0; i < summaryItems.length; i++) {
const summaryItem = summaryItems[i];
const text = gridCore.getSummaryText(summaryItem, options.summaryTexts);

$summaryItems.push($('<div>')
const $summaryItemElement = $('<div>')
.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(text)
.attr('aria-label', `${column.caption} ${text}`));
.text(text);

setAria('label', `${column.caption} ${text}`, $summaryItemElement);
$summaryItems.push($summaryItemElement);
}
$cell.append($summaryItems);
}
Expand Down Expand Up @@ -204,7 +205,7 @@ export class FooterView extends ColumnsView {
}

protected _renderCellContent($cell, options) {
renderSummaryCell($cell, options);
renderSummaryCell($cell, options, this.setAria.bind(this));
// @ts-expect-error
super._renderCellContent.apply(this, arguments);
}
Expand Down Expand Up @@ -911,7 +912,7 @@ const rowsView = (Base: ModuleType<RowsView>) => class SummaryRowsViewExtender e

protected _getCellTemplate(options) {
if (!options.column.command && !isDefined(options.column.groupIndex) && options.summaryItems && options.summaryItems.length) {
return renderSummaryCell;
return (cell, options) => renderSummaryCell(cell, options, this.setAria.bind(this));
}
return super._getCellTemplate(options);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import {
afterEach, beforeEach, describe, expect, it, jest,
} from '@jest/globals';
import fx from '@js/common/core/animation/fx';
import type { dxElementWrapper } from '@js/core/renderer';
import $ from '@js/core/renderer';
import type { Properties as DataGridProperties } from '@js/ui/data_grid';
import DataGrid from '@js/ui/data_grid';
import { DataGridModel } from '@ts/grids/data_grid/__tests__/__mock__/model/data_grid';

const SELECTORS = {
gridContainer: '#gridContainer',
};

const GRID_CONTAINER_ID = 'gridContainer';

const createDataGrid = async (
options: DataGridProperties = {},
): Promise<{
$container: dxElementWrapper;
component: DataGridModel;
instance: DataGrid;
}> => new Promise((resolve) => {
const $container = $('<div>')
.attr('id', GRID_CONTAINER_ID)
.appendTo(document.body);

const dataGridOptions: DataGridProperties = {
keyExpr: 'id',
...options,
};

const instance = new DataGrid($container.get(0) as HTMLDivElement, dataGridOptions);
const component = new DataGridModel($container.get(0) as HTMLElement);

jest.runAllTimers();

resolve({
$container,
component,
instance,
});
});

const beforeTest = (): void => {
fx.off = true;
jest.useFakeTimers();
};

const afterTest = (): void => {
const $container = $(SELECTORS.gridContainer);
const dataGrid = ($container as any).dxDataGrid('instance') as DataGrid;

dataGrid.dispose();
$container.remove();
jest.clearAllMocks();
jest.useRealTimers();
fx.off = false;
};

describe('Grid', () => {
beforeEach(beforeTest);
afterEach(afterTest);

describe('when column caption has a newline character', () => {
it('should exclude the newline character from the header filter\'s aria-label', async () => {
const { component } = await createDataGrid({
dataSource: [
{ id: 1, name: 'Name 1', value: 10 },
{ id: 2, name: 'Name 2', value: 20 },
],
columns: ['id', { dataField: 'name', caption: 'Test\nName' }, 'value'],
showBorders: true,
headerFilter: {
visible: true,
},
});

expect(component.getHeaderCellFilter(1).attr('aria-label')).not.toMatch(/\n/);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -849,7 +849,10 @@ export class AdaptiveColumnsController extends modules.ViewController {

public setCommandAdaptiveAriaLabel($row, labelName) {
const $adaptiveCommand = $row.find('.dx-command-adaptive');
$adaptiveCommand.attr('aria-label', messageLocalization.format(labelName));

if ($adaptiveCommand.length) {
this.setAria('label', messageLocalization.format(labelName), $adaptiveCommand);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2302,7 +2302,10 @@ class EditingControllerImpl extends modules.ViewController {
$container.addClass(COMMAND_EDIT_WITH_ICONS_CLASS);

const localizationName = this.getButtonLocalizationNames()[button.name];
localizationName && $button.attr('aria-label', messageLocalization.format(localizationName));

if (localizationName) {
this.setAria('label', messageLocalization.format(localizationName), $button);
}
} else {
$button.text(button.text);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,6 @@ const editingControllerExtender = (Base: ModuleType<EditingController>) => class
}
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
protected _updateEditRowCore(row, skipCurrentRow, isCustomSetCellValue) {
const editForm = this._editForm;

Expand Down Expand Up @@ -219,7 +218,7 @@ const editingControllerExtender = (Base: ModuleType<EditingController>) => class

formTemplate(this._$popupContent, templateOptions, { isPopupForm: true });
this._rowsView.renderDelayedTemplates();
$(container).parent().attr('aria-label', this.localize('dxDataGrid-ariaEditForm'));
this.setAria('label', this.localize('dxDataGrid-ariaEditForm'), $(container).parent());
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,12 @@ export class ErrorHandlingController extends modules.ViewController {
private _renderErrorMessage(error) {
const message = error.url ? error.message.replace(error.url, '') : error.message || error;
const $message = $('<div>')
.attr('role', 'alert')
.attr('aria-roledescription', messageLocalization.format('dxDataGrid-ariaError'))
.addClass(ERROR_MESSAGE_CLASS)
.text(message);

this.setAria('role', 'alert', $message);
this.setAria('roledescription', messageLocalization.format('dxDataGrid-ariaError'), $message);

if (error.url) {
$('<a>').attr('href', error.url).text(error.url).appendTo($message);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -542,9 +542,9 @@ export const headerFilterMixin = <T extends ModuleType<any>>(Base: T) => class H

const indicatorLabel = (messageLocalization.format as any)('dxDataGrid-headerFilterIndicatorLabel', column.caption);

$headerFilterIndicator.attr('aria-label', indicatorLabel);
$headerFilterIndicator.attr('aria-haspopup', 'dialog');
$headerFilterIndicator.attr('role', 'button');
this.setAria('label', indicatorLabel, $headerFilterIndicator);
this.setAria('haspopup', 'dialog', $headerFilterIndicator);
this.setAria('role', 'button', $headerFilterIndicator);
}

return $headerFilterIndicator;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ export class HeaderPanel extends ColumnsView {
const $headerPanel = this.element();
$headerPanel.addClass(this.addWidgetPrefix(HEADER_PANEL_CLASS));
const label = messageLocalization.format(this.component.NAME + TOOLBAR_ARIA_LABEL);
const $toolbar = $('<div>').attr('aria-label', label).appendTo($headerPanel);
const $toolbar = $('<div>').appendTo($headerPanel);

this.setAria('label', label, $toolbar);
this._toolbar = this._createComponent($toolbar, Toolbar, this._toolbarOptions);
} else {
this._toolbar.option(this._toolbarOptions!);
Expand Down
14 changes: 7 additions & 7 deletions packages/devextreme/js/__internal/grids/grid_core/m_modules.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
/* eslint-disable max-classes-per-file */
/* eslint-disable @typescript-eslint/method-signature-style */

import messageLocalization from '@js/common/core/localization/message';
import type { Component } from '@js/core/component';
import type { dxElementWrapper } from '@js/core/renderer';
Expand Down Expand Up @@ -145,14 +145,15 @@ export class ModuleItem {
return this._actions[actionName];
}

public setAria(name, value, $target) {
public setAria(name: string, value: any, $target: dxElementWrapper) {
const target = $target.get(0);
const prefix = name !== 'role' && name !== 'id' ? 'aria-' : '';
const normalizedValue = String(value).replace(/\s+/g, ' ').trim();

if (target.setAttribute) {
target.setAttribute(prefix + name, value);
if (target?.setAttribute) {
target.setAttribute(prefix + name, normalizedValue);
} else {
$target.attr(prefix + name, value);
$target.attr(prefix + name, normalizedValue);
}
}

Expand Down Expand Up @@ -485,9 +486,8 @@ export function processModules(
rootViewTypes,
);

// eslint-disable-next-line no-param-reassign
componentInstance._controllers = createModuleItems(controllerTypes);
// eslint-disable-next-line no-param-reassign

componentInstance._views = createModuleItems(viewTypes);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ const rowsView = (Base: ModuleType<RowsView>) => class RowsViewMasterDetailExten
const isEditForm = row.isEditing;

if (!isEditForm) {
$detailCell.attr('aria-roledescription', messageLocalization.format('dxDataGrid-masterDetail'));
this.setAria('roledescription', messageLocalization.format('dxDataGrid-masterDetail'), $detailCell);
}

return $detailCell;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1390,8 +1390,9 @@ export const validatingEditorFactoryExtender = (Base: ModuleType<EditorFactory>)

if (shouldSetValidationAriaAttributes) {
const $focusElement = this._getCurrentFocusElement($focus);
$focusElement.attr('aria-labelledby', inputDescriptionValues.join(' '));
$focusElement.attr('aria-invalid', true);

this.setAria('labelledby', inputDescriptionValues.join(' '), $focusElement);
this.setAria('invalid', true, $focusElement);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { addShadowDomStyles } from 'core/utils/shadow_dom';

import * as summaryModule from '__internal/grids/data_grid/summary/m_summary';
import gridCoreUtils from '__internal/grids/grid_core/m_utils';
import { noop } from 'core/utils/common';

QUnit.testStart(function() {
const markup =
Expand Down Expand Up @@ -448,7 +449,7 @@ QUnit.module('Summary footer', {
}],
column: { alignment: 'left' },
summaryTexts: summaryTexts
});
}, noop);

// assert
assert.equal($cellElements[0].find('.dx-datagrid-summary-item').text(), 119, 'column is not command');
Expand All @@ -462,7 +463,7 @@ QUnit.module('Summary footer', {
}],
column: { command: 'expand', alignment: 'left' },
summaryTexts: summaryTexts
});
}, noop);

// assert
assert.equal($cellElements[1].html(), '', 'command column');
Expand Down
Loading