mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-08 02:24:11 +00:00
118220: Add live-region service and component
This commit is contained in:
@@ -380,3 +380,17 @@ vocabularies:
|
||||
comcolSelectionSort:
|
||||
sortField: 'dc.title'
|
||||
sortDirection: 'ASC'
|
||||
|
||||
# Live Region configuration
|
||||
# Live Region as defined by w3c, https://www.w3.org/TR/wai-aria-1.1/#terms:
|
||||
# Live regions are perceivable regions of a web page that are typically updated as a
|
||||
# result of an external event when user focus may be elsewhere.
|
||||
#
|
||||
# The DSpace live region is a component present at the bottom of all pages that is invisible by default, but is useful
|
||||
# for screen readers. Any message pushed to the live region will be announced by the screen reader. These messages
|
||||
# usually contain information about changes on the page that might not be in focus.
|
||||
liveRegion:
|
||||
# The duration after which messages disappear from the live region in milliseconds
|
||||
messageTimeOutDurationMs: 30000
|
||||
# The visibility of the live region. Setting this to true is only useful for debugging purposes.
|
||||
isVisible: false
|
||||
|
3
src/app/shared/live-region/live-region.component.html
Normal file
3
src/app/shared/live-region/live-region.component.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<div class="live-region" [ngClass]="{'visually-hidden': !isVisible }" aria-live="assertive" role="log" aria-relevant="additions" aria-atomic="true">
|
||||
<div class="live-region-message" *ngFor="let message of (messages$ | async)">{{ message }}</div>
|
||||
</div>
|
13
src/app/shared/live-region/live-region.component.scss
Normal file
13
src/app/shared/live-region/live-region.component.scss
Normal file
@@ -0,0 +1,13 @@
|
||||
.live-region {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding-left: 60px;
|
||||
height: 90px;
|
||||
line-height: 18px;
|
||||
color: var(--bs-white);
|
||||
background-color: var(--bs-dark);
|
||||
opacity: 0.94;
|
||||
z-index: var(--ds-live-region-z-index);
|
||||
}
|
25
src/app/shared/live-region/live-region.component.ts
Normal file
25
src/app/shared/live-region/live-region.component.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { LiveRegionService } from './live-region.service';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: `ds-live-region`,
|
||||
templateUrl: './live-region.component.html',
|
||||
styleUrls: ['./live-region.component.scss'],
|
||||
})
|
||||
export class LiveRegionComponent implements OnInit {
|
||||
|
||||
protected isVisible: boolean;
|
||||
|
||||
protected messages$: Observable<string[]>;
|
||||
|
||||
constructor(
|
||||
protected liveRegionService: LiveRegionService,
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.isVisible = this.liveRegionService.getLiveRegionVisibility();
|
||||
this.messages$ = this.liveRegionService.getMessages$();
|
||||
}
|
||||
}
|
9
src/app/shared/live-region/live-region.config.ts
Normal file
9
src/app/shared/live-region/live-region.config.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Config } from '../../../config/config.interface';
|
||||
|
||||
/**
|
||||
* Configuration interface used by the LiveRegionService
|
||||
*/
|
||||
export class LiveRegionConfig implements Config {
|
||||
messageTimeOutDurationMs: number;
|
||||
isVisible: boolean;
|
||||
}
|
118
src/app/shared/live-region/live-region.service.ts
Normal file
118
src/app/shared/live-region/live-region.service.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { environment } from '../../../environments/environment';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class LiveRegionService {
|
||||
|
||||
/**
|
||||
* The duration after which the messages disappear in milliseconds
|
||||
* @protected
|
||||
*/
|
||||
protected messageTimeOutDurationMs: number = environment.liveRegion.messageTimeOutDurationMs;
|
||||
|
||||
/**
|
||||
* Array containing the messages that should be shown in the live region
|
||||
* @protected
|
||||
*/
|
||||
protected messages: string[] = [];
|
||||
|
||||
/**
|
||||
* BehaviorSubject emitting the array with messages every time the array updates
|
||||
* @protected
|
||||
*/
|
||||
protected messages$: BehaviorSubject<string[]> = new BehaviorSubject([]);
|
||||
|
||||
/**
|
||||
* Whether the live region should be visible
|
||||
* @protected
|
||||
*/
|
||||
protected liveRegionIsVisible: boolean = environment.liveRegion.isVisible;
|
||||
|
||||
/**
|
||||
* Returns a copy of the array with the current live region messages
|
||||
*/
|
||||
getMessages() {
|
||||
return [...this.messages];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the BehaviorSubject emitting the array with messages every time the array updates
|
||||
*/
|
||||
getMessages$() {
|
||||
return this.messages$;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a message to the live-region messages array
|
||||
* @param message
|
||||
*/
|
||||
addMessage(message: string) {
|
||||
this.messages.push(message);
|
||||
this.emitCurrentMessages();
|
||||
|
||||
// Clear the message once the timeOut has passed
|
||||
setTimeout(() => this.pop(), this.messageTimeOutDurationMs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the live-region messages array
|
||||
*/
|
||||
clear() {
|
||||
this.messages = [];
|
||||
this.emitCurrentMessages();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the longest living message from the array.
|
||||
* @protected
|
||||
*/
|
||||
protected pop() {
|
||||
if (this.messages.length > 0) {
|
||||
this.messages.shift();
|
||||
this.emitCurrentMessages();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the messages$ BehaviorSubject emit the current messages array
|
||||
* @protected
|
||||
*/
|
||||
protected emitCurrentMessages() {
|
||||
this.messages$.next(this.getMessages());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean specifying whether the live region should be visible.
|
||||
* Returns 'true' if the region should be visible and false otherwise.
|
||||
*/
|
||||
getLiveRegionVisibility(): boolean {
|
||||
return this.liveRegionIsVisible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the visibility of the live region.
|
||||
* Setting this to true will make the live region visible which is useful for debugging purposes.
|
||||
* @param isVisible
|
||||
*/
|
||||
setLiveRegionVisibility(isVisible: boolean) {
|
||||
this.liveRegionIsVisible = isVisible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current message timeOut duration in milliseconds
|
||||
*/
|
||||
getMessageTimeOutMs(): number {
|
||||
return this.messageTimeOutDurationMs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the message timeOut duration
|
||||
* @param timeOutMs the message timeOut duration in milliseconds
|
||||
*/
|
||||
setMessageTimeOutMs(timeOutMs: number) {
|
||||
this.messageTimeOutDurationMs = timeOutMs;
|
||||
}
|
||||
}
|
@@ -284,6 +284,7 @@ import {
|
||||
} from '../item-page/simple/field-components/specific-field/title/themed-item-page-field.component';
|
||||
import { BitstreamListItemComponent } from './object-list/bitstream-list-item/bitstream-list-item.component';
|
||||
import { NgxPaginationModule } from 'ngx-pagination';
|
||||
import { LiveRegionComponent } from './live-region/live-region.component';
|
||||
|
||||
const MODULES = [
|
||||
CommonModule,
|
||||
@@ -465,7 +466,8 @@ const ENTRY_COMPONENTS = [
|
||||
AdvancedClaimedTaskActionRatingComponent,
|
||||
EpersonGroupListComponent,
|
||||
EpersonSearchBoxComponent,
|
||||
GroupSearchBoxComponent
|
||||
GroupSearchBoxComponent,
|
||||
LiveRegionComponent,
|
||||
];
|
||||
|
||||
const PROVIDERS = [
|
||||
|
@@ -22,6 +22,7 @@ import { HomeConfig } from './homepage-config.interface';
|
||||
import { MarkdownConfig } from './markdown-config.interface';
|
||||
import { FilterVocabularyConfig } from './filter-vocabulary-config';
|
||||
import { DiscoverySortConfig } from './discovery-sort.config';
|
||||
import { LiveRegionConfig } from '../app/shared/live-region/live-region.config';
|
||||
|
||||
interface AppConfig extends Config {
|
||||
ui: UIServerConfig;
|
||||
@@ -48,6 +49,7 @@ interface AppConfig extends Config {
|
||||
markdown: MarkdownConfig;
|
||||
vocabularies: FilterVocabularyConfig[];
|
||||
comcolSelectionSort: DiscoverySortConfig;
|
||||
liveRegion: LiveRegionConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -22,6 +22,7 @@ import { HomeConfig } from './homepage-config.interface';
|
||||
import { MarkdownConfig } from './markdown-config.interface';
|
||||
import { FilterVocabularyConfig } from './filter-vocabulary-config';
|
||||
import { DiscoverySortConfig } from './discovery-sort.config';
|
||||
import { LiveRegionConfig } from '../app/shared/live-region/live-region.config';
|
||||
|
||||
export class DefaultAppConfig implements AppConfig {
|
||||
production = false;
|
||||
@@ -432,4 +433,10 @@ export class DefaultAppConfig implements AppConfig {
|
||||
sortField:'dc.title',
|
||||
sortDirection:'ASC',
|
||||
};
|
||||
|
||||
// Live Region configuration, used by the LiveRegionService
|
||||
liveRegion: LiveRegionConfig = {
|
||||
messageTimeOutDurationMs: 30000,
|
||||
isVisible: false,
|
||||
};
|
||||
}
|
||||
|
@@ -313,5 +313,10 @@ export const environment: BuildConfig = {
|
||||
vocabulary: 'srsc',
|
||||
enabled: true
|
||||
}
|
||||
]
|
||||
],
|
||||
|
||||
liveRegion: {
|
||||
messageTimeOutDurationMs: 30000,
|
||||
isVisible: false,
|
||||
},
|
||||
};
|
||||
|
@@ -13,6 +13,7 @@
|
||||
--ds-login-logo-width:72px;
|
||||
--ds-submission-header-z-index: 1001;
|
||||
--ds-submission-footer-z-index: 999;
|
||||
--ds-live-region-z-index: 1030;
|
||||
|
||||
--ds-main-z-index: 1;
|
||||
--ds-nav-z-index: 10;
|
||||
|
Reference in New Issue
Block a user