Skip to content

Commit

Permalink
Merge branch 'accessibility-settings-7.6' into accessibility-settings…
Browse files Browse the repository at this point in the history
…-main

# Conflicts:
#	src/app/accessibility/accessibility-settings.service.ts
#	src/app/info/accessibility-settings/accessibility-settings.component.spec.ts
#	src/app/info/accessibility-settings/accessibility-settings.component.ts
#	src/app/info/info.module.ts
#	src/app/shared/notifications/notifications-board/notifications-board.component.ts
  • Loading branch information
AAwouters committed Nov 29, 2024
2 parents ed0fcd9 + cdec488 commit 923d0ff
Show file tree
Hide file tree
Showing 12 changed files with 236 additions and 62 deletions.
8 changes: 0 additions & 8 deletions src/app/accessibility/accessibility-settings.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -375,12 +375,4 @@ describe('accessibilitySettingsService', () => {
});
});

describe('getInputType', () => {
it('should correctly return the input type', () => {
expect(service.getInputType(AccessibilitySetting.NotificationTimeOut)).toEqual('number');
expect(service.getInputType(AccessibilitySetting.LiveRegionTimeOut)).toEqual('number');
expect(service.getInputType('unknownValue' as AccessibilitySetting)).toEqual('text');
});
});

});
6 changes: 6 additions & 0 deletions src/app/accessibility/accessibility-settings.service.stub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,10 @@ export class AccessibilitySettingsServiceStub {
setSettingsInCookie = jasmine.createSpy('setSettingsInCookie');

getInputType = jasmine.createSpy('getInputType').and.returnValue('text');

convertFormValuesToStoredValues = jasmine.createSpy('convertFormValuesToStoredValues').and.returnValue({});

convertStoredValuesToFormValues = jasmine.createSpy('convertStoredValuesToFormValues').and.returnValue({});

getPlaceholder = jasmine.createSpy('getPlaceholder').and.returnValue('placeholder');
}
84 changes: 73 additions & 11 deletions src/app/accessibility/accessibility-settings.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import { getFirstCompletedRemoteData } from '../core/shared/operators';
import {
hasValue,
isNotEmpty,
isNotEmptyOperator,
} from '../shared/empty.util';
import { createSuccessfulRemoteDataObject$ } from '../shared/remote-data.utils';

/**
* Name of the cookie used to store the settings locally
Expand All @@ -34,15 +34,27 @@ export const ACCESSIBILITY_SETTINGS_METADATA_KEY = 'dspace.accessibility.setting

/**
* Enum containing all possible accessibility settings.
* When adding new settings, the {@link AccessibilitySettingsService#getInputType} method and the i18n keys for the
* accessibility settings page should be updated.
* When adding new settings, make sure to add the new setting to the accessibility-settings component.
* The converter methods to convert from stored format to form format (and vice-versa) need to be updated as well.
*/
export enum AccessibilitySetting {
NotificationTimeOut = 'notificationTimeOut',
LiveRegionTimeOut = 'liveRegionTimeOut',
}

export type AccessibilitySettings = { [key in AccessibilitySetting]?: any };
/**
* Type representing an object that contains accessibility settings values.
*/
export type AccessibilitySettings = { [key in AccessibilitySetting]?: string };

/**
* The accessibility settings object format used by the accessibility-settings component form.
*/
export interface AccessibilitySettingsFormValues {
disableNotificationTimeOut: boolean,
notificationTimeOut: string,
liveRegionTimeOut: string,
}

