mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-09 18:03:21 +00:00
[ACS-12582] [ADW] Document list container is not accessible via keyboard navigation for file selection (#12210)
This commit is contained in:
+15
-1
@@ -87,12 +87,26 @@ describe('DataTableRowComponent', () => {
|
||||
expect(fixture.debugElement.nativeElement.getAttribute('tabindex')).toBeNull();
|
||||
});
|
||||
|
||||
it('should not set tabindex when row is disabled', () => {
|
||||
it('should set tabindex as focusable only with the arrow keys when row is enabled but not active', () => {
|
||||
component.disabled = false;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.nativeElement.getAttribute('tabindex')).toBe('-1');
|
||||
});
|
||||
|
||||
it('should set tabindex as focusable with the Tab key when row is enabled and active', () => {
|
||||
component.disabled = false;
|
||||
component.active = true;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.nativeElement.getAttribute('tabindex')).toBe('0');
|
||||
});
|
||||
|
||||
it('should not set tabindex when row is disabled even if it is active', () => {
|
||||
component.disabled = true;
|
||||
component.active = true;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.nativeElement.getAttribute('tabindex')).toBeNull();
|
||||
});
|
||||
|
||||
it('should focus element', () => {
|
||||
expect(document.activeElement.classList.contains('adf-datatable-row')).toBe(false);
|
||||
component.disabled = false;
|
||||
|
||||
@@ -35,6 +35,8 @@ export class DataTableRowComponent implements FocusableOption {
|
||||
|
||||
@Input() disabled = true;
|
||||
|
||||
@Input() active = false;
|
||||
|
||||
@Output()
|
||||
select: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
@@ -65,7 +67,10 @@ export class DataTableRowComponent implements FocusableOption {
|
||||
|
||||
@HostBinding('attr.tabindex')
|
||||
get tabindex(): number | null {
|
||||
return this.disabled ? null : 0;
|
||||
if (this.disabled) {
|
||||
return null;
|
||||
}
|
||||
return this.active ? 0 : -1;
|
||||
}
|
||||
|
||||
@HostListener('keydown.space', ['$event'])
|
||||
|
||||
@@ -262,7 +262,9 @@
|
||||
[class.adf-datatable-row__dragging]="isDraggingRow"
|
||||
[attr.data-automation-id]="'datatable-row-' + idx"
|
||||
(contextmenu)="markRowAsContextMenuSource(row)"
|
||||
[disabled]="!(enableDragRows || multiselect)"
|
||||
(focus)="onRowFocus(idx)"
|
||||
[disabled]="!isRowKeyboardNavigable()"
|
||||
[active]="isRowActive(idx)"
|
||||
[attr.aria-description]="
|
||||
(multiselect ? ('ADF-DATATABLE.ACCESSIBILITY.ROW_SELECTION' | translate) : '') +
|
||||
(multiselect && enableDragRows ? '. ' : '') +
|
||||
|
||||
@@ -1881,10 +1881,10 @@ describe('Accessibility', () => {
|
||||
|
||||
const getBodyRows = (): DebugElement[] => testingUtils.getAllByCSS(rowSelector);
|
||||
|
||||
const expectRowsTabindex = (expected: string | null): void => {
|
||||
const expectRowsTabindex = (expected: (string | null)[]): void => {
|
||||
const rowElements = getBodyRows();
|
||||
expect(rowElements.length).toBeGreaterThan(0);
|
||||
expect(rowElements.every((row) => row.nativeElement.getAttribute('tabindex') === expected)).toBeTrue();
|
||||
expect(rowElements.length).toBe(expected.length);
|
||||
expect(rowElements.map((row) => row.nativeElement.getAttribute('tabindex'))).toEqual(expected);
|
||||
};
|
||||
|
||||
const activateRow = (rowIndex: number): void => {
|
||||
@@ -1907,24 +1907,42 @@ describe('Accessibility', () => {
|
||||
dataTable.data = new ObjectDataTableAdapter([], [new ObjectDataColumn({ key: 'name' })]);
|
||||
});
|
||||
|
||||
it('should set tabindex to null (disabled === true) on datatable-body rows when neither multiselect nor enableDragRows is enabled', () => {
|
||||
it('should set tabindex to null (disabled === true) on datatable-body rows when rows cannot be selected nor dragged', () => {
|
||||
dataTable.selectionMode = 'none';
|
||||
setRows();
|
||||
|
||||
expectRowsTabindex(null);
|
||||
expectRowsTabindex([null, null]);
|
||||
});
|
||||
|
||||
it('should set tabindex to 0 (disabled === false) on datatable-body rows when multiselect is enabled', () => {
|
||||
it('should make only the first row reachable with the Tab key when rows are selectable', () => {
|
||||
setRows();
|
||||
|
||||
expectRowsTabindex(['0', '-1']);
|
||||
});
|
||||
|
||||
it('should make only the first row reachable with the Tab key when multiselect is enabled', () => {
|
||||
dataTable.multiselect = true;
|
||||
setRows();
|
||||
|
||||
expectRowsTabindex('0');
|
||||
expectRowsTabindex(['0', '-1']);
|
||||
});
|
||||
|
||||
it('should set tabindex to 0 (disabled === false) on datatable-body rows when enableDragRows is enabled', () => {
|
||||
it('should make only the first row reachable with the Tab key when enableDragRows is enabled', () => {
|
||||
dataTable.enableDragRows = true;
|
||||
setRows();
|
||||
|
||||
expectRowsTabindex('0');
|
||||
expectRowsTabindex(['0', '-1']);
|
||||
});
|
||||
|
||||
it('should move the tabindex to the active row', () => {
|
||||
setRows();
|
||||
dataTable.ngAfterViewInit();
|
||||
|
||||
activateRow(1);
|
||||
testingUtils.setDebugElement(fixture.debugElement);
|
||||
fixture.detectChanges();
|
||||
|
||||
expectRowsTabindex(['-1', '0']);
|
||||
});
|
||||
|
||||
it('should focus next row on ArrowDown event', () => {
|
||||
@@ -1954,6 +1972,17 @@ describe('Accessibility', () => {
|
||||
|
||||
expect(document.activeElement?.getAttribute('data-automation-id')).toBe('datatable-row-0');
|
||||
});
|
||||
|
||||
it('should navigate between rows with the arrow keys in single selection mode', () => {
|
||||
dataTable.selectionMode = 'single';
|
||||
setRows();
|
||||
dataTable.ngAfterViewInit();
|
||||
|
||||
activateRow(1);
|
||||
dispatchKeyUp(event);
|
||||
|
||||
expect(document.activeElement?.getAttribute('data-automation-id')).toBe('datatable-row-0');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Row cells focus management', () => {
|
||||
|
||||
@@ -347,6 +347,10 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
|
||||
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
private get rowsOffset(): number {
|
||||
return this.isHeaderVisible() ? 1 : 0;
|
||||
}
|
||||
|
||||
@HostListener('keyup', ['$event'])
|
||||
onKeydown(event: KeyboardEvent): void {
|
||||
if (event.shiftKey && this.enableDragRows) {
|
||||
@@ -640,7 +644,7 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
|
||||
}
|
||||
|
||||
if (row) {
|
||||
const rowIndex = this.data.getRows().indexOf(row) + (this.isHeaderVisible() ? 1 : 0);
|
||||
const rowIndex = this.data.getRows().indexOf(row) + this.rowsOffset;
|
||||
this.keyManager.setActiveItem(rowIndex);
|
||||
|
||||
const dataRowEvent = new DataRowEvent(row, mouseEvent, this);
|
||||
@@ -923,6 +927,19 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
|
||||
return this.selectionMode && this.selectionMode.toLowerCase() === 'multiple';
|
||||
}
|
||||
|
||||
protected isRowKeyboardNavigable(): boolean {
|
||||
return this.enableDragRows || this.multiselect || this.isSingleSelectionMode() || this.isMultiSelectionMode();
|
||||
}
|
||||
|
||||
protected isRowActive(rowIndex: number): boolean {
|
||||
const activeItemIndex = this.keyManager?.activeItemIndex ?? -1;
|
||||
return activeItemIndex < this.rowsOffset ? rowIndex === 0 : activeItemIndex === rowIndex + this.rowsOffset;
|
||||
}
|
||||
|
||||
protected onRowFocus(rowIndex: number): void {
|
||||
this.keyManager?.updateActiveItem(rowIndex + this.rowsOffset);
|
||||
}
|
||||
|
||||
getRowStyle(row: DataRow): string {
|
||||
row.cssClass = row.cssClass ? row.cssClass : '';
|
||||
this.rowStyleClass = this.rowStyleClass ? this.rowStyleClass : '';
|
||||
|
||||
Reference in New Issue
Block a user