Skip to content

Commit 1cc4756

Browse files
authored
Merge pull request DSpace#3270 from atmire/w2p-117544_support-for-disabled-elements-for-screen-readers-7.x
[Port dspace-7_x] support for disabled buttons for screen readers
2 parents 08bda53 + cd2f8ab commit 1cc4756

87 files changed

Lines changed: 431 additions & 190 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/app/access-control/bulk-access/bulk-access.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ <h1>{{ 'admin.access-control.bulk-access.title' | translate }}</h1>
1010
<button class="btn btn-outline-primary mr-3" (click)="reset()">
1111
{{ 'access-control-cancel' | translate }}
1212
</button>
13-
<button class="btn btn-primary" [disabled]="!canExport()" (click)="submit()">
13+
<button class="btn btn-primary" [dsBtnDisabled]="!canExport()" (click)="submit()">
1414
{{ 'access-control-execute' | translate }}
1515
</button>
1616
</div>

src/app/access-control/epeople-registry/epeople-registry.component.spec.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { RequestService } from '../../core/data/request.service';
2727
import { PaginationService } from '../../core/pagination/pagination.service';
2828
import { PaginationServiceStub } from '../../shared/testing/pagination-service.stub';
2929
import { FindListOptions } from '../../core/data/find-list-options.model';
30+
import {BtnDisabledDirective} from '../../shared/btn-disabled.directive';
3031