/**
* Service handling the retrieval and configuration of accessibility settings.
Expand Down Expand Up @@ -204,8 +216,8 @@ export class AccessibilitySettingsService {

return this.ePersonService.createPatchFromCache(user).pipe(
take(1),
isNotEmptyOperator(),
switchMap(operations => this.ePersonService.patch(user, operations)),
switchMap(operations =>
isNotEmpty(operations) ? this.ePersonService.patch(user, operations) : createSuccessfulRemoteDataObject$({})),
getFirstCompletedRemoteData(),
map(rd => rd.hasSucceeded),
);
Expand All @@ -223,17 +235,67 @@ export class AccessibilitySettingsService {
}

/**
* Returns the input type that a form should use for the provided {@link AccessibilitySetting}
* Clears all settings in the cookie and attempts to clear settings in metadata.
* Emits true if settings in metadata were cleared and false otherwise.
*/
getInputType(setting: AccessibilitySetting): string {
clearSettings(): Observable<boolean> {
this.setSettingsInCookie({});
return this.setSettingsInAuthenticatedUserMetadata({});

Check warning on line 243 in src/app/accessibility/accessibility-settings.service.ts

View check run for this annotation

Codecov / codecov/patch

src/app/accessibility/accessibility-settings.service.ts#L242-L243

Added lines #L242 - L243 were not covered by tests
}

/**
* Retrieve the placeholder to be used for the provided AccessibilitySetting.
* Returns an empty string when no placeholder is specified for the provided setting.
*/
getPlaceholder(setting: AccessibilitySetting): string {
switch (setting) {

Check warning on line 251 in src/app/accessibility/accessibility-settings.service.ts

View check run for this annotation

Codecov / codecov/patch

src/app/accessibility/accessibility-settings.service.ts#L251

Added line #L251 was not covered by tests
case AccessibilitySetting.NotificationTimeOut:
return 'number';
return millisecondsToSeconds(environment.notifications.timeOut.toString());

Check warning on line 253 in src/app/accessibility/accessibility-settings.service.ts

View check run for this annotation

Codecov / codecov/patch

src/app/accessibility/accessibility-settings.service.ts#L253

Added line #L253 was not covered by tests
case AccessibilitySetting.LiveRegionTimeOut:
return 'number';
return millisecondsToSeconds(environment.liveRegion.messageTimeOutDurationMs.toString());

Check warning on line 255 in src/app/accessibility/accessibility-settings.service.ts

View check run for this annotation

Codecov / codecov/patch

src/app/accessibility/accessibility-settings.service.ts#L255

Added line #L255 was not covered by tests
default:
return 'text';
return '';

Check warning on line 257 in src/app/accessibility/accessibility-settings.service.ts

View check run for this annotation

Codecov / codecov/patch

src/app/accessibility/accessibility-settings.service.ts#L257

Added line #L257 was not covered by tests
}
}

/**
* Convert values in the provided accessibility settings object to values ready to be stored.
*/
convertFormValuesToStoredValues(settings: AccessibilitySettingsFormValues): AccessibilitySettings {
return {

Check warning on line 265 in src/app/accessibility/accessibility-settings.service.ts

View check run for this annotation

Codecov / codecov/patch

src/app/accessibility/accessibility-settings.service.ts#L265

Added line #L265 was not covered by tests
'notificationTimeOut': settings.disableNotificationTimeOut ? '0'
: secondsToMilliseconds(settings.notificationTimeOut),
'liveRegionTimeOut': secondsToMilliseconds(settings.liveRegionTimeOut),
};
}

/**
* Convert values in the provided accessibility settings object to values ready to show in the form.
*/
convertStoredValuesToFormValues(settings: AccessibilitySettings): AccessibilitySettingsFormValues {
return {

Check warning on line 276 in src/app/accessibility/accessibility-settings.service.ts

View check run for this annotation

Codecov / codecov/patch

src/app/accessibility/accessibility-settings.service.ts#L276

Added line #L276 was not covered by tests
disableNotificationTimeOut: parseFloat(settings.notificationTimeOut) === 0,
notificationTimeOut: millisecondsToSeconds(settings.notificationTimeOut),
liveRegionTimeOut: millisecondsToSeconds(settings.liveRegionTimeOut),
};
}

}

