Skip to content
Draft
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
@@ -1,12 +1,11 @@
@if (buttonVisible$ | async) {
<div>
<a href="javascript:void(0);"
role="menuitem"
<button type="button"
class="ds-context-help-toggle-button"
(click)="onClick()"
[attr.aria-label]="'nav.context-help-toggle' | translate"
[title]="'nav.context-help-toggle' | translate"
>
[title]="'nav.context-help-toggle' | translate">
<i class="fas fa-lg fa-fw fa-question-circle ds-context-help-toggle"></i>
</a>
</button>
</div>
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
.ds-context-help-toggle-button {
background: none;
border: 0;
padding: 0;
cursor: pointer;
}

.ds-context-help-toggle {
color: var(--ds-header-icon-color);
background-color: var(--ds-header-bg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,17 @@ describe('ContextHelpToggleComponent', () => {
});

it('clicking the button should toggle context help icon visibility', fakeAsync(() => {
fixture.debugElement.query(By.css('a')).nativeElement.click();
fixture.debugElement.query(By.css('button')).nativeElement.click();
tick();
expect(contextHelpService.toggleIcons).toHaveBeenCalled();
}));

it('the toggle should be a real <button> without an orphan role="menuitem"', () => {
const toggle = fixture.debugElement.query(By.css('button')).nativeElement;
expect(toggle.tagName).toBe('BUTTON');
expect(toggle.getAttribute('role')).toBeNull();
expect(toggle.getAttribute('type')).toBe('button');
});
});

});
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
(mouseenter)="onMouseEnter($event)"
(mouseleave)="onMouseLeave($event)"
data-test="navbar-section-wrapper">
<a href="javascript:void(0);" routerLinkActive="active"
<button type="button"
role="menuitem"
(keyup.enter)="toggleSection($event)"
(keyup.space)="toggleSection($event)"
Expand All @@ -21,7 +21,7 @@
*ngComponentOutlet="(sectionMap$ | async).get(section.id).component; injector: (sectionMap$ | async).get(section.id).injector;"></ng-container>
</span>
<i class="fas fa-caret-down fa-xs toggle-menu-icon" aria-hidden="true"></i>
</a>
</button>
@if ((active$ | async).valueOf() === true) {
<div (click)="deactivateSection($event)"
[id]="expandableNavbarSectionId()"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
position: relative; // align dropdown menu with respect to this element
}

// The toggler is a <button> so user agents do not apply native button chrome
button.ds-menu-toggler-wrapper {
background: none;
border: 0;
padding: 0;
color: inherit;
font: inherit;
cursor: pointer;
}

.dropdown-menu {
overflow: hidden;
min-width: 100%;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ describe('ExpandableNavbarSectionComponent', () => {
fixture.detectChanges();
});

describe('toggler element', () => {
it('should be a real <button> rather than an anchor with href="javascript:void(0)"', () => {
const toggler = fixture.debugElement.query(By.css('[data-test="navbar-section-toggler"]')).nativeElement;
expect(toggler.tagName).toBe('BUTTON');
expect(toggler.getAttribute('type')).toBe('button');
expect(toggler.getAttribute('role')).toBe('menuitem');
});
});

describe('when the mouse enters the section header (while inactive)', () => {
beforeEach(() => {
spyOn(component, 'onMouseEnter').and.callThrough();
Expand Down
5 changes: 2 additions & 3 deletions src/app/shared/auth-nav-menu/auth-nav-menu.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@
<div ngbDropdown #loginDrop="ngbDropdown" display="dynamic" placement="bottom-right" class="d-inline-block" @fadeInOut>
<button class="dropdownLogin btn btn-link px-0" [attr.aria-label]="'nav.login' |translate"
(click)="$event.preventDefault()" [attr.data-test]="'login-menu' | dsBrowserOnly"
role="button"
tabindex="0"
aria-haspopup="menu"
type="button"
aria-haspopup="dialog"
aria-controls="loginDropdownMenu"
[attr.aria-expanded]="loginDrop.isOpen()"
ngbDropdownToggle>
Expand Down
6 changes: 6 additions & 0 deletions src/app/shared/auth-nav-menu/auth-nav-menu.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,12 @@ describe('AuthNavMenuComponent', () => {
const loginDropdownMenu = deNavMenuItem.query(By.css('div#loginDropdownMenu'));
expect(loginDropdownMenu.nativeElement).toBeDefined();
});

it('the login toggle should declare aria-haspopup="dialog" so it matches the role of the popup it controls', () => {
const loginToggle = deNavMenuItem.query(By.css('button.dropdownLogin'));
expect(loginToggle.nativeElement.getAttribute('aria-haspopup')).toBe('dialog');
expect(loginToggle.nativeElement.getAttribute('aria-controls')).toBe('loginDropdownMenu');
});
});

describe('when user is authenticated', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
[ngbTooltip]="itemModel.text | translate">
@if (!section.model.disabled) {
<a class="btn btn-dark btn-sm"
role="menuitem"
[routerLink]="itemModel.link">
<i class="fas fa-{{section.icon}} fa-fw" aria-hidden="true"></i>
<span class="sr-only">{{itemModel.text | translate}}</span>
</a>
}
@if (section.model.disabled) {
<button class="btn btn-dark btn-sm" [dsBtnDisabled]="true">
<button class="btn btn-dark btn-sm" role="menuitem" [dsBtnDisabled]="true">
<i class="fas fa-{{section.icon}} fa-fw" aria-hidden="true"></i>
<span class="sr-only">{{itemModel.text | translate}}</span>
</button>
Expand All @@ -20,7 +21,7 @@
@if (canActivate) {
<div class="dso-button-menu mb-1"
[ngbTooltip]="itemModel.text | translate">
<button class="btn btn-dark btn-sm" [dsBtnDisabled]="section.model.disabled"
<button class="btn btn-dark btn-sm" role="menuitem" [dsBtnDisabled]="section.model.disabled"
(click)="activate($event)">
<i class="fas fa-{{section.icon}} fa-fw" aria-hidden="true"></i>
<span class="sr-only">{{itemModel.text | translate}}</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ describe('DsoEditMenuSectionComponent', () => {
expect(button.nativeElement.innerHTML).toContain('fa-' + iconString);
});

it('should declare role="menuitem" so the parent menubar satisfies aria-required-children', () => {
const button = fixture.debugElement.query(By.css('.btn-dark'));
expect(button.nativeElement.getAttribute('role')).toBe('menuitem');
});

describe('when the section model in a disabled link or text', () => {
it('should show just the button', () => {
const textButton = fixture.debugElement.query(By.css('div a'));
Expand Down
Loading