All files / lib/internal/aria-live-reader aria-live-reader.component.ts

84.14% Statements 69/82
92.3% Branches 12/13
100% Functions 5/5
84.14% Lines 69/82

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 831x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 711x 711x 711x 1x 1x 154x 154x 154x 154x 154x       154x 154x 154x 154x 154x 154x 154x 148x 148x 2x   2x 148x 154x 154x 154x 154x                   154x 1x 1x 1x 47x 47x 47x 47x 47x 1x 1x 148x 148x 148x 148x 148x 148x 1x  
/*******************************************************************************
 * Copyright bei
 * Entwicklungs- und Pflegeverbund für das gemeinsame Fachverfahren gefa
 *
 *******************************************************************************/
import { Component, ElementRef, NgZone, OnDestroy } from '@angular/core';
 
export type AriaLiveReadDisposer = (finalText?: string) => void;
 
@Component({
  selector: 'gc-aria-live-reader',
  template: '',
  styleUrls: ['./aria-live-reader.component.css'],
  host: {
    class: 'gc-scr-only',
    // 'aria-atomic': 'true', causes problems on firefox see #2226
    'aria-live': 'polite',
  },
  standalone: false,
})
export class AriaLiveReaderComponent implements OnDestroy {
  private timerId: ReturnType<typeof setTimeout> | undefined;
  private repeatTimerId: ReturnType<typeof setInterval> | undefined;
 
  constructor(
    private readonly zone: NgZone,
    private readonly elementRef: ElementRef<HTMLElement>,
  ) {}
 
  public readText(
    text: string,
    initialDelay = 0,
    interval = 0,
  ): AriaLiveReadDisposer {
    if (interval !== 0 && interval < 500) {
      interval = 500;
      console.log(
        'Interval has be at least 500ms so that a11y tools have a chance to announce',
      );
    }
    this.zone.runOutsideAngular(() => {
      clearTimeout(this.timerId);
      clearInterval(this.repeatTimerId);
 
      this.timerId = setTimeout(() => {
        this.updateText(text, interval);
        if (interval > 0) {
          this.repeatTimerId = this.repeatTimerId = setInterval(() => {
            this.updateText(text, interval);
          }, interval);
        }
      }, initialDelay);
    });
 
    return (finalText?: string) => {
      this.zone.runOutsideAngular(() => {
        clearTimeout(this.timerId);
        clearInterval(this.repeatTimerId);

        if (finalText) {
          this.updateText(finalText, interval);
        }
      });
    };
  }
 
  /** @ignore */
  ngOnDestroy(): void {
    this.zone.runOutsideAngular(() => {
      clearTimeout(this.timerId);
      clearInterval(this.repeatTimerId);
    });
  }
 
  private updateText(text: string, interval: number) {
    this.elementRef.nativeElement.innerText = text;
    setTimeout(
      () => (this.elementRef.nativeElement.innerText = ''),
      Math.min(1000, Math.max(interval - 100, 400)), // the min repeat is 500 make sure we cleared before
    );
  }
}