function secondsToMilliseconds(secondsStr: string): string {
const seconds = parseFloat(secondsStr);

Check warning on line 286 in src/app/accessibility/accessibility-settings.service.ts

View check run for this annotation

Codecov / codecov/patch

src/app/accessibility/accessibility-settings.service.ts#L286

Added line #L286 was not covered by tests
if (isNaN(seconds)) {
return null;

Check warning on line 288 in src/app/accessibility/accessibility-settings.service.ts

View check run for this annotation

Codecov / codecov/patch

src/app/accessibility/accessibility-settings.service.ts#L288

Added line #L288 was not covered by tests
} else {
return (seconds * 1000).toString();

Check warning on line 290 in src/app/accessibility/accessibility-settings.service.ts

View check run for this annotation

Codecov / codecov/patch

src/app/accessibility/accessibility-settings.service.ts#L290

Added line #L290 was not covered by tests
}
}

function millisecondsToSeconds(millisecondsStr: string): string {
const milliseconds = parseFloat(millisecondsStr);

Check warning on line 295 in src/app/accessibility/accessibility-settings.service.ts

View check run for this annotation

Codecov / codecov/patch

src/app/accessibility/accessibility-settings.service.ts#L295

Added line #L295 was not covered by tests
if (isNaN(milliseconds)) {
return null;

Check warning on line 297 in src/app/accessibility/accessibility-settings.service.ts

View check run for this annotation

Codecov / codecov/patch

src/app/accessibility/accessibility-settings.service.ts#L297

Added line #L297 was not covered by tests
} else {
return (milliseconds / 1000).toString();

Check warning on line 299 in src/app/accessibility/accessibility-settings.service.ts

View check run for this annotation

Codecov / codecov/patch

src/app/accessibility/accessibility-settings.service.ts#L299

Added line #L299 was not covered by tests
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,87 @@
<h2>{{ 'info.accessibility-settings.title' | translate }}</h2>

<form>
<div *ngFor="let setting of accessibilitySettingsOptions" class="form-group row">
<label [for]="setting + 'Input'" class="col-sm-2 col-form-label">
{{ 'info.accessibility-settings.' + setting + '.label' | translate }}
<div class="form-group row">
<label [for]="'disableNotificationTimeOutInput'" class="col-sm-2 col-form-label">
{{ 'info.accessibility-settings.disableNotificationTimeOut.label' | translate }}
</label>

<div class="col-sm-10">
<input [type]="getInputType(setting)" [id]="setting + 'Input'" class="form-control"
[(ngModel)]="formValues[setting]" [ngModelOptions]="{ standalone: true }"
[attr.aria-describedby]="setting + 'Hint'">
<div class="col-sm-5">
<ui-switch [id]="'disableNotificationTimeOutInput'"
[(ngModel)]="formValues.disableNotificationTimeOut"
[ngModelOptions]="{ standalone: true }"
></ui-switch>
</div>

<div class="col-sm-1" *dsContextHelp="{
content: 'info.accessibility-settings.disableNotificationTimeOut.hint',
id: 'disableNotificationTimeOutHelp',
iconPlacement: 'right',
tooltipPlacement: 'right'
}">
</div>
</div>

<div class="form-group row">
<label [for]="'notificationTimeOutInput'" class="col-sm-2 col-form-label">
{{ 'info.accessibility-settings.notificationTimeOut.label' | translate }}
</label>

<small [id]="setting + 'Hint'" class="form-text text-muted">
{{ 'info.accessibility-settings.' + setting + '.hint' | translate }}
</small>
<div class="col-sm-4">
<input [type]="'number'" [id]="'notificationTimeOutInput'" class="form-control"
[placeholder]="getPlaceholder(AccessibilitySetting.NotificationTimeOut)"
[readOnly]="formValues.disableNotificationTimeOut"
[(ngModel)]="formValues.notificationTimeOut" [ngModelOptions]="{ standalone: true }"
[attr.aria-describedby]="'notificationTimeOutHint'">
</div>

<div class="col-sm-1 col-form-label">
{{ 'info.accessibility-settings.notificationTimeOut.unit' | translate }}
</div>

<div class="col-sm-1" *dsContextHelp="{
content: 'info.accessibility-settings.notificationTimeOut.hint',
id: 'notificationTimeOutHelp',
iconPlacement: 'right',
tooltipPlacement: 'right'
}">
</div>
</div>

