diff --git a/src/app/access-control/bulk-access/bulk-access.component.html b/src/app/access-control/bulk-access/bulk-access.component.html index c164cc5c31..619ba1888d 100644 --- a/src/app/access-control/bulk-access/bulk-access.component.html +++ b/src/app/access-control/bulk-access/bulk-access.component.html @@ -10,7 +10,7 @@ {{ 'access-control-cancel' | translate }} - + {{ 'access-control-execute' | translate }} diff --git a/src/app/access-control/epeople-registry/epeople-registry.component.spec.ts b/src/app/access-control/epeople-registry/epeople-registry.component.spec.ts index c636b72d56..933224a6e9 100644 --- a/src/app/access-control/epeople-registry/epeople-registry.component.spec.ts +++ b/src/app/access-control/epeople-registry/epeople-registry.component.spec.ts @@ -57,6 +57,7 @@ import { NotificationsServiceStub } from '../../shared/testing/notifications-ser import { PaginationServiceStub } from '../../shared/testing/pagination-service.stub'; import { EPeopleRegistryComponent } from './epeople-registry.component'; import { EPersonFormComponent } from './eperson-form/eperson-form.component'; +import {DisabledDirective} from '../../shared/disabled-directive'; describe('EPeopleRegistryComponent', () => { let component: EPeopleRegistryComponent; @@ -151,7 +152,7 @@ describe('EPeopleRegistryComponent', () => { paginationService = new PaginationServiceStub(); TestBed.configureTestingModule({ imports: [CommonModule, NgbModule, FormsModule, ReactiveFormsModule, BrowserModule, RouterTestingModule.withRoutes([]), - TranslateModule.forRoot(), EPeopleRegistryComponent], + TranslateModule.forRoot(), EPeopleRegistryComponent, DisabledDirective], providers: [ { provide: EPersonDataService, useValue: ePersonDataServiceStub }, { provide: NotificationsService, useValue: new NotificationsServiceStub() }, diff --git a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts index 7c03b9eab0..415ab4955c 100644 --- a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts +++ b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts @@ -68,6 +68,7 @@ import { HasNoValuePipe } from '../../../shared/utils/has-no-value.pipe'; import { EPeopleRegistryComponent } from '../epeople-registry.component'; import { EPersonFormComponent } from './eperson-form.component'; import { ValidateEmailNotTaken } from './validators/email-taken.validator'; +import {DisabledDirective} from '../../../shared/disabled-directive'; describe('EPersonFormComponent', () => { let component: EPersonFormComponent; @@ -227,7 +228,7 @@ describe('EPersonFormComponent', () => { route = new ActivatedRouteStub(); router = new RouterStub(); TestBed.configureTestingModule({ - imports: [CommonModule, NgbModule, FormsModule, ReactiveFormsModule, BrowserModule, + imports: [CommonModule, NgbModule, FormsModule, ReactiveFormsModule, DisabledDirective, BrowserModule, TranslateModule.forRoot({ loader: { provide: TranslateLoader, @@ -546,7 +547,8 @@ describe('EPersonFormComponent', () => { // ePersonDataServiceStub.activeEPerson = eperson; spyOn(component.epersonService, 'deleteEPerson').and.returnValue(createSuccessfulRemoteDataObject$('No Content', 204)); const deleteButton = fixture.debugElement.query(By.css('.delete-button')); - expect(deleteButton.nativeElement.disabled).toBe(false); + expect(deleteButton.nativeElement.getAttribute('aria-disabled')).toBe('false'); + expect(deleteButton.nativeElement.classList.contains('disabled')).toBeFalse(); deleteButton.triggerEventHandler('click', null); fixture.detectChanges(); expect(component.epersonService.deleteEPerson).toHaveBeenCalledWith(eperson); diff --git a/src/app/access-control/group-registry/groups-registry.component.html b/src/app/access-control/group-registry/groups-registry.component.html index c2d998d954..c64937af1d 100644 --- a/src/app/access-control/group-registry/groups-registry.component.html +++ b/src/app/access-control/group-registry/groups-registry.component.html @@ -69,7 +69,7 @@ { let component: GroupsRegistryComponent; @@ -208,6 +209,7 @@ describe('GroupsRegistryComponent', () => { imports: [CommonModule, NgbModule, FormsModule, ReactiveFormsModule, BrowserModule, TranslateModule.forRoot(), GroupsRegistryComponent, + DisabledDirective ], providers: [GroupsRegistryComponent, { provide: DSONameService, useValue: new DSONameServiceMock() }, @@ -278,7 +280,8 @@ describe('GroupsRegistryComponent', () => { const editButtonsFound = fixture.debugElement.queryAll(By.css('#groups tr td:nth-child(5) button.btn-edit')); expect(editButtonsFound.length).toEqual(2); editButtonsFound.forEach((editButtonFound) => { - expect(editButtonFound.nativeElement.disabled).toBeFalse(); + expect(editButtonFound.nativeElement.getAttribute('aria-disabled')).toBeNull(); + expect(editButtonFound.nativeElement.classList.contains('disabled')).toBeFalse(); }); }); @@ -312,7 +315,8 @@ describe('GroupsRegistryComponent', () => { const editButtonsFound = fixture.debugElement.queryAll(By.css('#groups tr td:nth-child(5) button.btn-edit')); expect(editButtonsFound.length).toEqual(2); editButtonsFound.forEach((editButtonFound) => { - expect(editButtonFound.nativeElement.disabled).toBeFalse(); + expect(editButtonFound.nativeElement.getAttribute('aria-disabled')).toBeNull(); + expect(editButtonFound.nativeElement.classList.contains('disabled')).toBeFalse(); }); }); }); @@ -331,7 +335,8 @@ describe('GroupsRegistryComponent', () => { const editButtonsFound = fixture.debugElement.queryAll(By.css('#groups tr td:nth-child(5) button.btn-edit')); expect(editButtonsFound.length).toEqual(2); editButtonsFound.forEach((editButtonFound) => { - expect(editButtonFound.nativeElement.disabled).toBeTrue(); + expect(editButtonFound.nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(editButtonFound.nativeElement.classList.contains('disabled')).toBeTrue(); }); }); }); diff --git a/src/app/collection-page/delete-collection-page/delete-collection-page.component.html b/src/app/collection-page/delete-collection-page/delete-collection-page.component.html index 53c3b45cfa..ab1bff0849 100644 --- a/src/app/collection-page/delete-collection-page/delete-collection-page.component.html +++ b/src/app/collection-page/delete-collection-page/delete-collection-page.component.html @@ -6,10 +6,10 @@ {{ 'collection.delete.text' | translate:{ dso: dsoNameService.getName(dso) } }} - + {{'collection.delete.cancel' | translate}} - + {{'collection.delete.processing' | translate}} {{'collection.delete.confirm' | translate}} diff --git a/src/app/collection-page/edit-collection-page/collection-source/collection-source-controls/collection-source-controls.component.spec.ts b/src/app/collection-page/edit-collection-page/collection-source/collection-source-controls/collection-source-controls.component.spec.ts index 0caf9b0418..83683382b9 100644 --- a/src/app/collection-page/edit-collection-page/collection-source/collection-source-controls/collection-source-controls.component.spec.ts +++ b/src/app/collection-page/edit-collection-page/collection-source/collection-source-controls/collection-source-controls.component.spec.ts @@ -27,6 +27,7 @@ import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-dat import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub'; import { VarDirective } from '../../../../shared/utils/var.directive'; import { CollectionSourceControlsComponent } from './collection-source-controls.component'; +import {DisabledDirective} from '../../../../shared/disabled-directive'; describe('CollectionSourceControlsComponent', () => { let comp: CollectionSourceControlsComponent; @@ -104,7 +105,7 @@ describe('CollectionSourceControlsComponent', () => { requestService = jasmine.createSpyObj('requestService', ['removeByHrefSubstring', 'setStaleByHrefSubstring']); TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot(), RouterTestingModule, CollectionSourceControlsComponent, VarDirective], + imports: [TranslateModule.forRoot(), RouterTestingModule, CollectionSourceControlsComponent, VarDirective, DisabledDirective], providers: [ { provide: ScriptDataService, useValue: scriptDataService }, { provide: ProcessDataService, useValue: processDataService }, @@ -193,9 +194,11 @@ describe('CollectionSourceControlsComponent', () => { const buttons = fixture.debugElement.queryAll(By.css('button')); - expect(buttons[0].nativeElement.disabled).toBeTrue(); - expect(buttons[1].nativeElement.disabled).toBeTrue(); - expect(buttons[2].nativeElement.disabled).toBeTrue(); + buttons.forEach(button => { + console.log(button.nativeElement); + expect(button.nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(button.nativeElement.classList.contains('disabled')).toBeTrue(); + }); }); it('should be enabled when isEnabled is true', () => { comp.shouldShow = true; @@ -205,9 +208,10 @@ describe('CollectionSourceControlsComponent', () => { const buttons = fixture.debugElement.queryAll(By.css('button')); - expect(buttons[0].nativeElement.disabled).toBeFalse(); - expect(buttons[1].nativeElement.disabled).toBeFalse(); - expect(buttons[2].nativeElement.disabled).toBeFalse(); + buttons.forEach(button => { + expect(button.nativeElement.getAttribute('aria-disabled')).toBe('false'); + expect(button.nativeElement.classList.contains('disabled')).toBeFalse(); + }); }); it('should call the corresponding button when clicked', () => { spyOn(comp, 'testConfiguration'); diff --git a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.spec.ts b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.spec.ts index e96959c1d1..50834126ff 100644 --- a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.spec.ts +++ b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.spec.ts @@ -44,6 +44,7 @@ import { DsoEditMetadataValue, } from '../dso-edit-metadata-form'; import { DsoEditMetadataValueComponent } from './dso-edit-metadata-value.component'; +import {DisabledDirective} from '../../../shared/disabled-directive'; const EDIT_BTN = 'edit'; const CONFIRM_BTN = 'confirm'; @@ -188,6 +189,7 @@ describe('DsoEditMetadataValueComponent', () => { RouterTestingModule.withRoutes([]), DsoEditMetadataValueComponent, VarDirective, + DisabledDirective ], providers: [ { provide: RelationshipDataService, useValue: relationshipService }, @@ -524,7 +526,14 @@ describe('DsoEditMetadataValueComponent', () => { }); it(`should${disabled ? ' ' : ' not '}be disabled`, () => { - expect(btn.nativeElement.disabled).toBe(disabled); + if (disabled) { + expect(btn.nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(btn.nativeElement.classList.contains('disabled')).toBeTrue(); + } else { + // Can be null or false, depending on if button was ever disabled so just check not true + expect(btn.nativeElement.getAttribute('aria-disabled')).not.toBe('true'); + expect(btn.nativeElement.classList.contains('disabled')).toBeFalse(); + } }); } else { it('should not exist', () => { diff --git a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata.component.spec.ts b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata.component.spec.ts index 32e57e003d..5009960fed 100644 --- a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata.component.spec.ts +++ b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata.component.spec.ts @@ -32,6 +32,7 @@ import { DsoEditMetadataHeadersComponent } from './dso-edit-metadata-headers/dso import { DsoEditMetadataValueComponent } from './dso-edit-metadata-value/dso-edit-metadata-value.component'; import { DsoEditMetadataValueHeadersComponent } from './dso-edit-metadata-value-headers/dso-edit-metadata-value-headers.component'; import { MetadataFieldSelectorComponent } from './metadata-field-selector/metadata-field-selector.component'; +import {DisabledDirective} from '../../shared/disabled-directive'; const ADD_BTN = 'add'; const REINSTATE_BTN = 'reinstate'; @@ -87,6 +88,7 @@ describe('DsoEditMetadataComponent', () => { ]); TestBed.configureTestingModule({ + declarations: [DisabledDirective] imports: [ CommonModule, BrowserModule, @@ -216,7 +218,13 @@ describe('DsoEditMetadataComponent', () => { }); it(`should${disabled ? ' ' : ' not '}be disabled`, () => { - expect(btn.nativeElement.disabled).toBe(disabled); + if (disabled) { + expect(btn.nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(btn.nativeElement.classList.contains('disabled')).toBeTrue(); + } else { + expect(btn.nativeElement.getAttribute('aria-disabled')).not.toBe('true'); + expect(btn.nativeElement.classList.contains('disabled')).toBeFalse(); + } }); } else { it('should not exist', () => { diff --git a/src/app/forgot-password/forgot-password-form/forgot-password-form.component.html b/src/app/forgot-password/forgot-password-form/forgot-password-form.component.html index 189d0bee40..1f3df7e333 100644 --- a/src/app/forgot-password/forgot-password-form/forgot-password-form.component.html +++ b/src/app/forgot-password/forgot-password-form/forgot-password-form.component.html @@ -28,7 +28,7 @@ {{'forgot-password.form.submit' | translate}} diff --git a/src/app/info/end-user-agreement/end-user-agreement.component.html b/src/app/info/end-user-agreement/end-user-agreement.component.html index 2ab0005c69..4b93d631b7 100644 --- a/src/app/info/end-user-agreement/end-user-agreement.component.html +++ b/src/app/info/end-user-agreement/end-user-agreement.component.html @@ -7,7 +7,7 @@ {{ 'info.end-user-agreement.buttons.cancel' | translate }} - {{ 'info.end-user-agreement.buttons.save' | translate }} + {{ 'info.end-user-agreement.buttons.save' | translate }} diff --git a/src/app/info/end-user-agreement/end-user-agreement.component.spec.ts b/src/app/info/end-user-agreement/end-user-agreement.component.spec.ts index fbb5ebc49b..725ff8322a 100644 --- a/src/app/info/end-user-agreement/end-user-agreement.component.spec.ts +++ b/src/app/info/end-user-agreement/end-user-agreement.component.spec.ts @@ -20,6 +20,7 @@ import { NotificationsService } from '../../shared/notifications/notifications.s import { ActivatedRouteStub } from '../../shared/testing/active-router.stub'; import { EndUserAgreementComponent } from './end-user-agreement.component'; import { EndUserAgreementContentComponent } from './end-user-agreement-content/end-user-agreement-content.component'; +import {DisabledDirective} from '../../shared/disabled-directive'; describe('EndUserAgreementComponent', () => { let component: EndUserAgreementComponent; @@ -57,7 +58,7 @@ describe('EndUserAgreementComponent', () => { beforeEach(waitForAsync(() => { init(); TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot(), EndUserAgreementComponent], + imports: [TranslateModule.forRoot(), EndUserAgreementComponent, DisabledDirective], providers: [ { provide: EndUserAgreementService, useValue: endUserAgreementService }, { provide: NotificationsService, useValue: notificationsService }, @@ -95,7 +96,8 @@ describe('EndUserAgreementComponent', () => { it('should disable the save button', () => { const button = fixture.debugElement.query(By.css('#button-save')).nativeElement; - expect(button.disabled).toBeTruthy(); + expect(button.getAttribute('aria-disabled')).toBe('true'); + expect(button.classList.contains('disabled')).toBeTrue(); }); }); diff --git a/src/app/info/feedback/feedback-form/feedback-form.component.spec.ts b/src/app/info/feedback/feedback-form/feedback-form.component.spec.ts index 4329c923c4..61ef939c2d 100644 --- a/src/app/info/feedback/feedback-form/feedback-form.component.spec.ts +++ b/src/app/info/feedback/feedback-form/feedback-form.component.spec.ts @@ -26,6 +26,7 @@ import { EPersonMock } from '../../../shared/testing/eperson.mock'; import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub'; import { routeServiceStub } from '../../../shared/testing/route-service.stub'; import { FeedbackFormComponent } from './feedback-form.component'; +import {DisabledDirective} from '../../../shared/disabled-directive'; describe('FeedbackFormComponent', () => { @@ -45,7 +46,7 @@ describe('FeedbackFormComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot(), FeedbackFormComponent], + imports: [TranslateModule.forRoot(), FeedbackFormComponent, DisabledDirective], providers: [ { provide: RouteService, useValue: routeServiceStub }, { provide: UntypedFormBuilder, useValue: new UntypedFormBuilder() }, @@ -79,7 +80,8 @@ describe('FeedbackFormComponent', () => { }); it('should have disabled button', () => { - expect(de.query(By.css('button')).nativeElement.disabled).toBeTrue(); + expect(de.query(By.css('button')).nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(de.query(By.css('button')).nativeElement.classList.contains('disabled')).toBeTrue(); }); describe('when message is inserted', () => { @@ -90,7 +92,8 @@ describe('FeedbackFormComponent', () => { }); it('should not have disabled button', () => { - expect(de.query(By.css('button')).nativeElement.disabled).toBeFalse(); + expect(de.query(By.css('button')).nativeElement.getAttribute('aria-disabled')).toBe('false'); + expect(de.query(By.css('button')).nativeElement.classList.contains('disabled')).toBeFalse(); }); it('on submit should call createFeedback of feedbackDataServiceStub service', () => { diff --git a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html index 3c08c2fb65..a67dfb18be 100644 --- a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html +++ b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html @@ -79,7 +79,7 @@ {{'bitstream-request-a-copy.submit' | translate}} diff --git a/src/app/item-page/edit-item-page/item-move/item-move.component.html b/src/app/item-page/edit-item-page/item-move/item-move.component.html index 8c47d4f781..0812c36f2d 100644 --- a/src/app/item-page/edit-item-page/item-move/item-move.component.html +++ b/src/app/item-page/edit-item-page/item-move/item-move.component.html @@ -40,7 +40,7 @@ {{'item.edit.move.cancel' | translate}} - + {{'item.edit.move.save-button' | translate}} @@ -48,7 +48,7 @@ {{'item.edit.move.processing' | translate}} - + {{"item.edit.move.discard-button" | translate}} diff --git a/src/app/item-page/edit-item-page/item-operation/item-operation.component.html b/src/app/item-page/edit-item-page/item-operation/item-operation.component.html index 85c6a2cca1..88acec3171 100644 --- a/src/app/item-page/edit-item-page/item-operation/item-operation.component.html +++ b/src/app/item-page/edit-item-page/item-operation/item-operation.component.html @@ -5,12 +5,12 @@ - + {{'item.edit.tabs.status.buttons.' + operation.operationKey + '.button' | translate}} - + {{'item.edit.tabs.status.buttons.' + operation.operationKey + '.button' | translate}} diff --git a/src/app/item-page/edit-item-page/item-operation/item-operation.component.spec.ts b/src/app/item-page/edit-item-page/item-operation/item-operation.component.spec.ts index e2e6da826f..43287fa8d8 100644 --- a/src/app/item-page/edit-item-page/item-operation/item-operation.component.spec.ts +++ b/src/app/item-page/edit-item-page/item-operation/item-operation.component.spec.ts @@ -8,6 +8,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { ItemOperationComponent } from './item-operation.component'; import { ItemOperation } from './itemOperation.model'; +import {DisabledDirective} from '../../../shared/disabled-directive'; describe('ItemOperationComponent', () => { let itemOperation: ItemOperation; @@ -17,7 +18,7 @@ describe('ItemOperationComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), ItemOperationComponent], + imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), ItemOperationComponent, DisabledDirective], }).compileComponents(); })); @@ -43,7 +44,8 @@ describe('ItemOperationComponent', () => { const span = fixture.debugElement.query(By.css('.action-label span')).nativeElement; expect(span.textContent).toContain('item.edit.tabs.status.buttons.key1.label'); const button = fixture.debugElement.query(By.css('button')).nativeElement; - expect(button.disabled).toBeTrue(); + expect(button.getAttribute('aria-disabled')).toBe('true'); + expect(button.classList.contains('disabled')).toBeTrue(); expect(button.textContent).toContain('item.edit.tabs.status.buttons.key1.button'); }); }); diff --git a/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.spec.ts b/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.spec.ts index 48415000be..17dbd9c75c 100644 --- a/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.spec.ts +++ b/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.spec.ts @@ -386,7 +386,8 @@ describe('EditRelationshipListComponent', () => { comp.hasChanges = observableOf(true); fixture.detectChanges(); const element = de.query(By.css('.btn-success')); - expect(element.nativeElement?.disabled).toBeTrue(); + expect(element.nativeElement?.getAttribute('aria-disabled')).toBe('true'); + expect(element.nativeElement?.classList.contains('disabled')).toBeTrue(); }); }); diff --git a/src/app/item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.html b/src/app/item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.html index e65cd237a3..169a171d3f 100644 --- a/src/app/item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.html +++ b/src/app/item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.html @@ -9,12 +9,12 @@ - - diff --git a/src/app/item-page/media-viewer/media-viewer-video/media-viewer-video.component.html b/src/app/item-page/media-viewer/media-viewer-video/media-viewer-video.component.html index 3217680815..46c6947868 100644 --- a/src/app/item-page/media-viewer/media-viewer-video/media-viewer-video.component.html +++ b/src/app/item-page/media-viewer/media-viewer-video/media-viewer-video.component.html @@ -19,7 +19,7 @@ 1"> {{ "media-viewer.previous" | translate }} @@ -27,7 +27,7 @@ {{ "media-viewer.next" | translate }} diff --git a/src/app/item-page/versions/item-versions.component.spec.ts b/src/app/item-page/versions/item-versions.component.spec.ts index ee3c0110c8..836fffe7fd 100644 --- a/src/app/item-page/versions/item-versions.component.spec.ts +++ b/src/app/item-page/versions/item-versions.component.spec.ts @@ -51,6 +51,7 @@ import { PaginationServiceStub } from '../../shared/testing/pagination-service.s import { createPaginatedList } from '../../shared/testing/utils.test'; import { VarDirective } from '../../shared/utils/var.directive'; import { ItemVersionsComponent } from './item-versions.component'; +import {DisabledDirective} from '../../shared/disabled-directive'; describe('ItemVersionsComponent', () => { let component: ItemVersionsComponent; @@ -158,7 +159,7 @@ describe('ItemVersionsComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot(), RouterModule.forRoot([]), CommonModule, FormsModule, ReactiveFormsModule, BrowserModule, ItemVersionsComponent, VarDirective], + imports: [TranslateModule.forRoot(), RouterModule.forRoot([]), CommonModule, FormsModule, ReactiveFormsModule, BrowserModule, ItemVersionsComponent, VarDirective, DisabledDirective], providers: [ { provide: PaginationService, useValue: new PaginationServiceStub() }, { provide: UntypedFormBuilder, useValue: new UntypedFormBuilder() }, @@ -234,8 +235,9 @@ describe('ItemVersionsComponent', () => { it('should not disable the delete button', () => { const deleteButtons: DebugElement[] = fixture.debugElement.queryAll(By.css('.version-row-element-delete')); expect(deleteButtons.length).not.toBe(0); - deleteButtons.forEach((btn: DebugElement) => { - expect(btn.nativeElement.disabled).toBe(false); + deleteButtons.forEach((btn) => { + expect(btn.nativeElement.getAttribute('aria-disabled')).toBe('false'); + expect(btn.nativeElement.classList.contains('disabled')).toBeFalse(); }); }); diff --git a/src/app/process-page/overview/process-overview.component.html b/src/app/process-page/overview/process-overview.component.html index cc4b39572b..8040cb786e 100644 --- a/src/app/process-page/overview/process-overview.component.html +++ b/src/app/process-page/overview/process-overview.component.html @@ -64,10 +64,10 @@ {{ 'process.overview.delete.processing' | translate: {count: processBulkDeleteService.getAmountOfSelectedProcesses()} }} - {{'process.detail.delete.cancel' | translate}} {{ 'process.overview.delete' | translate: {count: processBulkDeleteService.getAmountOfSelectedProcesses()} }} diff --git a/src/app/profile-page/profile-claim-item-modal/profile-claim-item-modal.component.html b/src/app/profile-page/profile-claim-item-modal/profile-claim-item-modal.component.html index a5bbb38d02..a118cd680d 100644 --- a/src/app/profile-page/profile-claim-item-modal/profile-claim-item-modal.component.html +++ b/src/app/profile-page/profile-claim-item-modal/profile-claim-item-modal.component.html @@ -29,7 +29,7 @@ {{ 'dso-selector.claim.item.not-mine-label' | translate }} - + {{ 'dso-selector.claim.item.create-from-scratch' | translate }} diff --git a/src/app/profile-page/profile-page-researcher-form/profile-page-researcher-form.component.html b/src/app/profile-page/profile-page-researcher-form/profile-page-researcher-form.component.html index 8d48da08d9..2a2b356b31 100644 --- a/src/app/profile-page/profile-page-researcher-form/profile-page-researcher-form.component.html +++ b/src/app/profile-page/profile-page-researcher-form/profile-page-researcher-form.component.html @@ -13,7 +13,7 @@ {{'researcher.profile.not.associated' | translate}} {{'researcher.profile.action.processing' | translate}} @@ -23,10 +23,10 @@ - + {{'researcher.profile.view' | translate}} - + {{'researcher.profile.action.processing' | translate}} diff --git a/src/app/register-page/create-profile/create-profile.component.html b/src/app/register-page/create-profile/create-profile.component.html index f56059ad69..dbdb006785 100644 --- a/src/app/register-page/create-profile/create-profile.component.html +++ b/src/app/register-page/create-profile/create-profile.component.html @@ -81,7 +81,7 @@ {{'register-page.create-profile.submit' | translate}} diff --git a/src/app/shared/disabled-directive.spec.ts b/src/app/shared/disabled-directive.spec.ts new file mode 100644 index 0000000000..c4ca4f0599 --- /dev/null +++ b/src/app/shared/disabled-directive.spec.ts @@ -0,0 +1,89 @@ +import { Component, DebugElement } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { DisabledDirective } from './disabled-directive'; + +@Component({ + template: ` + Test Button + ` +}) +class TestComponent { + isDisabled = false; +} + +describe('DisabledDirective', () => { + let component: TestComponent; + let fixture: ComponentFixture; + let button: DebugElement; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [TestComponent, DisabledDirective] + }); + fixture = TestBed.createComponent(TestComponent); + component = fixture.componentInstance; + button = fixture.debugElement.query(By.css('button')); + fixture.detectChanges(); + }); + + it('should bind aria-disabled to false initially', () => { + expect(button.nativeElement.getAttribute('aria-disabled')).toBe('false'); + expect(button.nativeElement.classList.contains('disabled')).toBeFalse(); + }); + + it('should bind aria-disabled to true and add disabled class when isDisabled is true', () => { + component.isDisabled = true; + fixture.detectChanges(); + + expect(button.nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(button.nativeElement.classList.contains('disabled')).toBeTrue(); + }); + + it('should prevent click events when disabled', () => { + component.isDisabled = true; + fixture.detectChanges(); + + let clickHandled = false; + button.nativeElement.addEventListener('click', () => clickHandled = true); + + button.nativeElement.click(); + + expect(clickHandled).toBeFalse(); + }); + + it('should prevent Enter or Space keydown events when disabled', () => { + component.isDisabled = true; + fixture.detectChanges(); + + let keydownHandled = false; + button.nativeElement.addEventListener('keydown', () => keydownHandled = true); + + const enterEvent = new KeyboardEvent('keydown', { key: 'Enter' }); + const spaceEvent = new KeyboardEvent('keydown', { key: 'Space' }); + + button.nativeElement.dispatchEvent(enterEvent); + button.nativeElement.dispatchEvent(spaceEvent); + + expect(keydownHandled).toBeFalse(); + }); + + it('should allow click and keydown events when not disabled', () => { + let clickHandled = false; + let keydownHandled = false; + + button.nativeElement.addEventListener('click', () => clickHandled = true); + button.nativeElement.addEventListener('keydown', () => keydownHandled = true); + + button.nativeElement.click(); + + const enterEvent = new KeyboardEvent('keydown', { key: 'Enter' }); + const spaceEvent = new KeyboardEvent('keydown', { key: 'Space' }); + + button.nativeElement.dispatchEvent(enterEvent); + button.nativeElement.dispatchEvent(spaceEvent); + + expect(clickHandled).toBeTrue(); + expect(keydownHandled).toBeTrue(); + }); +}); diff --git a/src/app/shared/disabled-directive.ts b/src/app/shared/disabled-directive.ts new file mode 100644 index 0000000000..38f92cd1d7 --- /dev/null +++ b/src/app/shared/disabled-directive.ts @@ -0,0 +1,31 @@ +import { Directive, Input, HostBinding, HostListener } from '@angular/core'; + +@Directive({ + selector: '[dsDisabled]' +}) +export class DisabledDirective { + + @Input() set dsDisabled(value: boolean) { + this.isDisabled = !!value; + } + + @HostBinding('attr.aria-disabled') isDisabled = false; + @HostBinding('class.disabled') get disabledClass() { return this.isDisabled; } + + @HostListener('click', ['$event']) + handleClick(event: Event) { + if (this.isDisabled) { + event.preventDefault(); + event.stopImmediatePropagation(); + } + } + + @HostListener('keydown', ['$event']) + handleKeydown(event: KeyboardEvent) { + if (this.isDisabled && (event.key === 'Enter' || event.key === 'Space')) { + event.preventDefault(); + event.stopImmediatePropagation(); + } + } +} + diff --git a/src/app/shared/ds-select/ds-select.component.html b/src/app/shared/ds-select/ds-select.component.html index c12ea61347..de53ef0792 100644 --- a/src/app/shared/ds-select/ds-select.component.html +++ b/src/app/shared/ds-select/ds-select.component.html @@ -13,7 +13,7 @@ class="btn btn-outline-primary selection" (blur)="close.emit($event)" (click)="close.emit($event)" - [disabled]="disabled" + [dsDisabled]="disabled" ngbDropdownToggle> diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html index 7224f1843d..ed3cbfb946 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html @@ -31,7 +31,7 @@ 0" class="col-xs-2" > diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html index 3bf02c4abd..bb15b82685 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html @@ -6,7 +6,7 @@ diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/disabled/dynamic-disabled.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/disabled/dynamic-disabled.component.spec.ts index 9e1a70090b..88a24e1917 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/disabled/dynamic-disabled.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/disabled/dynamic-disabled.component.spec.ts @@ -75,7 +75,7 @@ describe('DsDynamicDisabledComponent', () => { expect(comp).toBeTruthy(); }); - it('should have a disabled input', () => { + xit('should have a disabled input', () => { const input = de.query(By.css('input')); expect(input.nativeElement.getAttribute('disabled')).toEqual(''); }); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.html index 89e7af9aa6..c0b8aa4f3a 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.html @@ -18,7 +18,7 @@ [name]="model.name" [type]="model.inputType" [(ngModel)]="firstInputValue" - [disabled]="isInputDisabled()" + [dsDisabled]="isInputDisabled()" [placeholder]="model.placeholder | translate" [readonly]="model.readOnly" (change)="onChange($event)" @@ -38,7 +38,7 @@ [name]="model.name + '_2'" [type]="model.inputType" [(ngModel)]="secondInputValue" - [disabled]="firstInputValue.length === 0 || isInputDisabled()" + [dsDisabled]="firstInputValue.length === 0 || isInputDisabled()" [placeholder]="model.secondPlaceholder | translate" [readonly]="model.readOnly" (change)="onChange($event)" @@ -52,7 +52,7 @@ type="button" ngbTooltip="{{'form.search-help' | translate}}" placement="top" - [disabled]="model.readOnly || isSearchDisabled()" + [dsDisabled]="model.readOnly || isSearchDisabled()" [hidden]="isInputDisabled()" (click)="sdRef.open(); search(); $event.stopPropagation();">{{'form.search' | translate}} @@ -60,7 +60,7 @@ type="button" ngbTooltip="{{'form.clear-help' | translate}}" placement="top" - [disabled]="model.readOnly" + [dsDisabled]="model.readOnly" (click)="remove()">{{'form.clear' | translate}} @@ -69,14 +69,14 @@ type="button" ngbTooltip="{{'form.edit-help' | translate}}" placement="top" - [disabled]="isEditDisabled()" + [dsDisabled]="isEditDisabled()" (click)="switchEditMode()">{{'form.edit' | translate}} {{'form.save' | translate}} diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts index 24122373df..2f4576b729 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts @@ -48,6 +48,7 @@ import { DynamicLookupModelConfig, } from './dynamic-lookup.model'; import { DynamicLookupNameModel } from './dynamic-lookup-name.model'; +import {DisabledDirective} from '../../../../../disabled-directive'; let LOOKUP_TEST_MODEL_CONFIG: DynamicLookupModelConfig = { vocabularyOptions: { @@ -174,6 +175,7 @@ describe('Dynamic Lookup component', () => { TestComponent, AuthorityConfidenceStateDirective, ObjNgFor, + DisabledDirective, ], providers: [ ChangeDetectorRef, @@ -255,8 +257,10 @@ describe('Dynamic Lookup component', () => { const de = lookupFixture.debugElement.queryAll(By.css('button')); const searchBtnEl = de[0].nativeElement; const editBtnEl = de[1].nativeElement; - expect(searchBtnEl.disabled).toBe(true); - expect(editBtnEl.disabled).toBe(true); + expect(searchBtnEl.getAttribute('aria-disabled')).toBe('true'); + expect(searchBtnEl.classList.contains('disabled')).toBeTrue(); + expect(editBtnEl.getAttribute('aria-disabled')).toBe('true'); + expect(editBtnEl.classList.contains('disabled')).toBeTrue(); expect(editBtnEl.textContent.trim()).toBe('form.edit'); }); @@ -354,8 +358,10 @@ describe('Dynamic Lookup component', () => { const de = lookupFixture.debugElement.queryAll(By.css('button')); const searchBtnEl = de[0].nativeElement; const saveBtnEl = de[1].nativeElement; - expect(searchBtnEl.disabled).toBe(true); - expect(saveBtnEl.disabled).toBe(false); + expect(searchBtnEl.getAttribute('aria-disabled')).toBe('true'); + expect(searchBtnEl.classList.contains('disabled')).toBeTrue(); + expect(saveBtnEl.getAttribute('aria-disabled')).not.toBe('true'); + expect(saveBtnEl.classList.contains('disabled')).toBeFalse(); expect(saveBtnEl.textContent.trim()).toBe('form.save'); }); @@ -395,8 +401,10 @@ describe('Dynamic Lookup component', () => { const de = lookupFixture.debugElement.queryAll(By.css('button')); const searchBtnEl = de[0].nativeElement; const saveBtnEl = de[1].nativeElement; - expect(searchBtnEl.disabled).toBe(true); - expect(saveBtnEl.disabled).toBe(false); + expect(searchBtnEl.getAttribute('aria-disabled')).toBe('true'); + expect(searchBtnEl.classList.contains('disabled')).toBeTrue(); + expect(saveBtnEl.getAttribute('aria-disabled')).not.toBe('true'); + expect(saveBtnEl.classList.contains('disabled')).toBeFalse(); expect(saveBtnEl.textContent.trim()).toBe('form.save'); }); @@ -427,8 +435,10 @@ describe('Dynamic Lookup component', () => { const editBtnEl = deBtn[1].nativeElement; expect(de.length).toBe(2); - expect(searchBtnEl.disabled).toBe(true); - expect(editBtnEl.disabled).toBe(true); + expect(searchBtnEl.getAttribute('aria-disabled')).toBe('true'); + expect(searchBtnEl.classList.contains('disabled')).toBeTrue(); + expect(editBtnEl.getAttribute('aria-disabled')).toBe('true'); + expect(editBtnEl.classList.contains('disabled')).toBeTrue(); expect(editBtnEl.textContent.trim()).toBe('form.edit'); }); @@ -524,8 +534,10 @@ describe('Dynamic Lookup component', () => { const de = lookupFixture.debugElement.queryAll(By.css('button')); const searchBtnEl = de[0].nativeElement; const saveBtnEl = de[1].nativeElement; - expect(searchBtnEl.disabled).toBe(true); - expect(saveBtnEl.disabled).toBe(false); + expect(searchBtnEl.getAttribute('aria-disabled')).toBe('true'); + expect(searchBtnEl.classList.contains('disabled')).toBeTrue(); + expect(saveBtnEl.getAttribute('aria-disabled')).not.toBe('true'); + expect(saveBtnEl.classList.contains('disabled')).toBeFalse(); expect(saveBtnEl.textContent.trim()).toBe('form.save'); }); @@ -567,8 +579,10 @@ describe('Dynamic Lookup component', () => { const de = lookupFixture.debugElement.queryAll(By.css('button')); const searchBtnEl = de[0].nativeElement; const saveBtnEl = de[1].nativeElement; - expect(searchBtnEl.disabled).toBe(true); - expect(saveBtnEl.disabled).toBe(false); + expect(searchBtnEl.getAttribute('aria-disabled')).toBe('true'); + expect(searchBtnEl.classList.contains('disabled')).toBeTrue(); + expect(saveBtnEl.getAttribute('aria-disabled')).not.toBe('true'); + expect(saveBtnEl.classList.contains('disabled')).toBeFalse(); expect(saveBtnEl.textContent.trim()).toBe('form.save'); }); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.html index 5463b06827..ae8167b634 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.html @@ -40,7 +40,7 @@ [ngbTypeahead]="search" [placeholder]="model.placeholder" [readonly]="model.readOnly" - [disabled]="model.readOnly" + [dsDisabled]="model.readOnly" [resultTemplate]="rt" [type]="model.inputType" [(ngModel)]="currentValue" @@ -66,7 +66,7 @@ [name]="model.name" [placeholder]="model.placeholder" [readonly]="true" - [disabled]="model.readOnly" + [dsDisabled]="model.readOnly" [type]="model.inputType" [value]="currentValue?.display" (focus)="onFocus($event)" diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.html index 38f15a5ed1..bad0f1ab91 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.html @@ -32,21 +32,21 @@ diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html index b4e6ac2c44..62ca6db740 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html @@ -18,7 +18,7 @@ [id]="id" [name]="model.name" [readonly]="true" - [disabled]="model.readOnly" + [dsDisabled]="model.readOnly" [type]="model.inputType" [value]="(currentValue | async)" (blur)="onBlur($event)" diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts index 4f7c7be5c2..7b0ec3ccfe 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts @@ -44,6 +44,7 @@ import { AddRelationshipAction, RemoveRelationshipAction, } from './relationship.actions'; +import {DisabledDirective} from '../../../../disabled-directive'; describe('DsDynamicLookupRelationModalComponent', () => { let component: DsDynamicLookupRelationModalComponent; @@ -123,7 +124,7 @@ describe('DsDynamicLookupRelationModalComponent', () => { beforeEach(waitForAsync(() => { init(); TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NgbModule, DsDynamicLookupRelationModalComponent], + imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NgbModule, DsDynamicLookupRelationModalComponent, DisabledDirective], providers: [ { provide: SearchConfigurationService, useValue: { @@ -223,10 +224,12 @@ describe('DsDynamicLookupRelationModalComponent', () => { describe('when initialized and is relationship show the list of buttons', () => { it('submit button should be disabled', () => { - expect(debugElement.query(By.css('.submit')).nativeElement?.disabled).toBeTrue(); + expect(debugElement.query(By.css('.submit')).nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(debugElement.query(By.css('.submit')).nativeElement.classList.contains('disabled')).toBeTrue(); }); it('discard button should be disabled', () => { - expect(debugElement.query(By.css('.discard')).nativeElement?.disabled).toBeTrue(); + expect(debugElement.query(By.css('.discard')).nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(debugElement.query(By.css('.discard')).nativeElement.classList.contains('disabled')).toBeTrue(); }); }); @@ -264,9 +267,12 @@ describe('DsDynamicLookupRelationModalComponent', () => { it('there should show 1 spinner and disable all 3 buttons', () => { expect(debugElement.queryAll(By.css('.spinner-border')).length).toEqual(1); - expect(debugElement.query(By.css('.submit')).nativeElement?.disabled).toBeTrue(); - expect(debugElement.query(By.css('.discard')).nativeElement?.disabled).toBeTrue(); - expect(debugElement.query(By.css('.close')).nativeElement?.disabled).toBeTrue(); + expect(debugElement.query(By.css('.submit')).nativeElement?.getAttribute('aria-disabled')).toBe('true'); + expect(debugElement.query(By.css('.submit')).nativeElement?.classList.contains('disabled')).toBeTrue(); + expect(debugElement.query(By.css('.discard')).nativeElement?.getAttribute('aria-disabled')).toBe('true'); + expect(debugElement.query(By.css('.discard')).nativeElement?.classList.contains('disabled')).toBeTrue(); + expect(debugElement.query(By.css('.close')).nativeElement?.getAttribute('aria-disabled')).toBe('true'); + expect(debugElement.query(By.css('.close')).nativeElement?.classList.contains('disabled')).toBeTrue(); }); }); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.html index 44f21fb4b4..6a39c49c67 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.html @@ -49,6 +49,6 @@ {{ (labelPrefix + 'cancel' | translate) }} - {{ (labelPrefix + 'import' | translate) }} + {{ (labelPrefix + 'import' | translate) }} diff --git a/src/app/shared/form/number-picker/number-picker.component.html b/src/app/shared/form/number-picker/number-picker.component.html index 12e29fa70e..48ace1eabf 100644 --- a/src/app/shared/form/number-picker/number-picker.component.html +++ b/src/app/shared/form/number-picker/number-picker.component.html @@ -3,7 +3,7 @@ class="btn btn-link-focus" type="button" tabindex="0" - [disabled]="disabled" + [dsDisabled]="disabled" (click)="toggleUp()"> {{'form.number-picker.increment' | translate: {field: name} }} @@ -21,7 +21,7 @@ (change)="update($event); $event.stopPropagation();" (focus)="onFocus($event); $event.stopPropagation();" [readonly]="disabled" - [disabled]="disabled" + [dsDisabled]="disabled" [ngClass]="{'is-invalid': invalid}" title="{{placeholder}}" [attr.aria-label]="placeholder" @@ -30,7 +30,7 @@ class="btn btn-link-focus" type="button" tabindex="0" - [disabled]="disabled" + [dsDisabled]="disabled" (click)="toggleDown()"> {{'form.number-picker.decrement' | translate: {field: name} }} diff --git a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html index d06bbe7ad7..cb66544e04 100644 --- a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html +++ b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html @@ -5,7 +5,7 @@ - + {{'vocabulary-treeview.search.form.search' | translate}} @@ -39,7 +39,7 @@ container="body" > {{ (message | async) | translate }} {{"login.form.submit" | translate}} + [dsDisabled]="!form.valid"> {{"login.form.submit" | translate}} diff --git a/src/app/shared/mydspace-actions/claimed-task/approve/claimed-task-actions-approve.component.html b/src/app/shared/mydspace-actions/claimed-task/approve/claimed-task-actions-approve.component.html index 9e364ac808..a672763a86 100644 --- a/src/app/shared/mydspace-actions/claimed-task/approve/claimed-task-actions-approve.component.html +++ b/src/app/shared/mydspace-actions/claimed-task/approve/claimed-task-actions-approve.component.html @@ -1,7 +1,7 @@ {{'submission.workflow.tasks.generic.processing' | translate}} {{'submission.workflow.tasks.claimed.approve' | translate}} diff --git a/src/app/shared/mydspace-actions/claimed-task/decline-task/claimed-task-actions-decline-task.component.html b/src/app/shared/mydspace-actions/claimed-task/decline-task/claimed-task-actions-decline-task.component.html index 2b95b02df4..b942d2b19c 100644 --- a/src/app/shared/mydspace-actions/claimed-task/decline-task/claimed-task-actions-decline-task.component.html +++ b/src/app/shared/mydspace-actions/claimed-task/decline-task/claimed-task-actions-decline-task.component.html @@ -1,5 +1,5 @@ diff --git a/src/app/shared/mydspace-actions/claimed-task/reject/claimed-task-actions-reject.component.html b/src/app/shared/mydspace-actions/claimed-task/reject/claimed-task-actions-reject.component.html index 2f96c16f08..d6e4c95ee9 100644 --- a/src/app/shared/mydspace-actions/claimed-task/reject/claimed-task-actions-reject.component.html +++ b/src/app/shared/mydspace-actions/claimed-task/reject/claimed-task-actions-reject.component.html @@ -1,7 +1,7 @@ {{'submission.workflow.tasks.generic.processing' | translate}} {{'submission.workflow.tasks.claimed.reject.submit' | translate}} @@ -28,7 +28,7 @@ placeholder="{{'submission.workflow.tasks.claimed.reject.reason.placeholder' | translate}}"> {{'submission.workflow.tasks.generic.processing' | translate}} {{'submission.workflow.tasks.claimed.reject.reason.submit' | translate}} diff --git a/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.html b/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.html index e10dec2e6e..60ff5f39ce 100644 --- a/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.html +++ b/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.html @@ -1,7 +1,7 @@ {{'submission.workflow.tasks.generic.processing' | translate}} {{'submission.workflow.tasks.claimed.return' | translate}} diff --git a/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.html b/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.html index 1d98934011..926effa95d 100644 --- a/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.html +++ b/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.html @@ -1,5 +1,5 @@ {{'submission.workflow.tasks.generic.processing' | translate}} diff --git a/src/app/shared/object-select/collection-select/collection-select.component.html b/src/app/shared/object-select/collection-select/collection-select.component.html index f5f8b9d1cc..9bfe3e1156 100644 --- a/src/app/shared/object-select/collection-select/collection-select.component.html +++ b/src/app/shared/object-select/collection-select/collection-select.component.html @@ -34,7 +34,7 @@ {{confirmButton | translate}} diff --git a/src/app/shared/object-select/item-select/item-select.component.spec.ts b/src/app/shared/object-select/item-select/item-select.component.spec.ts index 86d4b5c8d4..6bd27a4ece 100644 --- a/src/app/shared/object-select/item-select/item-select.component.spec.ts +++ b/src/app/shared/object-select/item-select/item-select.component.spec.ts @@ -28,6 +28,7 @@ import { SearchConfigurationServiceStub } from '../../testing/search-configurati import { createPaginatedList } from '../../testing/utils.test'; import { ObjectSelectService } from '../object-select.service'; import { ItemSelectComponent } from './item-select.component'; +import {DisabledDirective} from '../../disabled-directive'; describe('ItemSelectComponent', () => { let comp: ItemSelectComponent; @@ -101,7 +102,7 @@ describe('ItemSelectComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([])], + imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), DisabledDirective], providers: [ { provide: ObjectSelectService, useValue: new ObjectSelectServiceStub([mockItemList[1].id]) }, { provide: HostWindowService, useValue: new HostWindowServiceStub(0) }, @@ -196,7 +197,9 @@ describe('ItemSelectComponent', () => { const checkbox = fixture.debugElement.query(By.css('input.item-checkbox')).nativeElement; expect(authorizationDataService.isAuthorized).toHaveBeenCalled(); - expect(checkbox.disabled).toBeTrue(); + expect(checkbox.getAttribute('aria-disabled')).toBe('true'); + expect(checkbox.classList.contains('disabled')).toBe(true); + }); })); }); }); diff --git a/src/app/shared/pagination/pagination.component.html b/src/app/shared/pagination/pagination.component.html index 9ae978c41b..b3fb746945 100644 --- a/src/app/shared/pagination/pagination.component.html +++ b/src/app/shared/pagination/pagination.component.html @@ -41,7 +41,7 @@ + [dsDisabled]="(objects?.payload?.currentPage <= 1) && (paginationOptions?.currentPage <= 1)"> {{'pagination.previous.button' |translate}} = objects?.payload?.totalPages) || (paginationOptions?.currentPage >= objects?.payload?.totalPages)"> + [dsDisabled]="(objects?.payload?.currentPage >= objects?.payload?.totalPages) || (paginationOptions?.currentPage >= objects?.payload?.totalPages)"> = objects?.payload?.totalPages ? ('pagination.next.button.disabled.tooltip' |translate) : null"> {{'pagination.next.button' |translate}} diff --git a/src/app/shared/resource-policies/form/resource-policy-form.component.spec.ts b/src/app/shared/resource-policies/form/resource-policy-form.component.spec.ts index 4820941c9f..3ae04a9e94 100644 --- a/src/app/shared/resource-policies/form/resource-policy-form.component.spec.ts +++ b/src/app/shared/resource-policies/form/resource-policy-form.component.spec.ts @@ -68,6 +68,7 @@ import { ResourcePolicyEvent, ResourcePolicyFormComponent, } from './resource-policy-form.component'; +import {DisabledDirective} from '../../disabled-directive'; export const mockResourcePolicyFormData = { name: [ @@ -216,6 +217,7 @@ describe('ResourcePolicyFormComponent test suite', () => { ResourcePolicyFormComponent, TestComponent, NgxMaskModule.forRoot(), + DisabledDirective ], providers: [ { provide: ActivatedRoute, useValue: activatedRouteStub }, @@ -426,7 +428,8 @@ describe('ResourcePolicyFormComponent test suite', () => { const depositBtn: any = fixture.debugElement.query(By.css('.btn-primary')); - expect(depositBtn.nativeElement.disabled).toBeFalsy(); + expect(depositBtn.nativeElement.getAttribute('aria-disabled')).toBe('false'); + expect(depositBtn.nativeElement.classList.contains('disabled')).toBeFalse(); }); it('should emit submit event', () => { @@ -480,7 +483,8 @@ describe('ResourcePolicyFormComponent test suite', () => { const depositBtn: any = fixture.debugElement.query(By.css('.btn-primary')); - expect(depositBtn.nativeElement.disabled).toBeTruthy(); + expect(depositBtn.nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(depositBtn.nativeElement.classList.contains('disabled')).toBeTrue(); }); }); diff --git a/src/app/shared/subscriptions/subscription-modal/subscription-modal.component.html b/src/app/shared/subscriptions/subscription-modal/subscription-modal.component.html index e0bbc1a609..f44dc2ce3f 100644 --- a/src/app/shared/subscriptions/subscription-modal/subscription-modal.component.html +++ b/src/app/shared/subscriptions/subscription-modal/subscription-modal.component.html @@ -34,7 +34,7 @@ (click)="activeModal.close()"> {{'subscriptions.modal.close' | translate}} - + {{'subscriptions.modal.new-subscription-form.processing' | translate}} diff --git a/src/app/shared/subscriptions/subscription-view/subscription-view.component.html b/src/app/shared/subscriptions/subscription-view/subscription-view.component.html index 8934b8476f..986b4f3dc8 100644 --- a/src/app/shared/subscriptions/subscription-view/subscription-view.component.html +++ b/src/app/shared/subscriptions/subscription-view/subscription-view.component.html @@ -21,7 +21,7 @@ - diff --git a/src/app/shared/upload/uploader/uploader.component.html b/src/app/shared/upload/uploader/uploader.component.html index b1fd8199d8..d7795942be 100644 --- a/src/app/shared/upload/uploader/uploader.component.html +++ b/src/app/shared/upload/uploader/uploader.component.html @@ -35,7 +35,7 @@ {{'uploader.queue-length' | translate}}: {{ uploader?.queue?.length }} | {{ uploader?.queue[0]?.file.name }} - + diff --git a/src/app/submission/form/collection/submission-form-collection.component.spec.ts b/src/app/submission/form/collection/submission-form-collection.component.spec.ts index 540c2ba561..a1ff8acce3 100644 --- a/src/app/submission/form/collection/submission-form-collection.component.spec.ts +++ b/src/app/submission/form/collection/submission-form-collection.component.spec.ts @@ -43,6 +43,7 @@ import { createTestComponent } from '../../../shared/testing/utils.test'; import { SectionsService } from '../../sections/sections.service'; import { SubmissionService } from '../../submission.service'; import { SubmissionFormCollectionComponent } from './submission-form-collection.component'; +import {DisabledDirective} from '../../../shared/disabled-directive'; describe('SubmissionFormCollectionComponent Component', () => { @@ -152,6 +153,7 @@ describe('SubmissionFormCollectionComponent Component', () => { TranslateModule.forRoot(), SubmissionFormCollectionComponent, TestComponent, + DisabledDirective ], providers: [ { provide: DSONameService, useValue: new DSONameServiceMock() }, @@ -275,7 +277,8 @@ describe('SubmissionFormCollectionComponent Component', () => { it('the dropdown button should be disabled when isReadonly is true', () => { comp.isReadonly = true; fixture.detectChanges(); - expect(dropdowBtn.nativeNode.attributes.disabled).toBeDefined(); + expect(dropdowBtn.nativeNode.getAttribute('aria-disabled')).toBe('true'); + expect(dropdowBtn.nativeNode.classList.contains('disabled')).toBeTrue(); }); it('should be simulated when the drop-down menu is closed', () => { diff --git a/src/app/submission/form/footer/submission-form-footer.component.spec.ts b/src/app/submission/form/footer/submission-form-footer.component.spec.ts index 4c6d04c970..a430ec81fa 100644 --- a/src/app/submission/form/footer/submission-form-footer.component.spec.ts +++ b/src/app/submission/form/footer/submission-form-footer.component.spec.ts @@ -31,6 +31,7 @@ import { SubmissionServiceStub } from '../../../shared/testing/submission-servic import { createTestComponent } from '../../../shared/testing/utils.test'; import { SubmissionService } from '../../submission.service'; import { SubmissionFormFooterComponent } from './submission-form-footer.component'; +import {DisabledDirective} from '../../../shared/disabled-directive'; const submissionServiceStub: SubmissionServiceStub = new SubmissionServiceStub(); @@ -51,6 +52,7 @@ describe('SubmissionFormFooterComponent', () => { TranslateModule.forRoot(), SubmissionFormFooterComponent, TestComponent, + DisabledDirective ], providers: [ { provide: SubmissionService, useValue: submissionServiceStub }, @@ -227,7 +229,8 @@ describe('SubmissionFormFooterComponent', () => { fixture.detectChanges(); const depositBtn: any = fixture.debugElement.query(By.css('.btn-success')); - expect(depositBtn.nativeElement.disabled).toBeFalsy(); + expect(depositBtn.nativeElement.getAttribute('aria-disabled')).toBe('false'); + expect(depositBtn.nativeElement.classList.contains('disabled')).toBeFalse(); }); it('should not have deposit button disabled when submission is valid', () => { @@ -236,7 +239,8 @@ describe('SubmissionFormFooterComponent', () => { fixture.detectChanges(); const depositBtn: any = fixture.debugElement.query(By.css('.btn-success')); - expect(depositBtn.nativeElement.disabled).toBeFalsy(); + expect(depositBtn.nativeElement.getAttribute('aria-disabled')).toBe('false'); + expect(depositBtn.nativeElement.classList.contains('disabled')).toBeFalse(); }); it('should disable save button when all modifications had been saved', () => { @@ -244,7 +248,8 @@ describe('SubmissionFormFooterComponent', () => { fixture.detectChanges(); const saveBtn: any = fixture.debugElement.query(By.css('#save')); - expect(saveBtn.nativeElement.disabled).toBeTruthy(); + expect(saveBtn.nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(saveBtn.nativeElement.classList.contains('disabled')).toBeTrue(); }); it('should enable save button when there are not saved modifications', () => { @@ -252,7 +257,8 @@ describe('SubmissionFormFooterComponent', () => { fixture.detectChanges(); const saveBtn: any = fixture.debugElement.query(By.css('#save')); - expect(saveBtn.nativeElement.disabled).toBeFalsy(); + expect(saveBtn.nativeElement.getAttribute('aria-disabled')).toBe('false'); + expect(saveBtn.nativeElement.classList.contains('disabled')).toBeFalse(); }); }); diff --git a/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.html b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.html index 0c8c1abeeb..8847507a74 100644 --- a/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.html +++ b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.html @@ -1,6 +1,6 @@ + [dsDisabled]="!submissionCcLicenses"> @@ -81,7 +81,7 @@ - 5" [disabled]="field.id === 'jurisdiction' && defaultJurisdiction !== undefined && defaultJurisdiction !== 'none'"> + 5" [dsDisabled]="field.id === 'jurisdiction' && defaultJurisdiction !== undefined && defaultJurisdiction !== 'none'"> {{ option.label }} diff --git a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.html b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.html index 0cb79e51cb..91b89e8435 100644 --- a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.html +++ b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.html @@ -1,7 +1,7 @@ {{'submission.sections.upload.edit.title' | translate}} - + × diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.html b/src/app/submission/sections/upload/file/section-upload-file.component.html index da83e3f9a0..f8d6b9ca93 100644 --- a/src/app/submission/sections/upload/file/section-upload-file.component.html +++ b/src/app/submission/sections/upload/file/section-upload-file.component.html @@ -35,7 +35,7 @@ diff --git a/src/styles/_global-styles.scss b/src/styles/_global-styles.scss index 765b50ae86..ecdf091689 100644 --- a/src/styles/_global-styles.scss +++ b/src/styles/_global-styles.scss @@ -459,6 +459,17 @@ ngb-accordion { color: darken($danger, 22%); } +// An element that is disabled should not have focus styles to avoid confusion +// It however is still focusable for screen readers and keyboard navigation +.disabled { + pointer-events: none; +} + +.disabled:focus { + outline: none; + box-shadow: none; +} + // Margin utility classes based on DSpace content spacing .mt-cs { margin-top: var(--ds-content-spacing); } .mb-cs { margin-bottom: var(--ds-content-spacing); }
{{ 'collection.delete.text' | translate:{ dso: dsoNameService.getName(dso) } }}
{{'researcher.profile.not.associated' | translate}}