From d9090f0f5dfc2ee51230f0fbf5644c6afc9aa959 Mon Sep 17 00:00:00 2001 From: ivanvpetrov <110455887+ivanvpetrov@users.noreply.github.com> Date: Thu, 3 Oct 2024 11:18:25 +0300 Subject: [PATCH] Edit and Close buttons now tab indexed properly so that Space/Enter works on them (#14865) * fix(query-builder): fix edit/close buttons now tabindexed properly --- .../grid/grid-filtering-advanced.spec.ts | 36 +++++++++- .../query-builder.component.html | 6 +- .../src/lib/test-utils/grid-functions.spec.ts | 69 +++++++++++++++++++ 3 files changed, 108 insertions(+), 3 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-advanced.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-advanced.spec.ts index 5dd2a4e8fe1..6fe40fae4c4 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-advanced.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-advanced.spec.ts @@ -2150,7 +2150,7 @@ describe('IgxGrid - Advanced Filtering #grid - ', () => { tick(50); fix.detectChanges(); expect(editIcon.getAttribute('aria-hidden')).toBe('true'); - expect(editIcon.getAttribute('tabIndex')).toBeFalsy(); + expect(editIcon.getAttribute('tabIndex')).toBe('0'); })); describe('Context Menu - ', () => { @@ -3001,6 +3001,40 @@ describe('IgxGrid - Advanced Filtering #grid - ', () => { verifyContextMenuVisibility(fix, false); })); + it('Should navigate with Tab/Shift+Tab through chips" "edit", "cancel" and "adding" buttons, fields of a condition in edit mode.', fakeAsync(() => { + // Apply advanced filter through API. + const tree = new FilteringExpressionsTree(FilteringLogic.Or); + tree.filteringOperands.push({ + fieldName: 'ProductName', searchVal: 'angular', condition: IgxStringFilteringOperand.instance().condition('contains'), + ignoreCase: true + }); + tree.filteringOperands.push({ + fieldName: 'ProductName', searchVal: 'script', condition: IgxStringFilteringOperand.instance().condition('contains'), + ignoreCase: true + }); + grid.advancedFilteringExpressionsTree = tree; + fix.detectChanges(); + + // Open Advanced Filtering dialog. + grid.openAdvancedFilteringDialog(); + fix.detectChanges(); + + // Press 'Enter' on the second chip and verify it is selected. + UIInteractions.triggerKeyDownEvtUponElem('Enter', GridFunctions.getAdvancedFilteringTreeExpressionChip(fix, [0])); + tick(200); + fix.detectChanges(); + + let chipActions = fix.debugElement.query(By.css('.igx-filter-tree')); + GridFunctions.verifyTabbableElements(chipActions); + + // Press 'Enter' on the edit button. + UIInteractions.triggerKeyDownEvtUponElem('Enter', GridFunctions.getAdvancedFilteringTreeExpressionEditIcon(fix, [0])); + fix.detectChanges(); + + chipActions = fix.debugElement.query(By.css('.igx-filter-tree')); + GridFunctions.verifyInEditTabbableElements(chipActions); + })); + }); }); diff --git a/projects/igniteui-angular/src/lib/query-builder/query-builder.component.html b/projects/igniteui-angular/src/lib/query-builder/query-builder.component.html index 713fada94e6..8173c3c97e1 100644 --- a/projects/igniteui-angular/src/lib/query-builder/query-builder.component.html +++ b/projects/igniteui-angular/src/lib/query-builder/query-builder.component.html @@ -147,16 +147,18 @@
expressionItem.hovered " > - + edit - + { + const tabElements = this.getTabbableElements(chipActions.nativeElement); + + let i = 0; + tabElements.forEach((element: HTMLElement) => { + switch (i) { + case 0: expect(element).toHaveClass('igx-filter-tree__line--or'); break; + case 1: expect(element).toHaveClass('igx-input-group__input'); break; + case 2: expect(element).toHaveClass('igx-input-group__input'); break; + case 3: expect(element).toHaveClass('igx-input-group__input'); break; + case 4: expect(element).toHaveClass('igx-icon-button'); + expect(element.innerText).toContain('check'); + break; + case 5: expect(element).toHaveClass('igx-icon-button'); + expect(element.innerText).toContain('close'); + break; + case 6: expect(element).toHaveClass('igx-chip'); break; + case 7: expect(element).toHaveClass('igx-chip__remove'); break; + } + i++; + }); + }; + + /* + * Get tabbable elements in a container element. Result is returned as node elements ordered the way they will be tabbed + */ + public static getTabbableElements(inElement: HTMLElement) { + const focusableElements = + 'a:not([disabled]), button:not([disabled]), input[type=text]:not([disabled]), [tabindex]:not([disabled]):not([tabindex="-1"])'; + + return Array.prototype.filter.call( + inElement.querySelectorAll(focusableElements), + element => { + return (element.offsetWidth > 0 || element.offsetHeight > 0); + } + ); + } } export class GridSummaryFunctions { public static getRootSummaryRow(fix): DebugElement {