<div class="form-group row">
<label [for]="'liveRegionTimeOutInput'" class="col-sm-2 col-form-label">
{{ 'info.accessibility-settings.liveRegionTimeOut.label' | translate }}
</label>

<div class="col-sm-4">
<input [type]="'number'" [id]="'liveRegionTimeOutInput'" class="form-control"
[placeholder]="getPlaceholder(AccessibilitySetting.LiveRegionTimeOut)"
[(ngModel)]="formValues.liveRegionTimeOut" [ngModelOptions]="{ standalone: true }"
[attr.aria-describedby]="'liveRegionTimeOutHint'">
</div>

<div class="col-sm-1 col-form-label">
{{ 'info.accessibility-settings.liveRegionTimeOut.unit' | translate }}
</div>

<div class="col-sm-1" *dsContextHelp="{
content: 'info.accessibility-settings.liveRegionTimeOut.hint',
id: 'liveRegionTimeOutHelp',
iconPlacement: 'right',
tooltipPlacement: 'right'
}">
</div>
</div>

<div role="group">
<button type="submit" (click)="saveSettings()" class="btn btn-primary mr-2">
{{ 'info.accessibility-settings.submit' | translate }}
</button>
<button type="reset" (click)="resetSettings()" class="btn btn-warning">
{{ 'info.accessibility-settings.reset' | translate }}
</button>
</div>

<button type="submit" (click)="saveSettings()" class="btn btn-primary">
{{ 'info.accessibility-settings.submit' | translate }}
</button>
</form>

</div>
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@ import {
import { TranslateModule } from '@ngx-translate/core';
import { of } from 'rxjs';

import {
AccessibilitySetting,
AccessibilitySettingsService,
} from '../../accessibility/accessibility-settings.service';
import { AccessibilitySettingsService } from '../../accessibility/accessibility-settings.service';
import { getAccessibilitySettingsServiceStub } from '../../accessibility/accessibility-settings.service.stub';
import { AuthService } from '../../core/auth/auth.service';
import { ContextHelpDirective } from '../../shared/context-help.directive';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { AuthServiceStub } from '../../shared/testing/auth-service.stub';
import { NotificationsServiceStub } from '../../shared/testing/notifications-service.stub';
Expand Down Expand Up @@ -40,6 +38,10 @@ describe('AccessibilitySettingsComponent', () => {
{ provide: NotificationsService, useValue: notificationsService },
],
schemas: [NO_ERRORS_SCHEMA],
}).overrideComponent(AccessibilitySettingsComponent, {
remove: {
imports: [ContextHelpDirective],
},
}).compileComponents();
}));

Expand All @@ -54,19 +56,12 @@ describe('AccessibilitySettingsComponent', () => {
});

describe('On Init', () => {
it('should retrieve all accessibility settings options', () => {
expect(settingsService.getAllAccessibilitySettingKeys).toHaveBeenCalled();
});

it('should retrieve the current settings', () => {
expect(settingsService.getAll).toHaveBeenCalled();
});
});

describe('getInputType', () => {
it('should retrieve the input type for the setting from the service', () => {
component.getInputType(AccessibilitySetting.LiveRegionTimeOut);
expect(settingsService.getInputType).toHaveBeenCalledWith(AccessibilitySetting.LiveRegionTimeOut);
it('should convert retrieved settings to form format', () => {
expect(settingsService.convertStoredValuesToFormValues).toHaveBeenCalled();
});
});

Expand All @@ -77,6 +72,12 @@ describe('AccessibilitySettingsComponent', () => {
expect(settingsService.setSettings).toHaveBeenCalled();
});

it('should convert form settings to stored format', () => {
settingsService.setSettings = jasmine.createSpy('setSettings').and.returnValue(of('cookie'));
component.saveSettings();
expect(settingsService.convertFormValuesToStoredValues).toHaveBeenCalled();
});

it('should give the user a notification mentioning where the settings were saved', () => {
settingsService.setSettings = jasmine.createSpy('setSettings').and.returnValue(of('cookie'));
component.saveSettings();
Expand Down
Loading

0 comments on commit 923d0ff

Please sign in to comment.