import { Component , ComponentFactoryResolver , ElementRef , Inject , Type , ViewContainerRef , ViewChild , Renderer2 , ComponentRef , NgZone } from '@angular/core' ; import { Observable , of } from 'rxjs' ; import { DefaultSimpleModalOptionConfig , SimpleModalOptions , SimpleModalOptionsOverrides } from './simple-modal-options' ; import { SimpleModalWrapperComponent } from './simple-modal-wrapper.component' ; import { SimpleModalComponent } from './simple-modal.component' ; import { DraggableDirective } from './simple-modal-draggable.directive' ; /**
 * View container manager which manages a list of modals currently active
 * inside the viewvontainer
 */ @ Component ( { selector : 'simple-modal-holder' , template : '<ng-template #viewContainer></ng-template>' , } ) export class SimpleModalHolderComponent { /**
     * Target viewContainer to insert modals
     */ @ ViewChild ( 'viewContainer' , { read : ViewContainerRef , static : true } ) viewContainer ; type { Array < SimpleModalComponent > } modals : Array < SimpleModalComponent < any , any > > = [ ] ; /**
     * if auto focus is on and no element focused, store it here to be restored back after close
     */ previousActiveElement = null ; param { ComponentFactoryResolver } resolver param renderer param ngZone param defaultSimpleModalOptions constructor ( private resolver , private renderer , private ngZone , @ Inject ( DefaultSimpleModalOptionConfig ) private defaultSimpleModalOptions ) { } param { Type < SimpleModalComponent > } component param { object ? } data param { SimpleModalOptionsOverrides ? } options return { Observable < * > } addModal < T , T1 > ( component , data ? , options ? ) { if ( ! this . viewContainer ) { return of ( null ) ; } const factory = this . resolver . resolveComponentFactory ( SimpleModalWrapperComponent ) ; const componentRef = this . viewContainer . createComponent ( factory ) ; const modalWrapper = < SimpleModalWrapperComponent > ( componentRef . instance ) ; const { ref : _componentRef , component : _component } = modalWrapper . addComponent ( component ) ; _component . options = options = Object . assign ( { } , this . defaultSimpleModalOptions , options ) as SimpleModalOptions ; modalWrapper . modalClasses = options . wrapperDefaultClasses ; this . modals . push ( _component ) ; this . wait ( ) . then ( ( ) => { this . toggleWrapperClass ( modalWrapper . wrapper , options . wrapperClass ) ; this . toggleBodyClass ( options . bodyClass ) ; if ( options . draggable ) { this . setDraggable ( _componentRef , options ) ; } this . wait ( options . animationDuration ) . then ( ( ) => { this . autoFocusFirstElement ( _component . wrapper , options . autoFocus ) ; _component . markAsReady ( ) ; } ) ; } ) ; _component . onClosing ( modal => this . removeModal ( modal ) ) ; this . configureCloseOnClickOutside ( modalWrapper ) ; _component . mapDataObject ( data ) ; return _component . setupObserver ( ) ; } returns { Promise < void > } param closingModal removeModal ( closingModal ) { const options = closingModal . options ; this . toggleWrapperClass ( closingModal . wrapper , options . wrapperClass ) ; return this . wait ( options . animationDuration ) . then ( ( ) => { this . removeModalFromArray ( closingModal ) ; this . toggleBodyClass ( options . bodyClass ) ; this . restorePreviousFocus ( ) ; } ) ; } /**
     * Instructs all open modals to
     */ removeAllModals ( ) { return Promise . all ( this . modals . map ( modal => this . removeModal ( modal ) ) ) ; } param bodyClass private toggleBodyClass ( bodyClass ) { if ( ! bodyClass ) { return ; } const body = document . getElementsByTagName ( 'body' ) [ 0 ] ; const bodyClassItems = bodyClass . split ( ' ' ) ; if ( ! this . modals . length ) { body . classList . remove ( ... bodyClassItems ) ; } else { body . classList . add ( ... bodyClassItems ) ; } } param modalWrapper private configureCloseOnClickOutside ( modalWrapper ) { modalWrapper . onClickOutsideModalContent ( ( ) => { if ( modalWrapper . content . options . closeOnClickOutside ) { modalWrapper . content . close ( ) ; } } ) ; } param componentWrapper param autoFocus private autoFocusFirstElement ( componentWrapper , autoFocus ) { if ( autoFocus ) { const focusable = componentWrapper . nativeElement . querySelectorAll ( 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])' ) ; if ( focusable && focusable . length ) { this . previousActiveElement = document . activeElement ; focusable [ 0 ] . focus ( ) ; } } } /**
     * Restores the last focus is there was one
     */ private restorePreviousFocus ( ) { if ( this . previousActiveElement ) { this . previousActiveElement . focus ( ) ; this . previousActiveElement = null ; } } param modalWrapperEl param wrapperClass private toggleWrapperClass ( modalWrapperEl , wrapperClass ) { const wrapperClassList = modalWrapperEl . nativeElement . classList ; const wrapperClassItems = wrapperClass . split ( ' ' ) ; if ( wrapperClassList . toString ( ) . indexOf ( wrapperClass ) !== - 1 ) { wrapperClassList . remove ( ... wrapperClassItems ) ; } else { wrapperClassList . add ( ... wrapperClassItems ) ; } } param component param options private private setDraggable ( component , options ) { const draggableDirective = new DraggableDirective ( component . location , this . ngZone , this . renderer ) ; draggableDirective . dragTarget = component . location . nativeElement ; draggableDirective . dragHandle = component . instance . handle ? component . instance . handle . nativeElement : undefined ; draggableDirective . ngAfterViewInit ( ) ; component . location . nativeElement . classList . add ( options . draggableClass ) ; } param ms private wait ( ms = 0 ) { return new Promise ( ( resolve , reject ) => { setTimeout ( ( ) => resolve ( ) , ms ) ; } ) ; } param { SimpleModalComponent } component private removeModalFromArray ( component ) { const index = this . modals . indexOf ( component ) ; if ( index > - 1 ) { this . viewContainer . remove ( index ) ; this . modals . splice ( index , 1 ) ; } } }