Skip to content

Commit fe4dcf0

Browse files
committed
Merge branch 'accessibility-settings-7.6' into accessibility-settings-8_x
# Conflicts: # src/app/accessibility/accessibility-settings.service.spec.ts # 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/live-region/live-region.service.ts # src/app/shared/notifications/notifications-board/notifications-board.component.ts
2 parents 6319c9b + c71c666 commit fe4dcf0

13 files changed

Lines changed: 267 additions & 108 deletions

src/app/accessibility/accessibility-settings.service.spec.ts

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import { AuthServiceStub } from '../shared/testing/auth-service.stub';
1717
import {
1818
ACCESSIBILITY_COOKIE,
1919
ACCESSIBILITY_SETTINGS_METADATA_KEY,
20-
AccessibilitySetting,
2120
AccessibilitySettings,
2221
AccessibilitySettingsService,
2322
} from './accessibility-settings.service';
@@ -48,17 +47,6 @@ describe('accessibilitySettingsService', () => {
4847
);
4948
});
5049

51-
describe('getALlAccessibilitySettingsKeys', () => {
52-
it('should return an array containing all accessibility setting names', () => {
53-
const settingNames: AccessibilitySetting[] = [
54-
AccessibilitySetting.NotificationTimeOut,
55-
AccessibilitySetting.LiveRegionTimeOut,
56-
];
57-
58-
expect(service.getAllAccessibilitySettingKeys()).toEqual(settingNames);
59-
});
60-
});
61-
6250
describe('get', () => {
6351
it('should return the setting if it is set', () => {
6452
const settings: AccessibilitySettings = {
@@ -67,7 +55,7 @@ describe('accessibilitySettingsService', () => {
6755

6856
service.getAll = jasmine.createSpy('getAll').and.returnValue(of(settings));
6957

70-
service.get(AccessibilitySetting.NotificationTimeOut, 'default').subscribe(value =>
58+
service.get('notificationTimeOut', 'default').subscribe(value =>
7159
expect(value).toEqual('1000'),
7260
);
7361
});
@@ -79,7 +67,7 @@ describe('accessibilitySettingsService', () => {
7967

8068
service.getAll = jasmine.createSpy('getAll').and.returnValue(of(settings));
8169

82-
service.get(AccessibilitySetting.LiveRegionTimeOut, 'default').subscribe(value =>
70+
service.get('liveRegionTimeOut', 'default').subscribe(value =>
8371
expect(value).toEqual('default'),
8472
);
8573
});
@@ -89,23 +77,23 @@ describe('accessibilitySettingsService', () => {
8977
it('should return the setting as number if the value for the setting can be parsed to a number', () => {
9078
service.get = jasmine.createSpy('get').and.returnValue(of('1000'));
9179

92-
service.getAsNumber(AccessibilitySetting.NotificationTimeOut).subscribe(value =>
80+
service.getAsNumber('notificationTimeOut').subscribe(value =>
9381
expect(value).toEqual(1000),
9482
);
9583
});
9684

9785
it('should return the default value if no value is set for the setting', () => {
9886
service.get = jasmine.createSpy('get').and.returnValue(of(null));
9987

100-
service.getAsNumber(AccessibilitySetting.NotificationTimeOut, 123).subscribe(value =>
88+
service.getAsNumber('notificationTimeOut', 123).subscribe(value =>
10189
expect(value).toEqual(123),
10290
);
10391
});
10492

10593
it('should return the default value if the value for the setting can not be parsed to a number', () => {
10694
service.get = jasmine.createSpy('get').and.returnValue(of('text'));
10795

108-
service.getAsNumber(AccessibilitySetting.NotificationTimeOut, 123).subscribe(value =>
96+
service.getAsNumber('notificationTimeOut', 123).subscribe(value =>
10997
expect(value).toEqual(123),
11098
);
11199
});
@@ -183,7 +171,7 @@ describe('accessibilitySettingsService', () => {
183171
it('should correctly update the chosen setting', () => {
184172
service.updateSettings = jasmine.createSpy('updateSettings');
185173

186-
service.set(AccessibilitySetting.LiveRegionTimeOut, '500');
174+
service.set('liveRegionTimeOut', '500');
187175
expect(service.updateSettings).toHaveBeenCalledWith({ liveRegionTimeOut: '500' });
188176
});
189177
});
@@ -314,7 +302,7 @@ describe('accessibilitySettingsService', () => {
314302
});
315303

316304
it('should set the settings in metadata', () => {
317-
service.setSettingsInMetadata(ePerson, { [AccessibilitySetting.LiveRegionTimeOut]: '500' }).subscribe();
305+
service.setSettingsInMetadata(ePerson, { ['liveRegionTimeOut']: '500' }).subscribe();
318306
expect(ePerson.setMetadata).toHaveBeenCalled();
319307
});
320308

@@ -325,19 +313,19 @@ describe('accessibilitySettingsService', () => {
325313
});
326314

327315
it('should create a patch with the metadata changes', () => {
328-
service.setSettingsInMetadata(ePerson, { [AccessibilitySetting.LiveRegionTimeOut]: '500' }).subscribe();
316+
service.setSettingsInMetadata(ePerson, { ['liveRegionTimeOut']: '500' }).subscribe();
329317
expect(ePersonService.createPatchFromCache).toHaveBeenCalled();
330318
});
331319

332320
it('should send the patch request', () => {
333-
service.setSettingsInMetadata(ePerson, { [AccessibilitySetting.LiveRegionTimeOut]: '500' }).subscribe();
321+
service.setSettingsInMetadata(ePerson, { ['liveRegionTimeOut']: '500' }).subscribe();
334322
expect(ePersonService.patch).toHaveBeenCalled();
335323
});
336324

337325
it('should emit true when the update succeeded', fakeAsync(() => {
338326
ePersonService.patch = jasmine.createSpy().and.returnValue(createSuccessfulRemoteDataObject$({}));
339327

340-
service.setSettingsInMetadata(ePerson, { [AccessibilitySetting.LiveRegionTimeOut]: '500' })
328+
service.setSettingsInMetadata(ePerson, { ['liveRegionTimeOut']: '500' })
341329
.subscribe(value => {
342330
expect(value).toBeTrue();
343331
});
@@ -348,7 +336,7 @@ describe('accessibilitySettingsService', () => {
348336
it('should emit false when the update failed', fakeAsync(() => {
349337
ePersonService.patch = jasmine.createSpy().and.returnValue(createFailedRemoteDataObject$());
350338

351-
service.setSettingsInMetadata(ePerson, { [AccessibilitySetting.LiveRegionTimeOut]: '500' })
339+
service.setSettingsInMetadata(ePerson, { ['liveRegionTimeOut']: '500' })
352340
.subscribe(value => {
353341
expect(value).toBeFalse();
354342
});
@@ -364,7 +352,7 @@ describe('accessibilitySettingsService', () => {
364352
});
365353

366354
it('should store the settings in a cookie', () => {
367-
service.setSettingsInCookie({ [AccessibilitySetting.LiveRegionTimeOut]: '500' });
355+
service.setSettingsInCookie({ ['liveRegionTimeOut']: '500' });
368356
expect(cookieService.set).toHaveBeenCalled();
369357
});
370358

@@ -375,12 +363,4 @@ describe('accessibilitySettingsService', () => {
375363
});
376364
});
377365

378-
describe('getInputType', () => {
379-
it('should correctly return the input type', () => {
380-
expect(service.getInputType(AccessibilitySetting.NotificationTimeOut)).toEqual('number');
381-
expect(service.getInputType(AccessibilitySetting.LiveRegionTimeOut)).toEqual('number');
382-
expect(service.getInputType('unknownValue' as AccessibilitySetting)).toEqual('text');
383-
});
384-
});
385-
386366
});

src/app/accessibility/accessibility-settings.service.stub.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,10 @@ export class AccessibilitySettingsServiceStub {
3232
setSettingsInCookie = jasmine.createSpy('setSettingsInCookie');
3333

3434
getInputType = jasmine.createSpy('getInputType').and.returnValue('text');
35+
36+
convertFormValuesToStoredValues = jasmine.createSpy('convertFormValuesToStoredValues').and.returnValue({});
37+
38+
convertStoredValuesToFormValues = jasmine.createSpy('convertStoredValuesToFormValues').and.returnValue({});
39+
40+
getPlaceholder = jasmine.createSpy('getPlaceholder').and.returnValue('placeholder');
3541
}

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

Lines changed: 90 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ import { getFirstCompletedRemoteData } from '../core/shared/operators';
1919
import {
2020
hasValue,
2121
isNotEmpty,
22-
isNotEmptyOperator,
2322
} from '../shared/empty.util';
23+
import { createSuccessfulRemoteDataObject$ } from '../shared/remote-data.utils';
2424

2525
/**
2626
* Name of the cookie used to store the settings locally
@@ -33,16 +33,30 @@ export const ACCESSIBILITY_COOKIE = 'dsAccessibilityCookie';
3333
export const ACCESSIBILITY_SETTINGS_METADATA_KEY = 'dspace.accessibility.settings';
3434

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

45-
export type AccessibilitySettings = { [key in AccessibilitySetting]?: any };
42+
/**
43+
* Type representing an object that contains accessibility settings values for all accessibility settings.
44+
*/
45+
export type FullAccessibilitySettings = { [key in AccessibilitySetting]: string };
46+
47+
/**
48+
* Type representing an object that contains accessibility settings values for some accessibility settings.
49+
*/
50+
export type AccessibilitySettings = Partial<FullAccessibilitySettings>;
51+
52+
/**
53+
* The accessibility settings object format used by the accessibility-settings component form.
54+
*/
55+
export interface AccessibilitySettingsFormValues {
56+
notificationTimeOutEnabled: boolean,
57+
notificationTimeOut: string,
58+
liveRegionTimeOut: string,
59+
}
4660

4761
/**
4862
* Service handling the retrieval and configuration of accessibility settings.
@@ -62,10 +76,6 @@ export class AccessibilitySettingsService {
6276
) {
6377
}
6478

65-
getAllAccessibilitySettingKeys(): AccessibilitySetting[] {
66-
return Object.entries(AccessibilitySetting).map(([_, val]) => val);
67-
}
68-
6979
/**
7080
* Get the stored value for the provided {@link AccessibilitySetting}. If the value does not exist or if it is empty,
7181
* the provided defaultValue is emitted instead.
@@ -204,8 +214,8 @@ export class AccessibilitySettingsService {
204214

205215
return this.ePersonService.createPatchFromCache(user).pipe(
206216
take(1),
207-
isNotEmptyOperator(),
208-
switchMap(operations => this.ePersonService.patch(user, operations)),
217+
switchMap(operations =>
218+
isNotEmpty(operations) ? this.ePersonService.patch(user, operations) : createSuccessfulRemoteDataObject$({})),
209219
getFirstCompletedRemoteData(),
210220
map(rd => rd.hasSucceeded),
211221
);
@@ -223,17 +233,75 @@ export class AccessibilitySettingsService {
223233
}
224234

225235
/**
226-
* Returns the input type that a form should use for the provided {@link AccessibilitySetting}
236+
* Clears all settings in the cookie and attempts to clear settings in metadata.
237+
* Emits true if settings in metadata were cleared and false otherwise.
238+
*/
239+
clearSettings(): Observable<boolean> {
240+
this.setSettingsInCookie({});
241+
return this.setSettingsInAuthenticatedUserMetadata({});
242+
}
243+
244+
/**
245+
* Retrieve the placeholder to be used for the provided AccessibilitySetting.
246+
* Returns an empty string when no placeholder is specified for the provided setting.
227247
*/
228-
getInputType(setting: AccessibilitySetting): string {
248+
getPlaceholder(setting: AccessibilitySetting): string {
229249
switch (setting) {
230-
case AccessibilitySetting.NotificationTimeOut:
231-
return 'number';
232-
case AccessibilitySetting.LiveRegionTimeOut:
233-
return 'number';
250+
case 'notificationTimeOut':
251+
return millisecondsToSeconds(environment.notifications.timeOut.toString());
252+
case 'liveRegionTimeOut':
253+
return millisecondsToSeconds(environment.liveRegion.messageTimeOutDurationMs.toString());
234254
default:
235-
return 'text';
255+
return '';
236256
}
237257
}
238258

259+
/**
260+
* Convert values in the provided accessibility settings object to values ready to be stored.
261+
*/
262+
convertFormValuesToStoredValues(settings: AccessibilitySettingsFormValues): FullAccessibilitySettings {
263+
return {
264+
notificationTimeOut: settings.notificationTimeOutEnabled ?
265+
secondsToMilliseconds(settings.notificationTimeOut) : '0',
266+
liveRegionTimeOut: secondsToMilliseconds(settings.liveRegionTimeOut),
267+
};
268+
}
269+
270+
/**
271+
* Convert values in the provided accessibility settings object to values ready to show in the form.
272+
*/
273+
convertStoredValuesToFormValues(settings: AccessibilitySettings): AccessibilitySettingsFormValues {
274+
return {
275+
notificationTimeOutEnabled: parseFloat(settings.notificationTimeOut) !== 0,
276+
notificationTimeOut: millisecondsToSeconds(settings.notificationTimeOut),
277+
liveRegionTimeOut: millisecondsToSeconds(settings.liveRegionTimeOut),
278+
};
279+
}
280+
281+
}
282+
283+
/**
284+
* Converts a string representing seconds to a string representing milliseconds
285+
* Returns null if the input could not be parsed to a float
286+
*/
287+
function secondsToMilliseconds(secondsStr: string): string {
288+
const seconds = parseFloat(secondsStr);
289+
if (isNaN(seconds)) {
290+
return null;
291+
} else {
292+
return (seconds * 1000).toString();
293+
}
294+
}
295+
296+
/**
297+
* Converts a string representing milliseconds to a string representing seconds
298+
* Returns null if the input could not be parsed to a float
299+
*/
300+
function millisecondsToSeconds(millisecondsStr: string): string {
301+
const milliseconds = parseFloat(millisecondsStr);
302+
if (isNaN(milliseconds)) {
303+
return null;
304+
} else {
305+
return (milliseconds / 1000).toString();
306+
}
239307
}

0 commit comments

Comments
 (0)