import {
AfterContentInit,
AfterViewInit,
ChangeDetectorRef,
Component,
ContentChild,
ContentChildren,
EventEmitter,
Input,
NgZone,
OnChanges,
OnDestroy,
OnInit,
Output,
QueryList,
Renderer2,
SimpleChanges,
TemplateRef,
ViewChild,
ViewChildren
} from '@angular/core';
import { AnimationEvent } from '../animations/animations.interface';
import { AccordionToggleDirective } from './accordion.directive';
import { removeListeners, removeSubscriptions } from '../helpers';
import { Subscription } from 'rxjs';
/*
*
*/
@Component({
selector: 'mk-accordion-header',
template: ''
})
export class AccordionHeaderComponent {
@ViewChild('templateRef') public templateRef: TemplateRef;
}
/*
*
*/
@Component({
selector: 'mk-accordion-content',
template: ''
})
export class AccordionContentComponent {
@ViewChild('templateRef') public templateRef: TemplateRef;
}
/*
*
*/
@Component({
selector: 'mk-accordion',
template: ''
})
export class AccordionComponent implements OnInit {
public contentTemplateRef: TemplateRef;
public headerStyleColor: string;
public isCollapsing: boolean;
public isCollapsed: boolean;
public index: number;
@Input() public borderColor: string;
@Input() public contentColor: string;
@Input() public contentStyleClass = 'box-body';
@Input() public header: string;
@Input() public headerColor: string;
@Input() public headerColorHover: string;
@Input() public headerStyleClass = 'box-header with-border';
@ContentChild(AccordionHeaderComponent) public accordionHeaderComponent: AccordionHeaderComponent;
@ContentChild(AccordionContentComponent) public accordionContentComponent: AccordionContentComponent;
@ViewChild('templateRef') public templateRef: TemplateRef;
/**
* @method ngOnInit
*/
ngOnInit() {
this.headerStyleColor = this.headerColor;
if (!this.header && !this.accordionHeaderComponent) {
throw new Error('Attribute "header" OR Component "mk-+accordion-header" is required for component "mk-+accordion"');
}
if (this.accordionContentComponent) {
this.contentTemplateRef = this.accordionContentComponent.templateRef;
} else {
this.contentTemplateRef = this.templateRef;
}
}
}
/*
*
*/
@Component({
selector: 'mk-accordion-group',
templateUrl: './accordion.component.html'
})
export class AccordionGroupComponent implements AfterContentInit, AfterViewInit, OnChanges, OnDestroy {
private activeIndex: any = [0];
// @TODO change types for listeners to all files
private listeners: Array = [];
// @TODO change types for subscriptions to all files
private subscriptions: Array = [];
@Input('activeIndex') set _activeIndex(value) {
this.activeIndex = value instanceof Array ? value : [value];
}
@Input() public isMultiple: boolean;
@Input() public styleClass = 'box-group';
@Output() public onCollapseStart = new EventEmitter();
@Output() public onCollapseDone = new EventEmitter();
@ContentChildren(AccordionComponent) public accordionComponents: QueryList;
@ViewChildren(AccordionToggleDirective) private accordionToggleDirectives: QueryList;
/**
* @method constructor
* @param changeDetectorRef [description]
* @param ngZone [description]
* @param renderer2 [description]
*/
constructor(
private changeDetectorRef: ChangeDetectorRef,
private ngZone: NgZone,
private renderer2: Renderer2
) {}
/**
* [headerMouseLeave description]
* @method headerMouseLeave
* @param accordion [description]
*/
public static headerMouseLeave(accordion: AccordionComponent): void {
accordion.headerStyleColor = accordion.headerColor;
}
/**
* [headerMouseEnter description]
* @method headerMouseEnter
* @param accordion [description]
*/
public static headerMouseEnter(accordion: AccordionComponent): void {
if (accordion.headerColorHover) {
accordion.headerStyleColor = accordion.headerColorHover;
}
}
/**
* @method ngAfterViewInit
*/
ngAfterContentInit() {
this.setAccordionsIndex();
this.updateAccordionIsCollapsed();
this.subscriptions.push(this.accordionComponents.changes.subscribe(() => {
this.setAccordionsIndex();
}));
}
/**
* @method ngAfterViewInit
*/
ngAfterViewInit() {
this.setAccordionsToggle();
this.subscriptions.push(this.accordionToggleDirectives.changes.subscribe(() => {
this.setAccordionsToggle();
}));
}
/**
* [ngOnChanges description]
* @method ngOnChanges
* @param changes [description]
* @return [description]
*/
ngOnChanges(changes: SimpleChanges) {
if (changes._activeIndex.firstChange === false) {
this.updateAccordionIsCollapsed();
}
}
/**
* @method ngOnDestroy
*/
ngOnDestroy() {
removeListeners(this.listeners);
removeSubscriptions(this.subscriptions);
}
/**
* [toggleAccordion description]
* @method toggleAccordion
* @param event [description]
* @param toggleIndex [description]
*/
public toggleAccordion(event: Event, toggleIndex: number): void {
event.preventDefault();
const indexOf = this.activeIndex['indexOf'](toggleIndex);
if (indexOf === -1) {
if (this.isMultiple) {
this.activeIndex.push(toggleIndex);
} else {
this.activeIndex = [toggleIndex];
}
} else {
if (this.isMultiple) {
this.activeIndex.splice(indexOf, 1);
} else {
this.activeIndex = [];
}
}
this.updateAccordionIsCollapsed();
}
/**
* [collapseStart description]
* @method collapseStart
* @param event [description]
* @param accordion [description]
*/
public collapseStart(event: AnimationEvent, accordion: AccordionComponent): void {
accordion.isCollapsing = true;
this.onCollapseStart.emit({animationEvent: event, index: accordion.index});
}
/**
* [collapseDone description]
* @method collapseDone
* @param event [description]
* @param accordion [description]
*/
public collapseDone(event: AnimationEvent, accordion: AccordionComponent): void {
accordion.isCollapsing = false;
this.onCollapseDone.emit({animationEvent: event, index: accordion.index});
}
/**
* [setAccordionsIndex description]
* @method setAccordionsIndex
*/
private setAccordionsIndex(): void {
this.accordionComponents.forEach((accordion: AccordionComponent, index: number) => {
accordion.index = index;
});
}
/**
* [setAccordionsToggle description]
* @method setAccordionsToggle
*/
private setAccordionsToggle(): void {
this.listeners = removeListeners(this.listeners);
this.ngZone.runOutsideAngular(() => {
this.accordionToggleDirectives.forEach((accordionToggle: AccordionToggleDirective) => {
this.listeners.push(this.renderer2.listen(accordionToggle.elementRef.nativeElement, 'click', (event) => {
this.toggleAccordion(event, accordionToggle.accordionComponent.index);
this.changeDetectorRef.detectChanges();
}));
this.listeners.push(this.renderer2.listen(accordionToggle.elementRef.nativeElement, 'mouseenter', () => {
AccordionGroupComponent.headerMouseEnter(accordionToggle.accordionComponent);
this.changeDetectorRef.detectChanges();
}));
this.listeners.push(this.renderer2.listen(accordionToggle.elementRef.nativeElement, 'mouseleave', () => {
AccordionGroupComponent.headerMouseLeave(accordionToggle.accordionComponent);
this.changeDetectorRef.detectChanges();
}));
});
});
}
/**
* [updateAccordionIsCollapsed description]
* @method updateAccordionIsCollapsed
*/
private updateAccordionIsCollapsed(): void {
this.accordionComponents.forEach((accordion: AccordionComponent, index: number) => {
accordion.isCollapsed = this.activeIndex.indexOf(index) === -1;
});
}
}