import { ComponentRef , Injectable , TemplateRef , EventEmitter , Renderer2 , ViewContainerRef , ElementRef } from '@angular/core' ; import { ComponentLoader } from '../utils/component-loader' ; import { ComponentLoaderFactory } from '../utils/component-loader' ; import { ModalBackdropComponent } from './modalBackdrop.component' ; import { ModalContainerComponent } from './modalContainer.component' ; import { MDBModalRef , ClassName , modalConfigDefaults , ModalOptions , TransitionDurations } from './modal.options' ; import { msConfig } from './modalService.config' ; @ Injectable ( ) export class MDBModalService { public config : ModalOptions = modalConfigDefaults ; public onShow : EventEmitter < any > = new EventEmitter ( ) ; public onShown : EventEmitter < any > = new EventEmitter ( ) ; public onHide : EventEmitter < any > = new EventEmitter ( ) ; public onHidden : EventEmitter < any > = new EventEmitter ( ) ; protected isBodyOverflowing = false ; protected originalBodyPadding = 0 ; protected scrollbarWidth = 0 ; protected backdropRef : ComponentRef < ModalBackdropComponent > | any ; private _backdropLoader : ComponentLoader < ModalBackdropComponent > ; private modalsCount = 0 ; private lastDismissReason : any = '' ; private loaders : ComponentLoader < ModalContainerComponent > [ ] = [ ] ; public constructor ( private clf , private el , private v , private r ) { this . _backdropLoader = this . clf . createLoader < ModalBackdropComponent > ( this . el , this . v , this . r ) ; msConfig . serviceInstance = this ; } /** Shows a modal */ show ( content , config ? ) { this . modalsCount ++ ; this . _createLoaders ( ) ; this . config = Object . assign ( { } , modalConfigDefaults , config ) ; this . _showBackdrop ( ) ; this . lastDismissReason = null ; return this . _showModal ( content ) ; } hide ( level ) { if ( this . modalsCount === 1 ) { this . _hideBackdrop ( ) ; this . resetScrollbar ( ) ; } this . modalsCount = this . modalsCount >= 1 ? this . modalsCount - 1 : 0 ; setTimeout ( ( ) => { this . _hideModal ( level ) ; this . removeLoaders ( level ) ; } , this . config . animated ? TransitionDurations . BACKDROP : 0 ) ; } _showBackdrop ( ) { const isBackdropEnabled = this . config . backdrop || this . config . backdrop === 'static' ; const isBackdropInDOM = ! this . backdropRef || ! this . backdropRef . instance . isShown ; if ( this . modalsCount === 1 ) { this . removeBackdrop ( ) ; if ( isBackdropEnabled && isBackdropInDOM ) { this . _backdropLoader . attach ( ModalBackdropComponent ) . to ( 'body' ) . show ( { isAnimated : this . config . animated } ) ; this . backdropRef = this . _backdropLoader . _componentRef ; } } } _hideBackdrop ( ) { if ( ! this . backdropRef ) { return ; } this . backdropRef . instance . isShown = false ; const duration = this . config . animated ? TransitionDurations . BACKDROP : 0 ; setTimeout ( ( ) => this . removeBackdrop ( ) , duration ) ; } _showModal ( content ) { const modalLoader = this . loaders [ this . loaders . length - 1 ] ; const mdbModalRef = new MDBModalRef ( ) ; const modalContainerRef = modalLoader . provide ( { provide : ModalOptions , useValue : this . config } ) . provide ( { provide : MDBModalRef , useValue : mdbModalRef } ) . attach ( ModalContainerComponent ) . to ( 'body' ) . show ( { content , isAnimated : this . config . animated } ) ; modalContainerRef . instance . level = this . getModalsCount ( ) ; mdbModalRef . hide = ( ) => { modalContainerRef . instance . hide ( ) ; } ; mdbModalRef . content = modalLoader . getInnerComponent ( ) || null ; return mdbModalRef ; } _hideModal ( level ) { const modalLoader = this . loaders [ level - 1 ] ; if ( modalLoader ) { modalLoader . hide ( ) ; } } getModalsCount ( ) { return this . modalsCount ; } setDismissReason ( reason ) { this . lastDismissReason = reason ; } protected removeBackdrop ( ) { this . _backdropLoader . hide ( ) ; this . backdropRef = null ; } /** AFTER PR MERGE MODAL.COMPONENT WILL BE USING THIS CODE*/ /** Scroll bar tricks */ internal public checkScrollbar ( ) { this . isBodyOverflowing = document . body . clientWidth < window . innerWidth ; this . scrollbarWidth = this . getScrollbarWidth ( ) ; } public setScrollbar ( ) { if ( ! document ) { return ; } this . originalBodyPadding = parseInt ( window . getComputedStyle ( document . body ) . getPropertyValue ( 'padding-right' ) || '0' , 10 ) ; if ( this . isBodyOverflowing ) { document . body . style . paddingRight = `${ this . originalBodyPadding + this . scrollbarWidth }px` ; } } private resetScrollbar ( ) { document . body . style . paddingRight = this . originalBodyPadding + 'px' ; } private getScrollbarWidth ( ) { const scrollDiv = document . createElement ( 'div' ) ; scrollDiv . className = ClassName . SCROLLBAR_MEASURER ; document . body . appendChild ( scrollDiv ) ; const scrollbarWidth = scrollDiv . offsetWidth - scrollDiv . clientWidth ; document . body . removeChild ( scrollDiv ) ; return scrollbarWidth ; } private _createLoaders ( ) { const loader = this . clf . createLoader < ModalContainerComponent > ( this . el , this . v , this . r ) ; this . copyEvent ( loader . onBeforeShow , this . onShow ) ; this . copyEvent ( loader . onShown , this . onShown ) ; this . copyEvent ( loader . onBeforeHide , this . onHide ) ; this . copyEvent ( loader . onHidden , this . onHidden ) ; this . loaders . push ( loader ) ; } private removeLoaders ( level ) { this . loaders . splice ( level - 1 , 1 ) ; this . loaders . forEach ( ( loader , i ) => { loader . instance . level = i + 1 ; } ) ; } private copyEvent ( from , to ) { from . subscribe ( ( ) => { to . emit ( this . lastDismissReason ) ; } ) ; } }