All files / lib/accordion accordion.component.ts

92.85% Statements 104/112
80% Branches 16/20
85.71% Functions 6/7
92.85% Lines 104/112

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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 1131x 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 1x 1x 1x 15x 15x 15x 1x 1x 1x 15x 15x 15x 15x 15x 15x   15x 15x 1x 1x 1x     1x 1x 1x 1x 1x     1x 1x 1x 1x 1x 1x 1x 4x 4x 4x 4x 4x 1x 1x 3x 1x 1x 2x 2x       4x 1x 1x 1x 2x 2x 2x 2x 2x 2x 2x 2x 1x 1x 2x 1x 2x 2x 2x 2x 1x 1x 1x 1x 1x 45x 45x 1x  
/*******************************************************************************
 * Copyright bei
 * Entwicklungs- und Pflegeverbund für das gemeinsame Fachverfahren gefa
 *
 *******************************************************************************/
import {
  AfterContentInit,
  Component,
  ContentChildren,
  OnDestroy,
  QueryList,
} from '@angular/core';
import { Subscription } from 'rxjs';
 
import { FocusableElementOwner } from '../utils/util.types';
 
import { AccordionPanelComponent } from './accordion-panel.component';
 
/**
 * An `gc-accordion` allows the user have one or more components contained in collapsible containers.
 */
@Component({
  selector: 'gc-accordion',
  templateUrl: './accordion.component.html',
  styleUrls: ['./accordion.component.css'],
  standalone: false,
})
export class AccordionComponent
  implements AfterContentInit, OnDestroy, FocusableElementOwner
{
  /**
   * @ignore
   */
  @ContentChildren(AccordionPanelComponent)
  private panels?: QueryList<AccordionPanelComponent>;
 
  /** @ignore */
  private panelsChangeSubscription?: Subscription;
 
  /** @ignore */
  public ngAfterContentInit(): void {
    if (!this.panels) {
      return;
    }
    const handler = this.attachParent.bind(this);
    this.panels.forEach(handler);
    this.panelsChangeSubscription = this.panels.changes.subscribe(() => {
      this.panels?.forEach(handler);
    });
  }
 
  /** @ignore */
  public ngOnDestroy(): void {
    this.panelsChangeSubscription?.unsubscribe();
  }
 
  public focusChild(): boolean {
    if (this.panels?.first) {
      this.panels.first.focusChild();
      return true;
    } else {
      return false;
    }
  }
 
  /**
   * @ignore
   */
  public _moveFocus(
    curPanel: AccordionPanelComponent,
    action: 'first' | 'last' | 'next' | 'previous',
  ): boolean {
    if (this.panels && this.panels.length > 0) {
      if (action === 'first') {
        this.panels.get(0)?.focusChild();
        return true;
      } else if (action === 'last') {
        this.panels.get(this.panels.length - 1)?.focusChild();
        return true;
      } else {
        return this.moveFocusOnNeighbour(this.panels, curPanel, action);
      }
    }
    return false;
  }
 
  /** @ignore */
  private moveFocusOnNeighbour(
    panels: QueryList<AccordionPanelComponent>,
    curPanel: AccordionPanelComponent,
    action: 'next' | 'previous',
  ): boolean {
    const idx = panels.toArray().findIndex(item => item === curPanel);
    if (idx != -1) {
      if (action === 'previous' && idx - 1 >= 0) {
        panels.get(idx - 1)?.focusChild();
        return true;
      } else if (action === 'next' && idx + 1 < panels.length) {
        panels.get(idx + 1)?.focusChild();
        return true;
      }
    }
    return false;
  }
 
  /**
   * @ignore
   */
  private attachParent(panel: AccordionPanelComponent) {
    panel._parent = this;
  }
}