diff --git a/e2e/testcafe-devextreme/tests/accessibility/pivotGrid.ts b/e2e/testcafe-devextreme/tests/accessibility/pivotGrid.ts new file mode 100644 index 000000000000..d5a9dc3b1b02 --- /dev/null +++ b/e2e/testcafe-devextreme/tests/accessibility/pivotGrid.ts @@ -0,0 +1,106 @@ +import PivotGrid from 'devextreme-testcafe-models/pivotGrid'; +import { Selector } from 'testcafe'; +import url from '../../helpers/getPageUrl'; +import { createWidget } from '../../helpers/createWidget'; +import { a11yCheck } from '../../helpers/accessibility/utils'; + +fixture.disablePageReloads`PivotGrid - Accessibility` + .page(url(__dirname, '../container.html')); + +const PIVOT_GRID_SELECTOR = '#container'; + +const createConfig = () => ({ + width: 1000, + allowSorting: true, + allowSortingBySummary: true, + allowFiltering: true, + allowExpandAll: true, + showBorders: true, + fieldPanel: { + visible: true, + }, + fieldChooser: { + enabled: true, + height: 500, + }, + dataSource: { + fields: [{ + dataField: 'country', + area: 'filter', + }, { + caption: 'Region', + width: 120, + dataField: 'region', + area: 'row', + }, { + caption: 'City', + dataField: 'city', + width: 150, + area: 'row', + }, { + caption: 'Country', + dataField: 'country', + area: 'column', + }, { + dataField: 'date', + dataType: 'date', + area: 'column', + }, { + groupName: 'date', + groupInterval: 'year', + expanded: true, + area: 'column', + }, { + caption: 'Sales', + dataField: 'amount', + dataType: 'number', + summaryType: 'sum', + area: 'data', + }], + store: [{ + region: 'Africa', + country: 'Egypt', + city: 'Cairo', + amount: 500, + date: new Date('2015-05-26'), + }, { + region: 'South America', + country: 'Argentina', + city: 'Buenos Aires', + amount: 780, + date: new Date('2015-05-07'), + }], + }, +}); + +test('grid with field panel', async (t) => { + await a11yCheck(t, {}, PIVOT_GRID_SELECTOR); +}).before(async () => createWidget('dxPivotGrid', createConfig())); + +test('field chooser popup', async (t) => { + const pivotGrid = new PivotGrid(PIVOT_GRID_SELECTOR); + + await t.click(pivotGrid.getFieldChooserButton()); + + await a11yCheck(t); +}).before(async () => createWidget('dxPivotGrid', createConfig())); + +test('header filter popup', async (t) => { + const pivotGrid = new PivotGrid(PIVOT_GRID_SELECTOR); + const filterIcon = pivotGrid + .getColumnHeaderArea() + .getHeaderFilterIcon() + .element; + + await t.click(filterIcon); + + await a11yCheck(t); +}).before(async () => createWidget('dxPivotGrid', createConfig())); + +test('cell context menu', async (t) => { + const columnHeaderCell = Selector('.dx-pivotgrid-horizontal-headers td[tabindex]'); + + await t.rightClick(columnHeaderCell); + + await a11yCheck(t); +}).before(async () => createWidget('dxPivotGrid', createConfig())); diff --git a/e2e/testcafe-devextreme/tests/common/pivotGrid/kbn/fields.ts b/e2e/testcafe-devextreme/tests/common/pivotGrid/kbn/fields.ts index faed3c6abb61..011f13651e09 100644 --- a/e2e/testcafe-devextreme/tests/common/pivotGrid/kbn/fields.ts +++ b/e2e/testcafe-devextreme/tests/common/pivotGrid/kbn/fields.ts @@ -112,6 +112,32 @@ const createConfig = () => ({ ? Selector(`.dx-pivotgridfieldchooser .dx-area-fields[group="${area}"]`) : Selector(`.dx-pivotgrid-fields-area[group="${area}"]`)); + test(`${testTitlePrefix}: Fields should be exposed as menu items of an area menubar`, async (t) => { + const pivotGrid = new PivotGrid(PIVOT_GRID_SELECTOR); + + if (isFieldChooser) { + await t.click(pivotGrid.getFieldChooserButton()); + } + + const rowAreaContainer = getAreaFieldsContainer('row'); + const menubar = rowAreaContainer.find('[role="menubar"]'); + const firstField = getField(pivotGrid, 'row', 0); + + await t + .expect(menubar.count) + .eql(1, 'the area has a single menubar') + .expect(menubar.getAttribute('aria-label')) + .eql('Row Fields', 'the menubar is labelled with the area name') + .expect(menubar.getAttribute('aria-description')) + .ok('the menubar describes the available keyboard interactions'); + + await t + .expect(firstField.getAttribute('role')) + .eql('menuitem', 'a field is exposed as a menu item') + .expect(firstField.getAttribute('aria-label')) + .eql('Field: Region, Sort order: ascending', 'the field label includes the name and the sorting state'); + }).before(async () => createWidget('dxPivotGrid', createConfig())); + ['filter', 'data', 'column', 'row'].forEach((area) => { test(`${testTitlePrefix}: Fields in ${area} area should form a single tab stop`, async (t) => { const pivotGrid = new PivotGrid(PIVOT_GRID_SELECTOR); @@ -381,3 +407,58 @@ test('FieldChooser: Should traverse fields in all areas by tab', async (t) => { .expect(dataFirstField.focused) .ok('first field in data area is focused'); }).before(async () => createWidget('dxPivotGrid', createConfig())); + +// TestCafe's pressKey does not support function keys (F1-F12), so the Shift+F10 +// shortcut is reproduced by dispatching the keydown event on the focused field. +const SHIFT_F10_KEYDOWN = { + key: 'F10', code: 'F10', shiftKey: true, bubbles: true, cancelable: true, +}; + +test('PivotGrid: Should open the context menu by Shift+F10 on a field', async (t) => { + const pivotGrid = new PivotGrid(PIVOT_GRID_SELECTOR); + const firstField = pivotGrid.getRowHeaderArea().getField(0); + const contextMenuItem = Selector('.dx-context-menu .dx-menu-item-text').withText('Show Field Chooser'); + + await t + .click(firstField) + .expect(firstField.focused) + .ok('field is focused after click') + .dispatchEvent(firstField, 'keydown', SHIFT_F10_KEYDOWN) + .expect(contextMenuItem.visible) + .ok('the field context menu is shown after Shift+F10'); +}).before(async () => createWidget('dxPivotGrid', createConfig())); + +test('PivotGrid: Field should have focus after the context menu is closed', async (t) => { + const pivotGrid = new PivotGrid(PIVOT_GRID_SELECTOR); + const firstField = pivotGrid.getRowHeaderArea().getField(0); + const contextMenuItem = Selector('.dx-context-menu .dx-menu-item-text').withText('Show Field Chooser'); + + await t + .click(firstField) + .dispatchEvent(firstField, 'keydown', SHIFT_F10_KEYDOWN) + .expect(contextMenuItem.visible) + .ok('the field context menu is shown after Shift+F10'); + + await t + .pressKey('esc') + .expect(firstField.focused) + .ok('the field is focused after the context menu is closed'); +}).before(async () => createWidget('dxPivotGrid', createConfig())); + +test('FieldChooser: Shift+F10 on a popup field should not open the grid context menu', async (t) => { + const pivotGrid = new PivotGrid(PIVOT_GRID_SELECTOR); + const fieldChooser = pivotGrid.getFieldChooser(); + const contextMenu = Selector('.dx-context-menu .dx-menu-item-text'); + + await t.click(pivotGrid.getFieldChooserButton()); + + const firstField = fieldChooser.getRowAreaItem(0); + + // Parity with the mouse: right-click on the popup fields does not show the + // grid context menu either. + await t + .click(firstField) + .dispatchEvent(firstField, 'keydown', SHIFT_F10_KEYDOWN) + .expect(contextMenu.exists) + .notOk('the grid context menu is not shown for a field chooser popup field'); +}).before(async () => createWidget('dxPivotGrid', createConfig())); diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/a11y/data_cell_description.test.ts b/packages/devextreme/js/__internal/grids/pivot_grid/a11y/data_cell_description.test.ts new file mode 100644 index 000000000000..7f25d74ac399 --- /dev/null +++ b/packages/devextreme/js/__internal/grids/pivot_grid/a11y/data_cell_description.test.ts @@ -0,0 +1,115 @@ +import { describe, expect, it } from '@jest/globals'; + +import { describeDataCellsWithHeaders } from './data_cell_description'; + +const createSection = (tag: 'thead' | 'tbody', rowsHtml: string): HTMLTableSectionElement => { + const table = document.createElement('table'); + table.innerHTML = `<${tag}>${rowsHtml}${tag}>`; + return table.querySelector(tag) as HTMLTableSectionElement; +}; + +const getDescribingCells = (cell: HTMLTableCellElement | null): (Element | null)[] => (cell?.getAttribute('aria-describedby') ?? '') + .split(' ') + .filter((id) => !!id) + .map((id) => document.getElementById(id)); + +describe('describeDataCellsWithHeaders', () => { + it('should reference the column header path including colspan groups', () => { + const columns = createSection('thead', ` +
| ').append(fieldChooserBase.renderField(field, field.area === 'row')); + const td = $(' | ') + .attr('role', 'none') + .append(fieldChooserBase.renderField(field, field.area === 'row')); const indicators = td.find('.dx-column-indicators'); if (indicators.length && that._shouldCreateButton()) { indicators.insertAfter((indicators as any).next()); @@ -167,7 +182,25 @@ class FieldsArea extends AreaItem { renderGroupConnector(field, data[index + 1], data[index - 1], td); } }); - if (!row.children().length) { + if (row.children().length) { + // Expose the fields as a menubar of menu items, consistent with the + // field chooser and CardView. The menubar role lives on the table + // element (it is invalid on a table row); thead/tr/td are kept out of + // the accessibility tree so the field items become the menubar's items. + row.attr('role', 'presentation'); + tableElement + .attr('role', 'menubar') + .attr('aria-label', this._getAreaLabel()) + .attr('aria-description', getFieldsAreaA11yDescription()); + } else { + // A menubar without menu items is invalid ARIA, so an empty area keeps + // the plain placeholder text and the table stays presentational. The + // role is reset explicitly because the table element is reused across + // re-renders. + tableElement + .attr('role', 'presentation') + .removeAttr('aria-label') + .removeAttr('aria-description'); $(' | ').append($(DIV).addClass('dx-empty-area-text').text(this.option(`fieldPanel.texts.${area}FieldArea`))).appendTo(row); } diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts b/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts index f122d1881117..3e8a2c750766 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts @@ -26,6 +26,7 @@ import { current, isGeneric } from '@js/ui/themes'; import Widget from '@ts/core/widget/widget'; import gridCoreUtils from '@ts/grids/grid_core/m_utils'; +import { describeDataCellsWithHeaders } from './a11y/data_cell_description'; import { ChartIntegrationMixin } from './chart_integration/m_chart_integration'; import DataAreaImport from './data_area/m_data_area'; import DataControllerImport from './data_controller/m_data_controller'; @@ -1053,7 +1054,19 @@ class PivotGrid extends Widget { const cell = e.currentTarget; const navigation = this._getCellAreaNavigation(cell); - if (!navigation || !this._contextMenu) { + if (!navigation) { + return; + } + + this._showContextMenuFromKeyboard(e, navigation); + } + + _handleFieldContextMenuKeyDown(e, navigation: RovingTabIndex) { + this._showContextMenuFromKeyboard(e, navigation); + } + + _showContextMenuFromKeyboard(e, navigation: RovingTabIndex) { + if (!this._contextMenu) { return; } @@ -1449,6 +1462,7 @@ class PivotGrid extends Widget { visible: that.option('visible'), // @ts-expect-error ts-error remoteSort: that.option('scrolling.mode') === 'virtual', + onFieldContextMenuKeyDown: that._handleFieldContextMenuKeyDown.bind(that), }; if (that._fieldChooserBase) { @@ -1505,6 +1519,14 @@ class PivotGrid extends Widget { .attr('aria-owns', tableIds) .attr('aria-rowcount', this._dataController.totalRowCount()) .attr('aria-colcount', this._dataController.totalColumnCount()); + + // The areas can be partially stubbed in tests, so the sections are + // resolved defensively. + describeDataCellsWithHeaders( + columnsArea.headElement?.()?.get(0), + rowsArea.tableElement()?.children('tbody').get(0), + dataArea.tableElement()?.children('tbody').get(0), + ); } _update(isFirstDrawing) { diff --git a/packages/devextreme/js/localization/messages/ar.json b/packages/devextreme/js/localization/messages/ar.json index 0c0bbb248d7a..1494f4550c7b 100644 --- a/packages/devextreme/js/localization/messages/ar.json +++ b/packages/devextreme/js/localization/messages/ar.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "إفلات حقول البيانات هنا", "dxPivotGrid-rowFieldArea": "إفلات حقول الصف هنا", "dxPivotGrid-filterFieldArea": "إفلات حقول التصفية هنا", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "من {0} إلى {1}", "dxScheduler-ariaLabel": "المجدول. عرض {0}: {1} مع {2} مواعيد", diff --git a/packages/devextreme/js/localization/messages/bg.json b/packages/devextreme/js/localization/messages/bg.json index 2f366d172a26..5471b88035de 100644 --- a/packages/devextreme/js/localization/messages/bg.json +++ b/packages/devextreme/js/localization/messages/bg.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Пуснете полета с данни тук", "dxPivotGrid-rowFieldArea": "Пуснете полета на реда тук", "dxPivotGrid-filterFieldArea": "Пуснете полета за филтриране тук", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "от {0} до {1}", "dxScheduler-ariaLabel": "Планиращ. Изглед {0}: {1} с {2} срещи", diff --git a/packages/devextreme/js/localization/messages/ca.json b/packages/devextreme/js/localization/messages/ca.json index e6048fce76ea..b3ad530a7371 100644 --- a/packages/devextreme/js/localization/messages/ca.json +++ b/packages/devextreme/js/localization/messages/ca.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Deixar els camps de dades aquí", "dxPivotGrid-rowFieldArea": "Els camps de fila de la fila aquí", "dxPivotGrid-filterFieldArea": "Els camps de filtre de baixada aquí", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "de {0} a {1}", "dxScheduler-ariaLabel": "Planificador. Vista {0}: {1} amb {2} cites", diff --git a/packages/devextreme/js/localization/messages/cs.json b/packages/devextreme/js/localization/messages/cs.json index 8b0101b4a5c4..65d9167147de 100644 --- a/packages/devextreme/js/localization/messages/cs.json +++ b/packages/devextreme/js/localization/messages/cs.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Zde vložte pole dat", "dxPivotGrid-rowFieldArea": "Zde vložte pole řádků", "dxPivotGrid-filterFieldArea": "Zde vložte filtr pole", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "od {0} do {1}", "dxScheduler-ariaLabel": "Plánovač. Zobrazení {0}: {1} s {2} schůzkami", diff --git a/packages/devextreme/js/localization/messages/da.json b/packages/devextreme/js/localization/messages/da.json index d7a4c2742cca..beed4beca18b 100644 --- a/packages/devextreme/js/localization/messages/da.json +++ b/packages/devextreme/js/localization/messages/da.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Slip datafelter her", "dxPivotGrid-rowFieldArea": "Slip rækkefelter her", "dxPivotGrid-filterFieldArea": "Slip filterfelter her", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "fra {0} til {1}", "dxScheduler-ariaLabel": "Planlægger. {0} visning: {1} med {2} aftaler", diff --git a/packages/devextreme/js/localization/messages/de.json b/packages/devextreme/js/localization/messages/de.json index d14b0b30d688..000e35e50d45 100644 --- a/packages/devextreme/js/localization/messages/de.json +++ b/packages/devextreme/js/localization/messages/de.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Datenfelder hierher ziehen", "dxPivotGrid-rowFieldArea": "Zeilenfelder hierher ziehen", "dxPivotGrid-filterFieldArea": "Filterfelder hierher ziehen", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "von {0} bis {1}", "dxScheduler-ariaLabel": "Planer. {0} Ansicht: {1} mit {2} Terminen", diff --git a/packages/devextreme/js/localization/messages/el.json b/packages/devextreme/js/localization/messages/el.json index 2ace941c689c..2dea7899684c 100644 --- a/packages/devextreme/js/localization/messages/el.json +++ b/packages/devextreme/js/localization/messages/el.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Τοποθετήστε τα πεδία δεδομένων εδώ", "dxPivotGrid-rowFieldArea": "Τοποθετήστε τα πεδία γραμμών εδώ", "dxPivotGrid-filterFieldArea": "Τοποθετήστε τα πεδία φίλτρων εδώ", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "από {0} έως {1}", "dxScheduler-ariaLabel": "Χρονοδιάγραμμα. Προβολή {0}: {1} με {2} ραντεβού", diff --git a/packages/devextreme/js/localization/messages/en.json b/packages/devextreme/js/localization/messages/en.json index f7e629931ce9..cd72599595bf 100644 --- a/packages/devextreme/js/localization/messages/en.json +++ b/packages/devextreme/js/localization/messages/en.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Drop Data Fields Here", "dxPivotGrid-rowFieldArea": "Drop Row Fields Here", "dxPivotGrid-filterFieldArea": "Drop Filter Fields Here", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "from {0} to {1}", "dxScheduler-ariaLabel": "Scheduler. {0} view: {1} with {2} appointments", diff --git a/packages/devextreme/js/localization/messages/es.json b/packages/devextreme/js/localization/messages/es.json index 9dc3543fe8fc..8dfae2975cf1 100644 --- a/packages/devextreme/js/localization/messages/es.json +++ b/packages/devextreme/js/localization/messages/es.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Arrastra campos de dato aquí", "dxPivotGrid-rowFieldArea": "Arrastra campos de fila aquí", "dxPivotGrid-filterFieldArea": "Arrastra campos de filtro aquí", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "desde {0} hasta {1}", "dxScheduler-ariaLabel": "Programador. Vista {0}: {1} con {2} citas", diff --git a/packages/devextreme/js/localization/messages/fa.json b/packages/devextreme/js/localization/messages/fa.json index 3191cfcc8315..a1c5a186a7c7 100644 --- a/packages/devextreme/js/localization/messages/fa.json +++ b/packages/devextreme/js/localization/messages/fa.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "فیلدهای داده ای را به اینجا انتقال دهید (درگ نمایید)", "dxPivotGrid-rowFieldArea": "فیلدهای مربوط به سطر را به اینجا انتقال دهید (درگ نمایید)", "dxPivotGrid-filterFieldArea": "فیلدهای مربوط به فیلتر را به اینجا انتقال دهید (درگ نمایید)", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "از {0} تا {1}", "dxScheduler-ariaLabel": "زمانبندی. نمای {0}: {1} با {2} قرار ملاقات", diff --git a/packages/devextreme/js/localization/messages/fi.json b/packages/devextreme/js/localization/messages/fi.json index 8e90fb99eebf..65cc2ee5d63e 100644 --- a/packages/devextreme/js/localization/messages/fi.json +++ b/packages/devextreme/js/localization/messages/fi.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Pudota tietokentät tähän", "dxPivotGrid-rowFieldArea": "Pudota rivikentät tähän", "dxPivotGrid-filterFieldArea": "Pudota suodatinkentät tähän", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "{0}–{1}", "dxScheduler-ariaLabel": "Kalenteri. {0} näkymä: {1}, {2} tapaamista", diff --git a/packages/devextreme/js/localization/messages/fr.json b/packages/devextreme/js/localization/messages/fr.json index fd4c092b2250..6fd233c42e21 100644 --- a/packages/devextreme/js/localization/messages/fr.json +++ b/packages/devextreme/js/localization/messages/fr.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Déposer les champs de données ici", "dxPivotGrid-rowFieldArea": "Déposer les champs de ligne ici", "dxPivotGrid-filterFieldArea": "Déposer les champs de filtre ici", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "de {0} à {1}", "dxScheduler-ariaLabel": "Agenda. {0} vue : {1} avec {2} rendez-vous", diff --git a/packages/devextreme/js/localization/messages/hi.json b/packages/devextreme/js/localization/messages/hi.json index 1c1f79392548..8d5b3aff28fb 100644 --- a/packages/devextreme/js/localization/messages/hi.json +++ b/packages/devextreme/js/localization/messages/hi.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "डेटा फ़ील्ड यहां छोड़ें", "dxPivotGrid-rowFieldArea": "पंक्ति फ़ील्ड्स को यहां छोड़ें", "dxPivotGrid-filterFieldArea": "फ़िल्टर फ़ील्ड यहां छोड़ें", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "{0} से {1} तक", "dxScheduler-ariaLabel": "अनुसूचक. {0} दृश्य: {1} {2} नियुक्तियों के साथ", diff --git a/packages/devextreme/js/localization/messages/hu.json b/packages/devextreme/js/localization/messages/hu.json index f94c9113dc64..7b3965d86af5 100644 --- a/packages/devextreme/js/localization/messages/hu.json +++ b/packages/devextreme/js/localization/messages/hu.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Húzza az adatmezőket ide", "dxPivotGrid-rowFieldArea": "Húzza a sormezőket ide", "dxPivotGrid-filterFieldArea": "Húzza a szűrőmezőket ide", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "{0}-tól {1}-ig", "dxScheduler-ariaLabel": "Ütemező. {0} nézet: {1}, {2} eseménnyel", diff --git a/packages/devextreme/js/localization/messages/it.json b/packages/devextreme/js/localization/messages/it.json index 9318c530353e..044cffdbcdb8 100644 --- a/packages/devextreme/js/localization/messages/it.json +++ b/packages/devextreme/js/localization/messages/it.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Trascina qui i campi dati", "dxPivotGrid-rowFieldArea": "Trascina qui i campi riga", "dxPivotGrid-filterFieldArea": "Trascina qui i campi filtro", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "da {0} a {1}", "dxScheduler-ariaLabel": "Pianificatore. Vista {0}: {1} con {2} appuntamenti", diff --git a/packages/devextreme/js/localization/messages/ja.json b/packages/devextreme/js/localization/messages/ja.json index 80b25947b215..69dd7c165412 100644 --- a/packages/devextreme/js/localization/messages/ja.json +++ b/packages/devextreme/js/localization/messages/ja.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "データ フィールドをこちらへドラッグ&ドロップ", "dxPivotGrid-rowFieldArea": "行フィールドをこちらへドラッグ&ドロップ", "dxPivotGrid-filterFieldArea": "フィルター フィールドをこちらへドラッグ&ドロップ", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "{0} から {1} まで", "dxScheduler-ariaLabel": "スケジューラー。{0} ビュー: {2} 件の予定がある {1}", diff --git a/packages/devextreme/js/localization/messages/ko.json b/packages/devextreme/js/localization/messages/ko.json index cf9d06164045..b6c7d3c0ad1b 100644 --- a/packages/devextreme/js/localization/messages/ko.json +++ b/packages/devextreme/js/localization/messages/ko.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "여기에 데이터 필드를 놓으세요", "dxPivotGrid-rowFieldArea": "여기에 행 필드를 놓으세요", "dxPivotGrid-filterFieldArea": "여기에 필터 필드를 놓으세요", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "{0}부터 {1}까지", "dxScheduler-ariaLabel": "스케줄러. {0} 보기: {1}, 일정 {2}개", diff --git a/packages/devextreme/js/localization/messages/lt.json b/packages/devextreme/js/localization/messages/lt.json index 3c8e76cb9281..3e22b1d98c44 100644 --- a/packages/devextreme/js/localization/messages/lt.json +++ b/packages/devextreme/js/localization/messages/lt.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Vilkite duomenų laukus čia", "dxPivotGrid-rowFieldArea": "Vilkite eilučių laukus čia", "dxPivotGrid-filterFieldArea": "Vilkite filtrų laukus čia", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "nuo {0} iki {1}", "dxScheduler-ariaLabel": "Planuotuvas. {0} vaizdas: {1} su {2} įvykių", diff --git a/packages/devextreme/js/localization/messages/lv.json b/packages/devextreme/js/localization/messages/lv.json index 0d440c827f0d..ca52ca02489c 100644 --- a/packages/devextreme/js/localization/messages/lv.json +++ b/packages/devextreme/js/localization/messages/lv.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Velciet datu laukus šeit", "dxPivotGrid-rowFieldArea": "Velciet rindu laukus šeit", "dxPivotGrid-filterFieldArea": "Velciet filtra laukus šeit", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "no {0} līdz {1}", "dxScheduler-ariaLabel": "Plānotājs. {0} skats: {1} ar {2} apmeklējumiem", diff --git a/packages/devextreme/js/localization/messages/nb.json b/packages/devextreme/js/localization/messages/nb.json index 0c547e60b574..8059316faff5 100644 --- a/packages/devextreme/js/localization/messages/nb.json +++ b/packages/devextreme/js/localization/messages/nb.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Slipp datafelter her", "dxPivotGrid-rowFieldArea": "Slipp radfelter her", "dxPivotGrid-filterFieldArea": "Slipp filterfelter her", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "fra {0} til {1}", "dxScheduler-ariaLabel": "Planlegger. {0}-visning: {1} med {2} avtaler", diff --git a/packages/devextreme/js/localization/messages/nl.json b/packages/devextreme/js/localization/messages/nl.json index 4a7387378b25..19b577b2f8fc 100644 --- a/packages/devextreme/js/localization/messages/nl.json +++ b/packages/devextreme/js/localization/messages/nl.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Sleep gegevensvelden hier", "dxPivotGrid-rowFieldArea": "Sleep rijvelden hier", "dxPivotGrid-filterFieldArea": "Sleep filtervelden hier", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "van {0} tot {1}", "dxScheduler-ariaLabel": "Planner. {0} weergave: {1} met {2} afspraken", diff --git a/packages/devextreme/js/localization/messages/pl.json b/packages/devextreme/js/localization/messages/pl.json index 91610788ae6b..606db7fd3436 100644 --- a/packages/devextreme/js/localization/messages/pl.json +++ b/packages/devextreme/js/localization/messages/pl.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Przeciągnij pola danych tutaj", "dxPivotGrid-rowFieldArea": "Przeciągnij pola wiersza/-y tutaj", "dxPivotGrid-filterFieldArea": "Przeciągnij pola filtra tutaj", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "od {0} do {1}", "dxScheduler-ariaLabel": "Harmonogram. Widok {0}: {1}, liczba spotkań: {2}", diff --git a/packages/devextreme/js/localization/messages/pt-BR.json b/packages/devextreme/js/localization/messages/pt-BR.json index df9a1caec94b..187301ce3c46 100644 --- a/packages/devextreme/js/localization/messages/pt-BR.json +++ b/packages/devextreme/js/localization/messages/pt-BR.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Arraste os campos de dados até aqui", "dxPivotGrid-rowFieldArea": "Arraste os campos de linha até aqui", "dxPivotGrid-filterFieldArea": "Arraste os campos de filtro até aqui", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "de {0} a {1}", "dxScheduler-ariaLabel": "Agendador. Visualização {0}: {1} com {2} compromissos", diff --git a/packages/devextreme/js/localization/messages/pt-PT.json b/packages/devextreme/js/localization/messages/pt-PT.json index 8ede950af7c7..c65b214e866b 100644 --- a/packages/devextreme/js/localization/messages/pt-PT.json +++ b/packages/devextreme/js/localization/messages/pt-PT.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Arraste os campos de dados até aqui", "dxPivotGrid-rowFieldArea": "Arraste os campos de linha até aqui", "dxPivotGrid-filterFieldArea": "Arraste os campos de filtro até aqui", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "de {0} a {1}", "dxScheduler-ariaLabel": "Agendador. Visualização {0}: {1} com {2} compromissos", diff --git a/packages/devextreme/js/localization/messages/pt.json b/packages/devextreme/js/localization/messages/pt.json index 5637d420d6f3..c2d4c9acd648 100644 --- a/packages/devextreme/js/localization/messages/pt.json +++ b/packages/devextreme/js/localization/messages/pt.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Arraste os campos de dados até aqui", "dxPivotGrid-rowFieldArea": "Arraste os campos de linha até aqui", "dxPivotGrid-filterFieldArea": "Arraste os campos de filtro até aqui", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "de {0} a {1}", "dxScheduler-ariaLabel": "Agendador. Visualização {0}: {1} com {2} compromissos", diff --git a/packages/devextreme/js/localization/messages/ro.json b/packages/devextreme/js/localization/messages/ro.json index 2699cfbb2199..5952a344d34f 100644 --- a/packages/devextreme/js/localization/messages/ro.json +++ b/packages/devextreme/js/localization/messages/ro.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Plasați câmpurile de date aici", "dxPivotGrid-rowFieldArea": "Plasați câmpurile rândului aici", "dxPivotGrid-filterFieldArea": "Plasați câmpurile de filtrare aici", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "de la {0} până la {1}", "dxScheduler-ariaLabel": "Planificator. Vedere {0}: {1} cu {2} programări", diff --git a/packages/devextreme/js/localization/messages/ru.json b/packages/devextreme/js/localization/messages/ru.json index d8fc74d72b0a..cf99f090ca53 100644 --- a/packages/devextreme/js/localization/messages/ru.json +++ b/packages/devextreme/js/localization/messages/ru.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Перетащите поля данных cюда", "dxPivotGrid-rowFieldArea": "Перетащите поля строк cюда", "dxPivotGrid-filterFieldArea": "Перетащите поля фильтров cюда", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "с {0} по {1}", "dxScheduler-ariaLabel": "Планировщик. Вид {0}: {1}, записей: {2}", diff --git a/packages/devextreme/js/localization/messages/sl.json b/packages/devextreme/js/localization/messages/sl.json index 334073c40a76..642b37fe61a9 100644 --- a/packages/devextreme/js/localization/messages/sl.json +++ b/packages/devextreme/js/localization/messages/sl.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Povleci podatke tukaj", "dxPivotGrid-rowFieldArea": "Povleci vrstice tukaj", "dxPivotGrid-filterFieldArea": "Povleci filtre tukaj", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "od {0} do {1}", "dxScheduler-ariaLabel": "Načrtovalnik. Pogled {0}: {1} z {2} dogodki", diff --git a/packages/devextreme/js/localization/messages/sv.json b/packages/devextreme/js/localization/messages/sv.json index 2045b9878b15..bf5bcace26aa 100644 --- a/packages/devextreme/js/localization/messages/sv.json +++ b/packages/devextreme/js/localization/messages/sv.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Släpp datafält här", "dxPivotGrid-rowFieldArea": "Släpp radfält här", "dxPivotGrid-filterFieldArea": "Släpp filterfält här", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "från {0} till {1}", "dxScheduler-ariaLabel": "Schemaläggare. {0}-vy: {1} med {2} bokningar", diff --git a/packages/devextreme/js/localization/messages/tr.json b/packages/devextreme/js/localization/messages/tr.json index bcb5f6d3f6b2..be576db493a4 100644 --- a/packages/devextreme/js/localization/messages/tr.json +++ b/packages/devextreme/js/localization/messages/tr.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Veri Alanlarını Buraya Bırak", "dxPivotGrid-rowFieldArea": "Satır Alanlarını Buraya Bırak", "dxPivotGrid-filterFieldArea": "Filtre Alanlarını Buraya Bırak", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "{0} - {1}", "dxScheduler-ariaLabel": "Zamanlayıcı. {0} görünümü: {1}, {2} randevu", diff --git a/packages/devextreme/js/localization/messages/uk.json b/packages/devextreme/js/localization/messages/uk.json index dc1d48262688..27af6ea144aa 100644 --- a/packages/devextreme/js/localization/messages/uk.json +++ b/packages/devextreme/js/localization/messages/uk.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Перетягніть поля даних сюди", "dxPivotGrid-rowFieldArea": "Перетягніть поля рядків сюди", "dxPivotGrid-filterFieldArea": "Перетягніть поля фільтрації сюди", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "з {0} по {1}", "dxScheduler-ariaLabel": "Планувальник. Вид {0}: {1}, подій: {2}", diff --git a/packages/devextreme/js/localization/messages/vi.json b/packages/devextreme/js/localization/messages/vi.json index 82168e2b3296..aa8e4dac9760 100644 --- a/packages/devextreme/js/localization/messages/vi.json +++ b/packages/devextreme/js/localization/messages/vi.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "Thả các trường dữ liệu vào đây", "dxPivotGrid-rowFieldArea": "Thả các trường của hàng vào đây", "dxPivotGrid-filterFieldArea": "Thả bộ lọc các trường vào đây", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "từ {0} đến {1}", "dxScheduler-ariaLabel": "Lịch biểu. Chế độ xem {0}: {1} với {2} cuộc hẹn", diff --git a/packages/devextreme/js/localization/messages/zh-CN.json b/packages/devextreme/js/localization/messages/zh-CN.json index a60231563edf..9744677d9377 100644 --- a/packages/devextreme/js/localization/messages/zh-CN.json +++ b/packages/devextreme/js/localization/messages/zh-CN.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "将数据拖动到此处", "dxPivotGrid-rowFieldArea": "将行字段拖到此处", "dxPivotGrid-filterFieldArea": "拖动筛选字段到此处", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "从 {0} 到 {1}", "dxScheduler-ariaLabel": "日程表。{0} 视图:{1},共 {2} 个日程", diff --git a/packages/devextreme/js/localization/messages/zh-Hans.json b/packages/devextreme/js/localization/messages/zh-Hans.json index 6050b2769248..78df5e0e447f 100644 --- a/packages/devextreme/js/localization/messages/zh-Hans.json +++ b/packages/devextreme/js/localization/messages/zh-Hans.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "将数据拖动到此处", "dxPivotGrid-rowFieldArea": "将行字段拖到此处", "dxPivotGrid-filterFieldArea": "拖动筛选字段到此处", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "从 {0} 到 {1}", "dxScheduler-ariaLabel": "日程表。{0} 视图:{1},共 {2} 个日程", diff --git a/packages/devextreme/js/localization/messages/zh-tw.json b/packages/devextreme/js/localization/messages/zh-tw.json index 2ffba427171f..0fd718756c76 100644 --- a/packages/devextreme/js/localization/messages/zh-tw.json +++ b/packages/devextreme/js/localization/messages/zh-tw.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "將資料拖動到此處", "dxPivotGrid-rowFieldArea": "將列欄位拖曳至此", "dxPivotGrid-filterFieldArea": "拖動篩選欄位到此處", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "從 {0} 到 {1}", "dxScheduler-ariaLabel": "日程表。{0} 視圖:{1},共 {2} 個日程", diff --git a/packages/devextreme/js/localization/messages/zh.json b/packages/devextreme/js/localization/messages/zh.json index 6885efa6b29c..63bed7ec40b7 100644 --- a/packages/devextreme/js/localization/messages/zh.json +++ b/packages/devextreme/js/localization/messages/zh.json @@ -284,6 +284,11 @@ "dxPivotGrid-dataFieldArea": "将数据拖动到此处", "dxPivotGrid-rowFieldArea": "将行字段拖到此处", "dxPivotGrid-filterFieldArea": "拖动筛选字段到此处", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "从 {0} 到 {1}", "dxScheduler-ariaLabel": "日程表。{0} 视图:{1},共 {2} 个日程", diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js index a6123d08ad36..509f11554632 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js @@ -239,7 +239,7 @@ QUnit.module('PivotGrid accessibility markup', { assert.equal($outerTable.attr('role'), 'presentation'); }); - QUnit.test('Field-area tables have role="group" and localized aria-label', function(assert) { + QUnit.test('Populated field-area tables are exposed as a labelled menubar', function(assert) { if(!windowUtils.hasWindow()) { assert.expect(0); return; @@ -261,8 +261,7 @@ QUnit.module('PivotGrid accessibility markup', { const expectedLabels = { row: 'Row Fields', column: 'Column Fields', - data: 'Data Fields', - filter: 'Filter Fields' + data: 'Data Fields' }; Object.keys(expectedLabels).forEach((area) => { @@ -270,9 +269,19 @@ QUnit.module('PivotGrid accessibility markup', { .find(`.dx-area-fields[group="${area}"] > table`); assert.strictEqual($table.length, 1, `${area} field table exists`); - assert.strictEqual($table.attr('role'), 'group'); - assert.strictEqual($table.attr('aria-label'), expectedLabels[area]); + assert.strictEqual($table.attr('role'), 'menubar', `${area} field table is a menubar`); + assert.strictEqual($table.attr('aria-label'), expectedLabels[area], `${area} menubar has localized label`); + assert.ok($table.attr('aria-description'), `${area} menubar has an interaction description`); }); + + // The filter area has no fields in this data source; a menubar without + // menu items is invalid ARIA, so its table stays presentational. + const $filterTable = pivotGrid.$element() + .find('.dx-area-fields[group="filter"] > table'); + + assert.strictEqual($filterTable.attr('role'), 'presentation', 'empty filter area table is presentational'); + assert.strictEqual($filterTable.attr('aria-label'), undefined, 'empty filter area table has no aria-label'); + assert.strictEqual($filterTable.attr('aria-description'), undefined, 'empty filter area table has no aria-description'); }); QUnit.test('Scrollable containers have no tabindex', function(assert) { @@ -330,6 +339,49 @@ QUnit.module('PivotGrid accessibility markup', { }); }); + QUnit.test('Data cells are described by their row and column header cells', function(assert) { + if(!windowUtils.hasWindow()) { + assert.expect(0); + return; + } + + const pivotGrid = createPivotGrid({ + width: 600, height: 400, + dataSource: createExpandableDataSource() + }); + this.clock.tick(10); + + const $columnArea = pivotGrid.$element().find('.dx-pivotgrid-horizontal-headers'); + const $rowsArea = pivotGrid.$element().find('.dx-pivotgrid-vertical-headers'); + const $dataArea = pivotGrid.$element().find('.dx-pivotgrid-area-data'); + + $dataArea.find('td').each((_, dataCell) => { + const describedBy = dataCell.getAttribute('aria-describedby'); + + assert.ok(describedBy, 'data cell has aria-describedby'); + + describedBy.split(' ').forEach((id) => { + const header = document.getElementById(id); + + assert.ok(header, `referenced element #${id} exists`); + assert.ok( + $columnArea.find(header).length || $rowsArea.find(header).length, + 'referenced element is a row or column header cell' + ); + }); + }); + + const firstDataCell = $dataArea.find('td').get(0); + const describedTexts = firstDataCell.getAttribute('aria-describedby') + .split(' ') + .map((id) => document.getElementById(id).textContent.trim()); + const firstRowHeaderText = $rowsArea.find('td').first().text().trim(); + const firstColumnHeaderText = $columnArea.find('td').first().text().trim(); + + assert.ok(describedTexts.includes(firstRowHeaderText), 'description includes the row header caption'); + assert.ok(describedTexts.includes(firstColumnHeaderText), 'description includes the column header caption'); + }); + QUnit.test('Row header and data cells have aria-rowindex along shared row axis', function(assert) { if(!windowUtils.hasWindow()) { assert.expect(0); |