3132
describe('EPeopleRegistryComponent', () => {
3233
let component: EPeopleRegistryComponent;
@@ -131,7 +132,7 @@ describe('EPeopleRegistryComponent', () => {
131132
}
132133
}),
133134
],
134-
declarations: [EPeopleRegistryComponent],
135+
declarations: [EPeopleRegistryComponent, BtnDisabledDirective],
135136
providers: [
136137
{ provide: EPersonDataService, useValue: ePersonDataServiceStub },
137138
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
@@ -239,7 +240,8 @@ describe('EPeopleRegistryComponent', () => {
239240
it('should be disabled', () => {
240241
ePeopleDeleteButton = fixture.debugElement.queryAll(By.css('#epeople tr td div button.delete-button'));
241242
ePeopleDeleteButton.forEach((deleteButton: DebugElement) => {
242-
expect(deleteButton.nativeElement.disabled).toBe(true);
243+
expect(deleteButton.nativeElement.getAttribute('aria-disabled')).toBe('true');
244+
expect(deleteButton.nativeElement.classList.contains('disabled')).toBeTrue();
243245
});
244246
});
245247
});

src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ <h1 class="border-bottom pb-2">{{messagePrefix + '.edit' | translate}}</h1>
2525
</button>
2626
</div>
2727
<div *ngIf="displayResetPassword" between class="btn-group">
28-
<button class="btn btn-primary" [disabled]="!(canReset$ | async)" type="button" (click)="resetPassword()">
28+
<button class="btn btn-primary" [dsBtnDisabled]="!(canReset$ | async)" type="button" (click)="resetPassword()">
2929
<i class="fa fa-key"></i> {{'admin.access-control.epeople.actions.reset' | translate}}
3030
</button>
3131
</div>

src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import { ActivatedRoute, Router } from '@angular/router';
3535
import { RouterStub } from '../../../shared/testing/router.stub';
3636
import { ActivatedRouteStub } from '../../../shared/testing/active-router.stub';
3737
import { RouterTestingModule } from '@angular/router/testing';
38+
import {BtnDisabledDirective} from '../../../shared/btn-disabled.directive';
3839

3940
describe('EPersonFormComponent', () => {
4041
let component: EPersonFormComponent;
@@ -195,7 +196,7 @@ describe('EPersonFormComponent', () => {
195196
RouterTestingModule,
196197
TranslateModule.forRoot(),
197198
],
198-
declarations: [EPersonFormComponent],
199+
declarations: [EPersonFormComponent, BtnDisabledDirective],
199200
providers: [
200201
{ provide: EPersonDataService, useValue: ePersonDataServiceStub },
201202
{ provide: GroupDataService, useValue: groupsDataService },
@@ -481,7 +482,8 @@ describe('EPersonFormComponent', () => {
481482
// ePersonDataServiceStub.activeEPerson = eperson;
482483
spyOn(component.epersonService, 'deleteEPerson').and.returnValue(createSuccessfulRemoteDataObject$('No Content', 204));
483484
const deleteButton = fixture.debugElement.query(By.css('.delete-button'));
484-
expect(deleteButton.nativeElement.disabled).toBe(false);
485+
expect(deleteButton.nativeElement.getAttribute('aria-disabled')).toBeNull();
486+
expect(deleteButton.nativeElement.classList.contains('disabled')).toBeFalse();
485487
deleteButton.triggerEventHandler('click', null);
486488
fixture.detectChanges();
487489
expect(component.epersonService.deleteEPerson).toHaveBeenCalledWith(eperson);

src/app/access-control/group-registry/group-form/members-list/members-list.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ <h3>{{messagePrefix + '.headMembers' | translate}}</h3>
3434
<td class="align-middle">
3535
<div class="btn-group edit-field">
3636
<button (click)="deleteMemberFromGroup(eperson)"
37-
[disabled]="actionConfig.remove.disabled"
37+
[dsBtnDisabled]="actionConfig.remove.disabled"
3838
[ngClass]="['btn btn-sm', actionConfig.remove.css]"
3939
title="{{messagePrefix + '.table.edit.buttons.remove' | translate: { name: dsoNameService.getName(eperson) } }}">
4040
<i [ngClass]="actionConfig.remove.icon"></i>
@@ -114,7 +114,7 @@ <h3 id="search" class="border-bottom pb-2">
114114
<td class="align-middle">
115115
<div class="btn-group edit-field">
116116
<button (click)="addMemberToGroup(eperson)"
117-
[disabled]="actionConfig.add.disabled"
117+
[dsBtnDisabled]="actionConfig.add.disabled"
118118
[ngClass]="['btn btn-sm', actionConfig.add.css]"
119119
title="{{messagePrefix + '.table.edit.buttons.add' | translate: { name: dsoNameService.getName(eperson) } }}">
120120
<i [ngClass]="actionConfig.add.icon"></i>

src/app/access-control/group-registry/groups-registry.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ <h2 id="search" class="border-bottom pb-2">{{messagePrefix + 'search.head' | tra
6969
<i class="fas fa-edit fa-fw"></i>
7070
</button>
7171
<button *ngSwitchCase="false"
72-
[disabled]="true"
72+
[dsBtnDisabled]="true"
7373
class="btn btn-outline-primary btn-sm btn-edit"
7474
placement="left"
7575
[ngbTooltip]="'admin.access-control.epeople.table.edit.buttons.edit-disabled' | translate"

src/app/access-control/group-registry/groups-registry.component.spec.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import { FeatureID } from '../../core/data/feature-authorization/feature-id';
3434
import { NoContent } from '../../core/shared/NoContent.model';
3535
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
3636
import { DSONameServiceMock, UNDEFINED_NAME } from '../../shared/mocks/dso-name.service.mock';
37+
import {BtnDisabledDirective} from '../../shared/btn-disabled.directive';
3738

3839
describe('GroupsRegistryComponent', () => {
3940
let component: GroupsRegistryComponent;
@@ -171,7 +172,7 @@ describe('GroupsRegistryComponent', () => {
171172
}
172173
}),
173174
],
174-
declarations: [GroupsRegistryComponent],
175+
declarations: [GroupsRegistryComponent, BtnDisabledDirective],
175176
providers: [GroupsRegistryComponent,
176177
{ provide: DSONameService, useValue: new DSONameServiceMock() },
177178
{ provide: EPersonDataService, useValue: ePersonDataServiceStub },
@@ -231,7 +232,8 @@ describe('GroupsRegistryComponent', () => {
231232
const editButtonsFound = fixture.debugElement.queryAll(By.css('#groups tr td:nth-child(5) button.btn-edit'));
232233
expect(editButtonsFound.length).toEqual(2);
233234
editButtonsFound.forEach((editButtonFound) => {
234-
expect(editButtonFound.nativeElement.disabled).toBeFalse();
235+
expect(editButtonFound.nativeElement.getAttribute('aria-disabled')).toBeNull();
236+
expect(editButtonFound.nativeElement.classList.contains('disabled')).toBeFalse();
235237
});
236238
});
237239

@@ -265,7 +267,8 @@ describe('GroupsRegistryComponent', () => {
265267
const editButtonsFound = fixture.debugElement.queryAll(By.css('#groups tr td:nth-child(5) button.btn-edit'));
266268
expect(editButtonsFound.length).toEqual(2);
267269
editButtonsFound.forEach((editButtonFound) => {
268-
expect(editButtonFound.nativeElement.disabled).toBeFalse();
270+
expect(editButtonFound.nativeElement.getAttribute('aria-disabled')).toBeNull();
271+
expect(editButtonFound.nativeElement.classList.contains('disabled')).toBeFalse();
269272
});
270273
});
271274
});
@@ -284,7 +287,8 @@ describe('GroupsRegistryComponent', () => {
284287
const editButtonsFound = fixture.debugElement.queryAll(By.css('#groups tr td:nth-child(5) button.btn-edit'));
285288
expect(editButtonsFound.length).toEqual(2);
286289
editButtonsFound.forEach((editButtonFound) => {
287-
expect(editButtonFound.nativeElement.disabled).toBeTrue();
290+
expect(editButtonFound.nativeElement.getAttribute('aria-disabled')).toBe('true');
291+
expect(editButtonFound.nativeElement.classList.contains('disabled')).toBeTrue();
288292
});
289293
});
290294
});

src/app/collection-page/delete-collection-page/delete-collection-page.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ <h1 id="header" class="border-bottom pb-2">{{ 'collection.delete.head' | transla
66
<p class="pb-2">{{ 'collection.delete.text' | translate:{ dso: dsoNameService.getName(dso) } }}</p>
77
<div class="form-group row">
88
<div class="col text-right space-children-mr">
9-
<button class="btn btn-outline-secondary" (click)="onCancel(dso)" [disabled]="(processing$ | async)">
9+
<button class="btn btn-outline-secondary" (click)="onCancel(dso)" [dsBtnDisabled]="(processing$ | async)">
1010
<i class="fas fa-times"></i> {{'collection.delete.cancel' | translate}}
1111
</button>
12-
<button class="btn btn-danger" (click)="onConfirm(dso)" [disabled]="(processing$ | async)">
12+
<button class="btn btn-danger" (click)="onConfirm(dso)" [dsBtnDisabled]="(processing$ | async)">
1313
<span *ngIf="processing$ | async"><i class='fas fa-circle-notch fa-spin'></i> {{'collection.delete.processing' | translate}}</span>
1414
<span *ngIf="!(processing$ | async)"><i class="fas fa-trash"></i> {{'collection.delete.confirm' | translate}}</span>
1515
</button>

src/app/collection-page/edit-collection-page/collection-source/collection-source-controls/collection-source-controls.component.html

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,32 +19,32 @@ <h3>{{ 'collection.source.controls.head' | translate }}</h3>
1919
</div>
2020

2121
<button *ngIf="!(testConfigRunning$ |async)" class="btn btn-secondary"
22-
[disabled]="!(isEnabled)"
22+
[dsBtnDisabled]="!(isEnabled)"
2323
(click)="testConfiguration(contentSource)">
2424
<span>{{'collection.source.controls.test.submit' | translate}}</span>
2525
</button>
2626
<button *ngIf="(testConfigRunning$ |async)" class="btn btn-secondary"
27-
[disabled]="true">
27+
[dsBtnDisabled]="true">
2828
<span class="spinner-border spinner-border-sm spinner-button" role="status" aria-hidden="true"></span>
2929
<span>{{'collection.source.controls.test.running' | translate}}</span>
3030
</button>
3131
<button *ngIf="!(importRunning$ |async)" class="btn btn-primary"
32-
[disabled]="!(isEnabled)"
32+
[dsBtnDisabled]="!(isEnabled)"
3333
(click)="importNow()">
3434
<span class="d-none d-sm-inline">{{'collection.source.controls.import.submit' | translate}}</span>
3535
</button>
3636
<button *ngIf="(importRunning$ |async)" class="btn btn-primary"
37-
[disabled]="true">
37+
[dsBtnDisabled]="true">
3838
<span class="spinner-border spinner-border-sm spinner-button" role="status" aria-hidden="true"></span>
3939
<span class="d-none d-sm-inline">{{'collection.source.controls.import.running' | translate}}</span>
4040
</button>
4141
<button *ngIf="!(reImportRunning$ |async)" class="btn btn-primary"
42-
[disabled]="!(isEnabled)"
42+
[dsBtnDisabled]="!(isEnabled)"
4343
(click)="resetAndReimport()">
4444
<span class="d-none d-sm-inline">&nbsp;{{'collection.source.controls.reset.submit' | translate}}</span>
4545
</button>
4646
<button *ngIf="(reImportRunning$ |async)" class="btn btn-primary"
47-
[disabled]="true">
47+
[dsBtnDisabled]="true">
4848
<span class="spinner-border spinner-border-sm spinner-button" role="status" aria-hidden="true"></span>
4949
<span class="d-none d-sm-inline">&nbsp;{{'collection.source.controls.reset.running' | translate}}</span>
5050
</button>

src/app/collection-page/edit-collection-page/collection-source/collection-source-controls/collection-source-controls.component.spec.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { TestScheduler } from 'rxjs/testing';
2222
import { By } from '@angular/platform-browser';
2323
import { VarDirective } from '../../../../shared/utils/var.directive';
2424
import { ContentSourceSetSerializer } from '../../../../core/shared/content-source-set-serializer';
25+
import {BtnDisabledDirective} from '../../../../shared/btn-disabled.directive';
2526

2627
describe('CollectionSourceControlsComponent', () => {
2728
let comp: CollectionSourceControlsComponent;
@@ -100,7 +101,7 @@ describe('CollectionSourceControlsComponent', () => {
100101

101102
TestBed.configureTestingModule({
102103
imports: [TranslateModule.forRoot(), RouterTestingModule],
103-
declarations: [CollectionSourceControlsComponent, VarDirective],
104+
declarations: [CollectionSourceControlsComponent, VarDirective, BtnDisabledDirective],
104105
providers: [
105106
{provide: ScriptDataService, useValue: scriptDataService},
106107
{provide: ProcessDataService, useValue: processDataService},
@@ -189,9 +190,10 @@ describe('CollectionSourceControlsComponent', () => {
189190

190191
const buttons = fixture.debugElement.queryAll(By.css('button'));
191192

192-
expect(buttons[0].nativeElement.disabled).toBeTrue();
193-
expect(buttons[1].nativeElement.disabled).toBeTrue();
194-
expect(buttons[2].nativeElement.disabled).toBeTrue();
193+
buttons.forEach(button => {
194+
expect(button.nativeElement.getAttribute('aria-disabled')).toBe('true');
195+
expect(button.nativeElement.classList.contains('disabled')).toBeTrue();
196+
});
195197
});
196198
it('should be enabled when isEnabled is true', () => {
197199
comp.shouldShow = true;
@@ -201,9 +203,10 @@ describe('CollectionSourceControlsComponent', () => {
201203

202204
const buttons = fixture.debugElement.queryAll(By.css('button'));
203205

204-
expect(buttons[0].nativeElement.disabled).toBeFalse();
205-
expect(buttons[1].nativeElement.disabled).toBeFalse();
206-
expect(buttons[2].nativeElement.disabled).toBeFalse();
206+
buttons.forEach(button => {
207+
expect(button.nativeElement.getAttribute('aria-disabled')).toBe('false');
208+
expect(button.nativeElement.classList.contains('disabled')).toBeFalse();
209+
});
207210
});
208211
it('should call the corresponding button when clicked', () => {
209212
spyOn(comp, 'testConfiguration');

0 commit comments

Comments
 (0)