import { Component , ElementRef , HostListener , Renderer , ViewEncapsulation } from '@angular/core' ; import { Config } from '../../config/config' ; import { NON_TEXT_INPUT_REGEX } from '../../util/dom' ; import { BLOCK_ALL , BlockerDelegate , GestureController } from '../../gestures/gesture-controller' ; import { assert , isPresent } from '../../util/util' ; import { KEY_ENTER , KEY_ESCAPE } from '../../platform/key' ; import { NavParams } from '../../navigation/nav-params' ; import { NavOptions } from '../../navigation/nav-util' ; import { Platform } from '../../platform/platform' ; import { ViewController } from '../../navigation/view-controller' ; import { AlertButton , AlertInputOptions , AlertOptions } from './alert-options' ; hidden @ Component ( { selector : 'ion-alert' , template : '<ion-backdrop (click)="bdClick()" [class.backdrop-no-tappable]="!d.enableBackdropDismiss"></ion-backdrop>' + '<div class="alert-wrapper">' + '<div class="alert-head">' + '<h2 id="{{hdrId}}" class="alert-title" *ngIf="d.title" [innerHTML]="d.title"></h2>' + '<h3 id="{{subHdrId}}" class="alert-sub-title" *ngIf="d.subTitle" [innerHTML]="d.subTitle"></h3>' + '</div>' + '<div id="{{msgId}}" class="alert-message" [innerHTML]="d.message"></div>' + '<div *ngIf="d.inputs.length" [ngSwitch]="inputType">' + '<ng-template ngSwitchCase="radio">' + '<div class="alert-radio-group" role="radiogroup" [attr.aria-labelledby]="hdrId" [attr.aria-activedescendant]="activeId">' + '<button ion-button="alert-radio-button" *ngFor="let i of d.inputs" (click)="rbClick(i)" [attr.aria-checked]="i.checked" [disabled]="i.disabled" [attr.id]="i.id" class="alert-tappable alert-radio" role="radio">' + '<div class="alert-radio-icon"><div class="alert-radio-inner"></div></div>' + '<div class="alert-radio-label">' + '{{i.label}}' + '</div>' + '</button>' + '</div>' + '</ng-template>' + '<ng-template ngSwitchCase="checkbox">' + '<div class="alert-checkbox-group">' + '<button ion-button="alert-checkbox-button" *ngFor="let i of d.inputs" (click)="cbClick(i)" [attr.aria-checked]="i.checked" [attr.id]="i.id" [disabled]="i.disabled" class="alert-tappable alert-checkbox" role="checkbox">' + '<div class="alert-checkbox-icon"><div class="alert-checkbox-inner"></div></div>' + '<div class="alert-checkbox-label">' + '{{i.label}}' + '</div>' + '</button>' + '</div>' + '</ng-template>' + '<ng-template ngSwitchDefault>' + '<div class="alert-input-group">' + '<div *ngFor="let i of d.inputs" class="alert-input-wrapper">' + '<input [placeholder]="i.placeholder" [(ngModel)]="i.value" [type]="i.type" dir="auto" [min]="i.min" [max]="i.max" [attr.id]="i.id" [disabled]="i.disabled" class="alert-input">' + '</div>' + '</div>' + '</ng-template>' + '</div>' + '<div class="alert-button-group" [ngClass]="{\'alert-button-group-vertical\':d.buttons.length>2}">' + '<button ion-button="alert-button" *ngFor="let b of d.buttons" (click)="btnClick(b)" [ngClass]="b.cssClass">' + '{{b.text}}' + '</button>' + '</div>' + '</div>' , host : { 'role' : 'dialog' , '[attr.aria-labelledby]' : 'hdrId' , '[attr.aria-describedby]' : 'descId' } , encapsulation : ViewEncapsulation . None , } ) export class AlertCmp { activeId : string ; descId : string ; d : AlertOptions ; enabled : boolean ; hdrId : string ; id : number ; inputType : string ; lastClick : number ; msgId : string ; subHdrId : string ; mode : string ; keyboardResizes : boolean ; gestureBlocker : BlockerDelegate ; constructor ( public _viewCtrl , public _elementRef , config , gestureCtrl , params , private _renderer , private _plt ) { this . gestureBlocker = gestureCtrl . createBlocker ( BLOCK_ALL ) ; this . d = params . data ; this . mode = this . d . mode || config . get ( 'mode' ) ; this . keyboardResizes = config . getBoolean ( 'keyboardResizes' , false ) ; _renderer . setElementClass ( _elementRef . nativeElement , `alert-${ this . mode }` , true ) ; if ( this . d . cssClass ) { this . d . cssClass . split ( ' ' ) . forEach ( cssClass => { if ( cssClass . trim ( ) !== '' ) _renderer . setElementClass ( _elementRef . nativeElement , cssClass , true ) ; } ) ; } this . id = ( ++ alertIds ) ; this . descId = '' ; this . hdrId = 'alert-hdr-' + this . id ; this . subHdrId = 'alert-subhdr-' + this . id ; this . msgId = 'alert-msg-' + this . id ; this . activeId = '' ; this . lastClick = 0 ; if ( this . d . message ) { this . descId = this . msgId ; } else if ( this . d . subTitle ) { this . descId = this . subHdrId ; } if ( ! this . d . message ) { this . d . message = '' ; } } ionViewDidLoad ( ) { const data = this . d ; data . buttons = data . buttons . map ( button => { if ( typeof button === 'string' ) { return { text : button } ; } return button ; } ) ; data . inputs = data . inputs . map ( ( input , index ) => { let r = { type : input . type || 'text' , name : isPresent ( input . name ) ? input . name : index + '' , placeholder : isPresent ( input . placeholder ) ? input . placeholder : '' , value : isPresent ( input . value ) ? input . value : '' , label : input . label , checked : ! ! input . checked , disabled : ! ! input . disabled , id : isPresent ( input . id ) ? input . id : `alert-input-${ this . id }-${ index }` , handler : isPresent ( input . handler ) ? input . handler : null , min : isPresent ( input . min ) ? input . min : null , max : isPresent ( input . max ) ? input . max : null } ; return r ; } ) ; const inputTypes = [ ] ; data . inputs . forEach ( input => { if ( inputTypes . indexOf ( input . type ) < 0 ) { inputTypes . push ( input . type ) ; } } ) ; if ( inputTypes . length > 1 && ( inputTypes . indexOf ( 'checkbox' ) > - 1 || inputTypes . indexOf ( 'radio' ) > - 1 ) ) { console . warn ( `Alert cannot mix input types: ${ ( inputTypes . join ( '/' ) ) }. Please see alert docs for more info.` ) ; } this . inputType = inputTypes . length ? inputTypes [ 0 ] : null ; const checkedInput = this . d . inputs . find ( input => input . checked ) ; if ( checkedInput ) { this . activeId = checkedInput . id ; } const hasTextInput = ( this . d . inputs . length && this . d . inputs . some ( i => ! ( NON_TEXT_INPUT_REGEX . test ( i . type ) ) ) ) ; if ( ! this . keyboardResizes && hasTextInput && this . _plt . is ( 'mobile' ) ) { this . _renderer . setElementClass ( this . _elementRef . nativeElement , 'alert-top' , true ) ; } } ionViewWillEnter ( ) { this . gestureBlocker . block ( ) ; } ionViewDidLeave ( ) { this . gestureBlocker . unblock ( ) ; } ionViewDidEnter ( ) { const focusableEle = this . _elementRef . nativeElement . querySelector ( 'input,button' ) ; if ( focusableEle ) { setTimeout ( ( ) => focusableEle . focus ( ) ) ; } this . enabled = true ; } @ HostListener ( 'body:keyup' , [ '$event' ] ) keyUp ( ev ) { if ( this . enabled && this . _viewCtrl . isLast ( ) ) { if ( ev . keyCode === KEY_ENTER ) { if ( this . lastClick + 1000 < Date . now ( ) ) { console . debug ( `alert, enter button` ) ; let button = this . d . buttons [ this . d . buttons . length - 1 ] ; this . btnClick ( button ) ; } } else if ( ev . keyCode === KEY_ESCAPE ) { console . debug ( `alert, escape button` ) ; this . bdClick ( ) ; } } } btnClick ( button ) { if ( ! this . enabled ) { return ; } this . lastClick = Date . now ( ) ; let shouldDismiss = true ; if ( button . handler ) { if ( button . handler ( this . getValues ( ) ) === false ) { shouldDismiss = false ; } } if ( shouldDismiss ) { this . dismiss ( button . role ) ; } } rbClick ( checkedInput ) { if ( this . enabled ) { this . d . inputs . forEach ( input => { input . checked = ( checkedInput === input ) ; } ) ; this . activeId = checkedInput . id ; if ( checkedInput . handler ) { checkedInput . handler ( checkedInput ) ; } } } cbClick ( checkedInput ) { if ( this . enabled ) { checkedInput . checked = ! checkedInput . checked ; if ( checkedInput . handler ) { checkedInput . handler ( checkedInput ) ; } } } bdClick ( ) { if ( this . enabled && this . d . enableBackdropDismiss ) { var cancelBtn = this . d . buttons . find ( b => ( < AlertButton > b ) . role === 'cancel' ) ; if ( cancelBtn ) { this . btnClick ( cancelBtn ) ; } else { this . dismiss ( 'backdrop' ) ; } } } dismiss ( role ) { const opts = { minClickBlockDuration : 400 } ; return this . _viewCtrl . dismiss ( this . getValues ( ) , role , opts ) ; } getValues ( ) { if ( this . inputType === 'radio' ) { const checkedInput = this . d . inputs . find ( i => i . checked ) ; return checkedInput ? checkedInput . value : undefined ; } if ( this . inputType === 'checkbox' ) { return this . d . inputs . filter ( i => i . checked ) . map ( i => i . value ) ; } if ( this . d . inputs . length === 0 ) { return undefined ; } const values = { } ; this . d . inputs . forEach ( i => { values [ i . name ] = i . value ; } ) ; return values ; } ngOnDestroy ( ) { assert ( this . gestureBlocker . blocked === false , 'gesture blocker must be already unblocked' ) ; this . gestureBlocker . destroy ( ) ; } } let alertIds = - 1 ;