mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-08 18:44:14 +00:00
118220: Add live-region service and component
This commit is contained in:
@@ -380,3 +380,17 @@ vocabularies:
|
|||||||
comcolSelectionSort:
|
comcolSelectionSort:
|
||||||
sortField: 'dc.title'
|
sortField: 'dc.title'
|
||||||
sortDirection: 'ASC'
|
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';
|
} 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 { BitstreamListItemComponent } from './object-list/bitstream-list-item/bitstream-list-item.component';
|
||||||
import { NgxPaginationModule } from 'ngx-pagination';
|
import { NgxPaginationModule } from 'ngx-pagination';
|
||||||
|
import { LiveRegionComponent } from './live-region/live-region.component';
|
||||||
|
|
||||||
const MODULES = [
|
const MODULES = [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@@ -465,7 +466,8 @@ const ENTRY_COMPONENTS = [
|
|||||||
AdvancedClaimedTaskActionRatingComponent,
|
AdvancedClaimedTaskActionRatingComponent,
|
||||||
EpersonGroupListComponent,
|
EpersonGroupListComponent,
|
||||||
EpersonSearchBoxComponent,
|
EpersonSearchBoxComponent,
|
||||||
GroupSearchBoxComponent
|
GroupSearchBoxComponent,
|
||||||
|
LiveRegionComponent,
|
||||||
];
|
];
|
||||||
|
|
||||||
const PROVIDERS = [
|
const PROVIDERS = [
|
||||||
|
@@ -22,6 +22,7 @@ import { HomeConfig } from './homepage-config.interface';
|
|||||||
import { MarkdownConfig } from './markdown-config.interface';
|
import { MarkdownConfig } from './markdown-config.interface';
|
||||||
import { FilterVocabularyConfig } from './filter-vocabulary-config';
|
import { FilterVocabularyConfig } from './filter-vocabulary-config';
|
||||||
import { DiscoverySortConfig } from './discovery-sort.config';
|
import { DiscoverySortConfig } from './discovery-sort.config';
|
||||||
|
import { LiveRegionConfig } from '../app/shared/live-region/live-region.config';
|
||||||
|
|
||||||
interface AppConfig extends Config {
|
interface AppConfig extends Config {
|
||||||
ui: UIServerConfig;
|
ui: UIServerConfig;
|
||||||
@@ -48,6 +49,7 @@ interface AppConfig extends Config {
|
|||||||
markdown: MarkdownConfig;
|
markdown: MarkdownConfig;
|
||||||
vocabularies: FilterVocabularyConfig[];
|
vocabularies: FilterVocabularyConfig[];
|
||||||
comcolSelectionSort: DiscoverySortConfig;
|
comcolSelectionSort: DiscoverySortConfig;
|
||||||
|
liveRegion: LiveRegionConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -22,6 +22,7 @@ import { HomeConfig } from './homepage-config.interface';
|
|||||||
import { MarkdownConfig } from './markdown-config.interface';
|
import { MarkdownConfig } from './markdown-config.interface';
|
||||||
import { FilterVocabularyConfig } from './filter-vocabulary-config';
|
import { FilterVocabularyConfig } from './filter-vocabulary-config';
|
||||||
import { DiscoverySortConfig } from './discovery-sort.config';
|
import { DiscoverySortConfig } from './discovery-sort.config';
|
||||||
|
import { LiveRegionConfig } from '../app/shared/live-region/live-region.config';
|
||||||
|
|
||||||
export class DefaultAppConfig implements AppConfig {
|
export class DefaultAppConfig implements AppConfig {
|
||||||
production = false;
|
production = false;
|
||||||
@@ -432,4 +433,10 @@ export class DefaultAppConfig implements AppConfig {
|
|||||||
sortField:'dc.title',
|
sortField:'dc.title',
|
||||||
sortDirection:'ASC',
|
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',
|
vocabulary: 'srsc',
|
||||||
enabled: true
|
enabled: true
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
|
||||||
|
liveRegion: {
|
||||||
|
messageTimeOutDurationMs: 30000,
|
||||||
|
isVisible: false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
--ds-login-logo-width:72px;
|
--ds-login-logo-width:72px;
|
||||||
--ds-submission-header-z-index: 1001;
|
--ds-submission-header-z-index: 1001;
|
||||||
--ds-submission-footer-z-index: 999;
|
--ds-submission-footer-z-index: 999;
|
||||||
|
--ds-live-region-z-index: 1030;
|
||||||
|
|
||||||
--ds-main-z-index: 1;
|
--ds-main-z-index: 1;
|
||||||
--ds-nav-z-index: 10;
|
--ds-nav-z-index: 10;
|
||||||
|
Reference in New Issue
Block a user