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

85.39% Statements 76/89
92.3% Branches 12/13
100% Functions 5/5
85.39% Lines 76/89

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 83 84 85 86 87 88 89 901x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 745x 745x 745x 1x 1x 100x 100x 100x 100x 100x       100x 100x 100x 100x 100x 100x 100x 95x 95x 3x   3x 95x 100x 100x 100x 100x                   100x 1x 1x 1x 51x 51x 51x 51x 51x 1x 1x 95x 95x 95x 95x 95x 95x 1x  
/*******************************************************************************
 * Copyright bei
 * Entwicklungs- und Pflegeverbund für das gemeinsame Fachverfahren gefa
 *
 *******************************************************************************/
import {
  ChangeDetectionStrategy,
  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',
  },
  changeDetection: ChangeDetectionStrategy.Default,
  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
    );
  }
}