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();
|
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;
|
component.disabled = false;
|
||||||
fixture.detectChanges();
|
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');
|
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', () => {
|
it('should focus element', () => {
|
||||||
expect(document.activeElement.classList.contains('adf-datatable-row')).toBe(false);
|
expect(document.activeElement.classList.contains('adf-datatable-row')).toBe(false);
|
||||||
component.disabled = false;
|
component.disabled = false;
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ export class DataTableRowComponent implements FocusableOption {
|
|||||||
|
|
||||||
@Input() disabled = true;
|
@Input() disabled = true;
|
||||||
|
|
||||||
|
@Input() active = false;
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
select: EventEmitter<any> = new EventEmitter<any>();
|
select: EventEmitter<any> = new EventEmitter<any>();
|
||||||
|
|
||||||
@@ -65,7 +67,10 @@ export class DataTableRowComponent implements FocusableOption {
|
|||||||
|
|
||||||
@HostBinding('attr.tabindex')
|
@HostBinding('attr.tabindex')
|
||||||
get tabindex(): number | null {
|
get tabindex(): number | null {
|
||||||
return this.disabled ? null : 0;
|
if (this.disabled) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return this.active ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@HostListener('keydown.space', ['$event'])
|
@HostListener('keydown.space', ['$event'])
|
||||||
|
|||||||
@@ -262,7 +262,9 @@
|
|||||||
[class.adf-datatable-row__dragging]="isDraggingRow"
|
[class.adf-datatable-row__dragging]="isDraggingRow"
|
||||||
[attr.data-automation-id]="'datatable-row-' + idx"
|
[attr.data-automation-id]="'datatable-row-' + idx"
|
||||||
(contextmenu)="markRowAsContextMenuSource(row)"
|
(contextmenu)="markRowAsContextMenuSource(row)"
|
||||||
[disabled]="!(enableDragRows || multiselect)"
|
(focus)="onRowFocus(idx)"
|
||||||
|
[disabled]="!isRowKeyboardNavigable()"
|
||||||
|
[active]="isRowActive(idx)"
|
||||||
[attr.aria-description]="
|
[attr.aria-description]="
|
||||||
(multiselect ? ('ADF-DATATABLE.ACCESSIBILITY.ROW_SELECTION' | translate) : '') +
|
(multiselect ? ('ADF-DATATABLE.ACCESSIBILITY.ROW_SELECTION' | translate) : '') +
|
||||||
(multiselect && enableDragRows ? '. ' : '') +
|
(multiselect && enableDragRows ? '. ' : '') +
|
||||||
|
|||||||
@@ -1881,10 +1881,10 @@ describe('Accessibility', () => {
|
|||||||
|
|
||||||
const getBodyRows = (): DebugElement[] => testingUtils.getAllByCSS(rowSelector);
|
const getBodyRows = (): DebugElement[] => testingUtils.getAllByCSS(rowSelector);
|
||||||
|
|
||||||
const expectRowsTabindex = (expected: string | null): void => {
|
const expectRowsTabindex = (expected: (string | null)[]): void => {
|
||||||
const rowElements = getBodyRows();
|
const rowElements = getBodyRows();
|
||||||
expect(rowElements.length).toBeGreaterThan(0);
|
expect(rowElements.length).toBe(expected.length);
|
||||||
expect(rowElements.every((row) => row.nativeElement.getAttribute('tabindex') === expected)).toBeTrue();
|
expect(rowElements.map((row) => row.nativeElement.getAttribute('tabindex'))).toEqual(expected);
|
||||||
};
|
};
|
||||||
|
|
||||||
const activateRow = (rowIndex: number): void => {
|
const activateRow = (rowIndex: number): void => {
|
||||||
@@ -1907,24 +1907,42 @@ describe('Accessibility', () => {
|
|||||||
dataTable.data = new ObjectDataTableAdapter([], [new ObjectDataColumn({ key: 'name' })]);
|
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();
|
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;
|
dataTable.multiselect = true;
|
||||||
setRows();
|
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;
|
dataTable.enableDragRows = true;
|
||||||
setRows();
|
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', () => {
|
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');
|
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', () => {
|
describe('Row cells focus management', () => {
|
||||||
|
|||||||
@@ -347,6 +347,10 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
|
|||||||
|
|
||||||
private readonly destroyRef = inject(DestroyRef);
|
private readonly destroyRef = inject(DestroyRef);
|
||||||
|
|
||||||
|
private get rowsOffset(): number {
|
||||||
|
return this.isHeaderVisible() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
@HostListener('keyup', ['$event'])
|
@HostListener('keyup', ['$event'])
|
||||||
onKeydown(event: KeyboardEvent): void {
|
onKeydown(event: KeyboardEvent): void {
|
||||||
if (event.shiftKey && this.enableDragRows) {
|
if (event.shiftKey && this.enableDragRows) {
|
||||||
@@ -640,7 +644,7 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (row) {
|
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);
|
this.keyManager.setActiveItem(rowIndex);
|
||||||
|
|
||||||
const dataRowEvent = new DataRowEvent(row, mouseEvent, this);
|
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';
|
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 {
|
getRowStyle(row: DataRow): string {
|
||||||
row.cssClass = row.cssClass ? row.cssClass : '';
|
row.cssClass = row.cssClass ? row.cssClass : '';
|
||||||
this.rowStyleClass = this.rowStyleClass ? this.rowStyleClass : '';
|
this.rowStyleClass = this.rowStyleClass ? this.rowStyleClass : '';
|
||||||
|
|||||||
Reference in New Issue
Block a user