mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
Merge branch 'accessibility-settings-7.6' into accessibility-settings-main
# 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
This commit is contained in:
@@ -17,7 +17,6 @@ import { AuthServiceStub } from '../shared/testing/auth-service.stub';
|
||||
import {
|
||||
ACCESSIBILITY_COOKIE,
|
||||
ACCESSIBILITY_SETTINGS_METADATA_KEY,
|
||||
AccessibilitySetting,
|
||||
AccessibilitySettings,
|
||||
AccessibilitySettingsService,
|
||||
} from './accessibility-settings.service';
|
||||
@@ -48,17 +47,6 @@ describe('accessibilitySettingsService', () => {
|
||||
);
|
||||
});
|
||||
|
||||
describe('getALlAccessibilitySettingsKeys', () => {
|
||||
it('should return an array containing all accessibility setting names', () => {
|
||||
const settingNames: AccessibilitySetting[] = [
|
||||
AccessibilitySetting.NotificationTimeOut,
|
||||
AccessibilitySetting.LiveRegionTimeOut,
|
||||
];
|
||||
|
||||
expect(service.getAllAccessibilitySettingKeys()).toEqual(settingNames);
|
||||
});
|
||||
});
|
||||
|
||||
describe('get', () => {
|
||||
it('should return the setting if it is set', () => {
|
||||
const settings: AccessibilitySettings = {
|
||||
@@ -67,7 +55,7 @@ describe('accessibilitySettingsService', () => {
|
||||
|
||||
service.getAll = jasmine.createSpy('getAll').and.returnValue(of(settings));
|
||||
|
||||
service.get(AccessibilitySetting.NotificationTimeOut, 'default').subscribe(value =>
|
||||
service.get('notificationTimeOut', 'default').subscribe(value =>
|
||||
expect(value).toEqual('1000'),
|
||||
);
|
||||
});
|
||||
@@ -79,7 +67,7 @@ describe('accessibilitySettingsService', () => {
|
||||
|
||||
service.getAll = jasmine.createSpy('getAll').and.returnValue(of(settings));
|
||||
|
||||
service.get(AccessibilitySetting.LiveRegionTimeOut, 'default').subscribe(value =>
|
||||
service.get('liveRegionTimeOut', 'default').subscribe(value =>
|
||||
expect(value).toEqual('default'),
|
||||
);
|
||||
});
|
||||
@@ -89,7 +77,7 @@ describe('accessibilitySettingsService', () => {
|
||||
it('should return the setting as number if the value for the setting can be parsed to a number', () => {
|
||||
service.get = jasmine.createSpy('get').and.returnValue(of('1000'));
|
||||
|
||||
service.getAsNumber(AccessibilitySetting.NotificationTimeOut).subscribe(value =>
|
||||
service.getAsNumber('notificationTimeOut').subscribe(value =>
|
||||
expect(value).toEqual(1000),
|
||||
);
|
||||
});
|
||||
@@ -97,7 +85,7 @@ describe('accessibilitySettingsService', () => {
|
||||
it('should return the default value if no value is set for the setting', () => {
|
||||
service.get = jasmine.createSpy('get').and.returnValue(of(null));
|
||||
|
||||
service.getAsNumber(AccessibilitySetting.NotificationTimeOut, 123).subscribe(value =>
|
||||
service.getAsNumber('notificationTimeOut', 123).subscribe(value =>
|
||||
expect(value).toEqual(123),
|
||||
);
|
||||
});
|
||||
@@ -105,7 +93,7 @@ describe('accessibilitySettingsService', () => {
|
||||
it('should return the default value if the value for the setting can not be parsed to a number', () => {
|
||||
service.get = jasmine.createSpy('get').and.returnValue(of('text'));
|
||||
|
||||
service.getAsNumber(AccessibilitySetting.NotificationTimeOut, 123).subscribe(value =>
|
||||
service.getAsNumber('notificationTimeOut', 123).subscribe(value =>
|
||||
expect(value).toEqual(123),
|
||||
);
|
||||
});
|
||||
@@ -183,7 +171,7 @@ describe('accessibilitySettingsService', () => {
|
||||
it('should correctly update the chosen setting', () => {
|
||||
service.updateSettings = jasmine.createSpy('updateSettings');
|
||||
|
||||
service.set(AccessibilitySetting.LiveRegionTimeOut, '500');
|
||||
service.set('liveRegionTimeOut', '500');
|
||||
expect(service.updateSettings).toHaveBeenCalledWith({ liveRegionTimeOut: '500' });
|
||||
});
|
||||
});
|
||||
@@ -314,7 +302,7 @@ describe('accessibilitySettingsService', () => {
|
||||
});
|
||||
|
||||
it('should set the settings in metadata', () => {
|
||||
service.setSettingsInMetadata(ePerson, { [AccessibilitySetting.LiveRegionTimeOut]: '500' }).subscribe();
|
||||
service.setSettingsInMetadata(ePerson, { ['liveRegionTimeOut']: '500' }).subscribe();
|
||||
expect(ePerson.setMetadata).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -325,19 +313,19 @@ describe('accessibilitySettingsService', () => {
|
||||
});
|
||||
|
||||
it('should create a patch with the metadata changes', () => {
|
||||
service.setSettingsInMetadata(ePerson, { [AccessibilitySetting.LiveRegionTimeOut]: '500' }).subscribe();
|
||||
service.setSettingsInMetadata(ePerson, { ['liveRegionTimeOut']: '500' }).subscribe();
|
||||
expect(ePersonService.createPatchFromCache).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should send the patch request', () => {
|
||||
service.setSettingsInMetadata(ePerson, { [AccessibilitySetting.LiveRegionTimeOut]: '500' }).subscribe();
|
||||
service.setSettingsInMetadata(ePerson, { ['liveRegionTimeOut']: '500' }).subscribe();
|
||||
expect(ePersonService.patch).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should emit true when the update succeeded', fakeAsync(() => {
|
||||
ePersonService.patch = jasmine.createSpy().and.returnValue(createSuccessfulRemoteDataObject$({}));
|
||||
|
||||
service.setSettingsInMetadata(ePerson, { [AccessibilitySetting.LiveRegionTimeOut]: '500' })
|
||||
service.setSettingsInMetadata(ePerson, { ['liveRegionTimeOut']: '500' })
|
||||
.subscribe(value => {
|
||||
expect(value).toBeTrue();
|
||||
});
|
||||
@@ -348,7 +336,7 @@ describe('accessibilitySettingsService', () => {
|
||||
it('should emit false when the update failed', fakeAsync(() => {
|
||||
ePersonService.patch = jasmine.createSpy().and.returnValue(createFailedRemoteDataObject$());
|
||||
|
||||
service.setSettingsInMetadata(ePerson, { [AccessibilitySetting.LiveRegionTimeOut]: '500' })
|
||||
service.setSettingsInMetadata(ePerson, { ['liveRegionTimeOut']: '500' })
|
||||
.subscribe(value => {
|
||||
expect(value).toBeFalse();
|
||||
});
|
||||
@@ -364,7 +352,7 @@ describe('accessibilitySettingsService', () => {
|
||||
});
|
||||
|
||||
it('should store the settings in a cookie', () => {
|
||||
service.setSettingsInCookie({ [AccessibilitySetting.LiveRegionTimeOut]: '500' });
|
||||
service.setSettingsInCookie({ ['liveRegionTimeOut']: '500' });
|
||||
expect(cookieService.set).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -375,12 +363,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');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
@@ -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');
|
||||
}
|
||||
|
@@ -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
|
||||
@@ -33,16 +33,30 @@ export const ACCESSIBILITY_COOKIE = 'dsAccessibilityCookie';
|
||||
export const ACCESSIBILITY_SETTINGS_METADATA_KEY = 'dspace.accessibility.settings';
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Type containing all possible accessibility settings.
|
||||
* When adding new settings, make sure to add the new setting to the accessibility-settings component form.
|
||||
* 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 AccessibilitySetting = 'notificationTimeOut' | 'liveRegionTimeOut';
|
||||
|
||||
export type AccessibilitySettings = { [key in AccessibilitySetting]?: any };
|
||||
/**
|
||||
* Type representing an object that contains accessibility settings values for all accessibility settings.
|
||||
*/
|
||||
export type FullAccessibilitySettings = { [key in AccessibilitySetting]: string };
|
||||
|
||||
/**
|
||||
* Type representing an object that contains accessibility settings values for some accessibility settings.
|
||||
*/
|
||||
export type AccessibilitySettings = Partial<FullAccessibilitySettings>;
|
||||
|
||||
/**
|
||||
* The accessibility settings object format used by the accessibility-settings component form.
|
||||
*/
|
||||
export interface AccessibilitySettingsFormValues {
|
||||
notificationTimeOutEnabled: boolean,
|
||||
notificationTimeOut: string,
|
||||
liveRegionTimeOut: string,
|
||||
}
|
||||
|
||||
/**
|
||||
* Service handling the retrieval and configuration of accessibility settings.
|
||||
@@ -62,10 +76,6 @@ export class AccessibilitySettingsService {
|
||||
) {
|
||||
}
|
||||
|
||||
getAllAccessibilitySettingKeys(): AccessibilitySetting[] {
|
||||
return Object.entries(AccessibilitySetting).map(([_, val]) => val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stored value for the provided {@link AccessibilitySetting}. If the value does not exist or if it is empty,
|
||||
* the provided defaultValue is emitted instead.
|
||||
@@ -204,8 +214,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),
|
||||
);
|
||||
@@ -223,17 +233,75 @@ 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({});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
case AccessibilitySetting.NotificationTimeOut:
|
||||
return 'number';
|
||||
case AccessibilitySetting.LiveRegionTimeOut:
|
||||
return 'number';
|
||||
case 'notificationTimeOut':
|
||||
return millisecondsToSeconds(environment.notifications.timeOut.toString());
|
||||
case 'liveRegionTimeOut':
|
||||
return millisecondsToSeconds(environment.liveRegion.messageTimeOutDurationMs.toString());
|
||||
default:
|
||||
return 'text';
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert values in the provided accessibility settings object to values ready to be stored.
|
||||
*/
|
||||
convertFormValuesToStoredValues(settings: AccessibilitySettingsFormValues): FullAccessibilitySettings {
|
||||
return {
|
||||
notificationTimeOut: settings.notificationTimeOutEnabled ?
|
||||
secondsToMilliseconds(settings.notificationTimeOut) : '0',
|
||||
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 {
|
||||
notificationTimeOutEnabled: parseFloat(settings.notificationTimeOut) !== 0,
|
||||
notificationTimeOut: millisecondsToSeconds(settings.notificationTimeOut),
|
||||
liveRegionTimeOut: millisecondsToSeconds(settings.liveRegionTimeOut),
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string representing seconds to a string representing milliseconds
|
||||
* Returns null if the input could not be parsed to a float
|
||||
*/
|
||||
function secondsToMilliseconds(secondsStr: string): string {
|
||||
const seconds = parseFloat(secondsStr);
|
||||
if (isNaN(seconds)) {
|
||||
return null;
|
||||
} else {
|
||||
return (seconds * 1000).toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string representing milliseconds to a string representing seconds
|
||||
* Returns null if the input could not be parsed to a float
|
||||
*/
|
||||
function millisecondsToSeconds(millisecondsStr: string): string {
|
||||
const milliseconds = parseFloat(millisecondsStr);
|
||||
if (isNaN(milliseconds)) {
|
||||
return null;
|
||||
} else {
|
||||
return (milliseconds / 1000).toString();
|
||||
}
|
||||
}
|
||||
|
@@ -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.notificationTimeOutEnabled"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
></ui-switch>
|
||||
</div>
|
||||
|
||||
<small [id]="setting + 'Hint'" class="form-text text-muted">
|
||||
{{ 'info.accessibility-settings.' + setting + '.hint' | translate }}
|
||||
</small>
|
||||
<div class="col-sm-1" *dsContextHelp="{
|
||||
content: 'info.accessibility-settings.disableNotificationTimeOut.hint',
|
||||
id: 'disableNotificationTimeOutHelp',
|
||||
iconPlacement: 'right',
|
||||
tooltipPlacement: 'right'
|
||||
}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" (click)="saveSettings()" class="btn btn-primary">
|
||||
<div class="form-group row">
|
||||
<label [for]="'notificationTimeOutInput'" class="col-sm-2 col-form-label">
|
||||
{{ 'info.accessibility-settings.notificationTimeOut.label' | translate }}
|
||||
</label>
|
||||
|
||||
<div class="col-sm-4">
|
||||
<input [type]="'number'" [id]="'notificationTimeOutInput'" class="form-control"
|
||||
[placeholder]="getPlaceholder('notificationTimeOut')"
|
||||
[readOnly]="!formValues.notificationTimeOutEnabled"
|
||||
[(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('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>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
@@ -6,11 +6,9 @@ import {
|
||||
} from '@angular/core/testing';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { of } from 'rxjs';
|
||||
import { ContextHelpDirective } from 'src/app/shared/context-help.directive';
|
||||
|
||||
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 { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
@@ -40,6 +38,10 @@ describe('AccessibilitySettingsComponent', () => {
|
||||
{ provide: NotificationsService, useValue: notificationsService },
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
}).overrideComponent(AccessibilitySettingsComponent, {
|
||||
remove: {
|
||||
imports: [ContextHelpDirective],
|
||||
},
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
|
@@ -8,16 +8,21 @@ import {
|
||||
TranslateModule,
|
||||
TranslateService,
|
||||
} from '@ngx-translate/core';
|
||||
import { UiSwitchModule } from 'ngx-ui-switch';
|
||||
import { take } from 'rxjs';
|
||||
|
||||
import {
|
||||
AccessibilitySetting,
|
||||
AccessibilitySettings,
|
||||
AccessibilitySettingsFormValues,
|
||||
AccessibilitySettingsService,
|
||||
} from '../../accessibility/accessibility-settings.service';
|
||||
import { AuthService } from '../../core/auth/auth.service';
|
||||
import { ContextHelpDirective } from '../../shared/context-help.directive';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
|
||||
/**
|
||||
* Component providing the form where users can update accessibility settings.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-accessibility-settings',
|
||||
templateUrl: './accessibility-settings.component.html',
|
||||
@@ -25,14 +30,14 @@ import { NotificationsService } from '../../shared/notifications/notifications.s
|
||||
CommonModule,
|
||||
TranslateModule,
|
||||
FormsModule,
|
||||
UiSwitchModule,
|
||||
ContextHelpDirective,
|
||||
],
|
||||
standalone: true,
|
||||
})
|
||||
export class AccessibilitySettingsComponent implements OnInit {
|
||||
|
||||
protected accessibilitySettingsOptions: AccessibilitySetting[];
|
||||
|
||||
protected formValues: AccessibilitySettings = { };
|
||||
protected formValues: AccessibilitySettingsFormValues;
|
||||
|
||||
constructor(
|
||||
protected authService: AuthService,
|
||||
@@ -43,19 +48,41 @@ export class AccessibilitySettingsComponent implements OnInit {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.accessibilitySettingsOptions = this.settingsService.getAllAccessibilitySettingKeys();
|
||||
this.settingsService.getAll().pipe(take(1)).subscribe(currentSettings => {
|
||||
this.formValues = currentSettings;
|
||||
});
|
||||
this.updateFormValues();
|
||||
}
|
||||
|
||||
getInputType(setting: AccessibilitySetting): string {
|
||||
return this.settingsService.getInputType(setting);
|
||||
getPlaceholder(setting: AccessibilitySetting): string {
|
||||
return this.settingsService.getPlaceholder(setting);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the user-configured settings
|
||||
*/
|
||||
saveSettings() {
|
||||
this.settingsService.setSettings(this.formValues).pipe(take(1)).subscribe(location => {
|
||||
const formValues = this.formValues;
|
||||
const convertedValues = this.settingsService.convertFormValuesToStoredValues(formValues);
|
||||
this.settingsService.setSettings(convertedValues).pipe(take(1)).subscribe(location => {
|
||||
this.notificationsService.success(null, this.translateService.instant('info.accessibility-settings.save-notification.' + location));
|
||||
this.updateFormValues();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the form values with the currently stored accessibility settings
|
||||
*/
|
||||
updateFormValues() {
|
||||
this.settingsService.getAll().pipe(take(1)).subscribe(storedSettings => {
|
||||
this.formValues = this.settingsService.convertStoredValuesToFormValues(storedSettings);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets accessibility settings
|
||||
*/
|
||||
resetSettings() {
|
||||
this.settingsService.clearSettings().pipe(take(1)).subscribe(() => {
|
||||
this.notificationsService.success(null, this.translateService.instant('info.accessibility-settings.reset-notification'));
|
||||
this.updateFormValues();
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -36,7 +36,7 @@
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">{{'profile.card.accessibility.header' | translate}}</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-1">{{'profile.card.accessibility.content' | translate}}</div>
|
||||
<ds-alert class="mb-4" [type]="'alert-info'">{{'profile.card.accessibility.content' | translate}}</ds-alert>
|
||||
<a [routerLink]="'/info/accessibility'">{{'profile.card.accessibility.link' | translate}}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -5,6 +5,7 @@ import {
|
||||
waitForAsync,
|
||||
} from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { StoreModule } from '@ngrx/store';
|
||||
import { provideMockStore } from '@ngrx/store/testing';
|
||||
@@ -116,6 +117,7 @@ describe('ProfilePageComponent', () => {
|
||||
RouterModule.forRoot([]),
|
||||
ProfilePageComponent,
|
||||
VarDirective,
|
||||
NoopAnimationsModule,
|
||||
],
|
||||
providers: [
|
||||
{ provide: EPersonDataService, useValue: epersonService },
|
||||
|
@@ -41,6 +41,7 @@ import {
|
||||
getRemoteDataPayload,
|
||||
} from '../core/shared/operators';
|
||||
import { SuggestionsNotificationComponent } from '../notifications/suggestions-notification/suggestions-notification.component';
|
||||
import { AlertComponent } from '../shared/alert/alert.component';
|
||||
import {
|
||||
hasValue,
|
||||
isNotEmpty,
|
||||
@@ -67,6 +68,7 @@ import { ProfilePageSecurityFormComponent } from './profile-page-security-form/p
|
||||
NgForOf,
|
||||
SuggestionsNotificationComponent,
|
||||
RouterModule,
|
||||
AlertComponent,
|
||||
],
|
||||
standalone: true,
|
||||
})
|
||||
|
@@ -9,10 +9,7 @@ import {
|
||||
} from 'rxjs';
|
||||
|
||||
import { environment } from '../../../environments/environment';
|
||||
import {
|
||||
AccessibilitySetting,
|
||||
AccessibilitySettingsService,
|
||||
} from '../../accessibility/accessibility-settings.service';
|
||||
import { AccessibilitySettingsService } from '../../accessibility/accessibility-settings.service';
|
||||
import { UUIDService } from '../../core/shared/uuid.service';
|
||||
|
||||
export const MIN_MESSAGE_DURATION = 200;
|
||||
@@ -141,7 +138,7 @@ export class LiveRegionService {
|
||||
*/
|
||||
getConfiguredMessageTimeOutMs(): Observable<number> {
|
||||
return this.accessibilitySettingsService.getAsNumber(
|
||||
AccessibilitySetting.LiveRegionTimeOut,
|
||||
'liveRegionTimeOut',
|
||||
this.getMessageTimeOutMs(),
|
||||
).pipe(map(timeOut => Math.max(timeOut, MIN_MESSAGE_DURATION)));
|
||||
}
|
||||
|
@@ -16,7 +16,7 @@ import {
|
||||
Store,
|
||||
} from '@ngrx/store';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import difference from 'lodash/difference';
|
||||
import differenceWith from 'lodash/differenceWith';
|
||||
import {
|
||||
BehaviorSubject,
|
||||
Subscription,
|
||||
@@ -24,10 +24,7 @@ import {
|
||||
import { take } from 'rxjs/operators';
|
||||
|
||||
import { INotificationBoardOptions } from '../../../../config/notifications-config.interfaces';
|
||||
import {
|
||||
AccessibilitySetting,
|
||||
AccessibilitySettingsService,
|
||||
} from '../../../accessibility/accessibility-settings.service';
|
||||
import { AccessibilitySettingsService } from '../../../accessibility/accessibility-settings.service';
|
||||
import { AppState } from '../../../app.reducer';
|
||||
import { INotification } from '../models/notification.model';
|
||||
import { NotificationComponent } from '../notification/notification.component';
|
||||
@@ -82,13 +79,13 @@ export class NotificationsBoardComponent implements OnInit, OnDestroy {
|
||||
this.notifications = [];
|
||||
} else if (state.length > this.notifications.length) {
|
||||
// Add
|
||||
const newElem = difference(state, this.notifications);
|
||||
const newElem = differenceWith(state, this.notifications, this.byId);
|
||||
newElem.forEach((notification) => {
|
||||
this.add(notification);
|
||||
});
|
||||
} else {
|
||||
// Remove
|
||||
const delElem = difference(this.notifications, state);
|
||||
const delElem = differenceWith(this.notifications, state, this.byId);
|
||||
delElem.forEach((notification) => {
|
||||
this.notifications = this.notifications.filter((item: INotification) => item.id !== notification.id);
|
||||
|
||||
@@ -98,6 +95,9 @@ export class NotificationsBoardComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
private byId = (notificationA: INotification, notificationB: INotification) =>
|
||||
notificationA.id === notificationB.id;
|
||||
|
||||
// Add the new notification to the notification array
|
||||
add(item: INotification): void {
|
||||
const toBlock: boolean = this.block(item);
|
||||
@@ -108,7 +108,7 @@ export class NotificationsBoardComponent implements OnInit, OnDestroy {
|
||||
|
||||
// It would be a bit better to handle the retrieval of configured settings in the NotificationsService.
|
||||
// Due to circular dependencies this is difficult to implement.
|
||||
this.accessibilitySettingsService.getAsNumber(AccessibilitySetting.NotificationTimeOut, item.options.timeOut)
|
||||
this.accessibilitySettingsService.getAsNumber('notificationTimeOut', item.options.timeOut)
|
||||
.pipe(take(1)).subscribe(timeOut => {
|
||||
if (timeOut < 0) {
|
||||
timeOut = 0;
|
||||
|
@@ -2134,18 +2134,30 @@
|
||||
|
||||
"info.accessibility-settings.breadcrumbs": "Accessibility settings",
|
||||
|
||||
"info.accessibility-settings.disableNotificationTimeOut.label": "Hide notifications automatically",
|
||||
|
||||
"info.accessibility-settings.disableNotificationTimeOut.hint": "When this toggle is activated, notifications will remain until manually closed.",
|
||||
|
||||
"info.accessibility-settings.liveRegionTimeOut.label": "Live region time-out",
|
||||
|
||||
"info.accessibility-settings.liveRegionTimeOut.hint": "The duration in milliseconds after which a message in the live region disappears.",
|
||||
"info.accessibility-settings.liveRegionTimeOut.hint": "The duration after which a message in the live region disappears.",
|
||||
|
||||
"info.accessibility-settings.liveRegionTimeOut.unit": "Seconds",
|
||||
|
||||
"info.accessibility-settings.notificationTimeOut.label": "Notification time-out",
|
||||
|
||||
"info.accessibility-settings.notificationTimeOut.hint": "The duration in milliseconds after which a notification disappears. Set to 0 for notifications to remain indefinitely.",
|
||||
"info.accessibility-settings.notificationTimeOut.hint": "The duration after which a notification disappears.",
|
||||
|
||||
"info.accessibility-settings.notificationTimeOut.unit": "Seconds",
|
||||
|
||||
"info.accessibility-settings.save-notification.cookie": "Successfully saved settings locally.",
|
||||
|
||||
"info.accessibility-settings.save-notification.metadata": "Successfully saved settings on the user profile.",
|
||||
|
||||
"info.accessibility-settings.reset-notification": "Successfully reset settings.",
|
||||
|
||||
"info.accessibility-settings.reset": "Reset accessibility settings",
|
||||
|
||||
"info.accessibility-settings.submit": "Save accessibility settings",
|
||||
|
||||
"info.accessibility-settings.title": "Accessibility settings",
|
||||
@@ -3896,7 +3908,7 @@
|
||||
|
||||
"profile.card.accessibility.header": "Accessibility",
|
||||
|
||||
"profile.card.accessibility.link": "Accessibility Settings Page",
|
||||
"profile.card.accessibility.link": "Go to Accessibility Settings Page",
|
||||
|
||||
"profile.card.identify": "Identify",
|
||||
|
||||
|
@@ -12,6 +12,7 @@ import { ProfilePageComponent as BaseComponent } from '../../../../app/profile-p
|
||||
import { ThemedProfilePageMetadataFormComponent } from '../../../../app/profile-page/profile-page-metadata-form/themed-profile-page-metadata-form.component';
|
||||
import { ProfilePageResearcherFormComponent } from '../../../../app/profile-page/profile-page-researcher-form/profile-page-researcher-form.component';
|
||||
import { ProfilePageSecurityFormComponent } from '../../../../app/profile-page/profile-page-security-form/profile-page-security-form.component';
|
||||
import { AlertComponent } from '../../../../app/shared/alert/alert.component';
|
||||
import { VarDirective } from '../../../../app/shared/utils/var.directive';
|
||||
|
||||
@Component({
|
||||
@@ -32,6 +33,7 @@ import { VarDirective } from '../../../../app/shared/utils/var.directive';
|
||||
NgForOf,
|
||||
SuggestionsNotificationComponent,
|
||||
RouterModule,
|
||||
AlertComponent,
|
||||
],
|
||||
})
|
||||
/**
|
||||
|
Reference in New Issue
Block a user