Skip to content

Commit dcf03fb

Browse files
committed
Merge branch 'live-region-7.6' into live-region-8.0
# Conflicts: # src/app/shared/live-region/live-region.component.ts # src/app/shared/live-region/live-region.service.spec.ts
2 parents 2249464 + 751d689 commit dcf03fb

3 files changed

Lines changed: 67 additions & 17 deletions

File tree

src/app/shared/live-region/live-region.component.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ import { Observable } from 'rxjs';
1111

1212
import { LiveRegionService } from './live-region.service';
1313

14+
/**
15+
* The Live Region Component is an accessibility tool for screenreaders. When a change occurs on a page when the changed
16+
* section is not in focus, a message should be displayed by this component so it can be announced by a screen reader.
17+
*
18+
* This component should not be used directly. Use the {@link LiveRegionService} to add messages.
19+
*/
1420
@Component({
1521
selector: `ds-live-region`,
1622
templateUrl: './live-region.component.html',

src/app/shared/live-region/live-region.service.spec.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@ import {
44
tick,
55
} from '@angular/core/testing';
66

7+
import { UUIDService } from '../../core/shared/uuid.service';
78
import { LiveRegionService } from './live-region.service';
89

910
describe('liveRegionService', () => {
1011
let service: LiveRegionService;
1112

12-
1313
beforeEach(() => {
14-
service = new LiveRegionService();
14+
service = new LiveRegionService(
15+
new UUIDService(),
16+
);
1517
});
1618

1719
describe('addMessage', () => {
@@ -90,6 +92,34 @@ describe('liveRegionService', () => {
9092
expect(results[3]).toEqual([]);
9193
}));
9294

95+
it('should not pop messages added after clearing within timeOut period', fakeAsync(() => {
96+
const results: string[][] = [];
97+
98+
service.getMessages$().subscribe((messages) => {
99+
results.push(messages);
100+
});
101+
102+
expect(results.length).toEqual(1);
103+
expect(results[0]).toEqual([]);
104+
105+
service.addMessage('Message One');
106+
tick(10000);
107+
service.clear();
108+
tick(15000);
109+
service.addMessage('Message Two');
110+
111+
// Message Two should not be cleared after 5 more seconds
112+
tick(5000);
113+
114+
expect(results.length).toEqual(4);
115+
expect(results[3]).toEqual(['Message Two']);
116+
117+
// But should be cleared 30 seconds after it was added
118+
tick(25000);
119+
expect(results.length).toEqual(5);
120+
expect(results[4]).toEqual([]);
121+
}));
122+
93123
it('should respect configured timeOut', fakeAsync(() => {
94124
const results: string[][] = [];
95125

src/app/shared/live-region/live-region.service.ts

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,34 @@ import { Injectable } from '@angular/core';
22
import { BehaviorSubject } from 'rxjs';
33

44
import { environment } from '../../../environments/environment';
5+
import { UUIDService } from '../../core/shared/uuid.service';
56

7+
/**
8+
* The LiveRegionService is responsible for handling the messages that are shown by the {@link LiveRegionComponent}.
9+
* Use this service to add or remove messages to the Live Region.
10+
*/
611
@Injectable({
712
providedIn: 'root',
813
})
914
export class LiveRegionService {
1015

16+
constructor(
17+
protected uuidService: UUIDService,
18+
) {
19+
}
20+
1121
/**
1222
* The duration after which the messages disappear in milliseconds
1323
* @protected
1424
*/
1525
protected messageTimeOutDurationMs: number = environment.liveRegion.messageTimeOutDurationMs;
1626

1727
/**
18-
* Array containing the messages that should be shown in the live region
28+
* Array containing the messages that should be shown in the live region,
29+
* together with a uuid, so they can be uniquely identified
1930
* @protected
2031
*/
21-
protected messages: string[] = [];
32+
protected messages: { message: string, uuid: string }[] = [];
2233

2334
/**
2435
* BehaviorSubject emitting the array with messages every time the array updates
@@ -35,27 +46,28 @@ export class LiveRegionService {
3546
/**
3647
* Returns a copy of the array with the current live region messages
3748
*/
38-
getMessages() {
39-
return [...this.messages];
49+
getMessages(): string[] {
50+
return this.messages.map(messageObj => messageObj.message);
4051
}
4152

4253
/**
4354
* Returns the BehaviorSubject emitting the array with messages every time the array updates
4455
*/
45-
getMessages$() {
56+
getMessages$(): BehaviorSubject<string[]> {
4657
return this.messages$;
4758
}
4859

4960
/**
5061
* Adds a message to the live-region messages array
5162
* @param message
63+
* @return The uuid of the message
5264
*/
53-
addMessage(message: string) {
54-
this.messages.push(message);
65+
addMessage(message: string): string {
66+
const uuid = this.uuidService.generate();
67+
this.messages.push({ message, uuid });
68+
setTimeout(() => this.clearMessageByUUID(uuid), this.messageTimeOutDurationMs);
5569
this.emitCurrentMessages();
56-
57-
// Clear the message once the timeOut has passed
58-
setTimeout(() => this.pop(), this.messageTimeOutDurationMs);
70+
return uuid;
5971
}
6072

6173
/**
@@ -67,12 +79,14 @@ export class LiveRegionService {
6779
}
6880

6981
/**
70-
* Removes the longest living message from the array.
71-
* @protected
82+
* Removes the message with the given UUID from the messages array
83+
* @param uuid The uuid of the message to clear
7284
*/
73-
protected pop() {
74-
if (this.messages.length > 0) {
75-
this.messages.shift();
85+
clearMessageByUUID(uuid: string) {
86+
const index = this.messages.findIndex(messageObj => messageObj.uuid === uuid);
87+
88+
if (index !== -1) {
89+
this.messages.splice(index, 1);
7690
this.emitCurrentMessages();
7791
}
7892
}

0 commit comments

Comments
 (0)