123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- 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, GestureController } from '../../gestures/gesture-controller';
- import { isPresent } from '../../util/util';
- import { KEY_ENTER, KEY_ESCAPE } from '../../platform/key';
- import { NavParams } from '../../navigation/nav-params';
- import { Platform } from '../../platform/platform';
- import { ViewController } from '../../navigation/view-controller';
- /**
- * @hidden
- */
- export class AlertCmp {
- constructor(_viewCtrl, _elementRef, config, gestureCtrl, params, _renderer, _plt) {
- this._viewCtrl = _viewCtrl;
- this._elementRef = _elementRef;
- this._renderer = _renderer;
- this._plt = _plt;
- // gesture blocker is used to disable gestures dynamically
- 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 => {
- // Make sure the class isn't whitespace, otherwise it throws exceptions
- 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() {
- // normalize the data
- 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;
- });
- // An alert can be created with several different inputs. Radios,
- // checkboxes and inputs are all accepted, but they cannot be mixed.
- 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 alert has a text input and it's on a mobile device so we should align
- // the alert up high because we need to leave space for the virtual keboard
- // this also helps prevent the layout getting all messed up from
- // the browser trying to scroll the input into a safe area
- this._renderer.setElementClass(this._elementRef.nativeElement, 'alert-top', true);
- }
- }
- ionViewWillEnter() {
- this.gestureBlocker.block();
- }
- ionViewDidLeave() {
- this.gestureBlocker.unblock();
- }
- ionViewDidEnter() {
- // set focus on the first input or button in the alert
- // note that this does not always work and bring up the keyboard on
- // devices since the focus command must come from the user's touch event
- // and ionViewDidEnter is not in the same callstack as the touch event :(
- const focusableEle = this._elementRef.nativeElement.querySelector('input,button');
- if (focusableEle) {
- setTimeout(() => focusableEle.focus());
- }
- this.enabled = true;
- }
- keyUp(ev) {
- if (this.enabled && this._viewCtrl.isLast()) {
- if (ev.keyCode === KEY_ENTER) {
- if (this.lastClick + 1000 < Date.now()) {
- // do not fire this click if there recently was already a click
- // this can happen when the button has focus and used the enter
- // key to click the button. However, both the click handler and
- // this keyup event will fire, so only allow one of them to go.
- (void 0) /* console.debug */;
- let button = this.d.buttons[this.d.buttons.length - 1];
- this.btnClick(button);
- }
- }
- else if (ev.keyCode === KEY_ESCAPE) {
- (void 0) /* console.debug */;
- this.bdClick();
- }
- }
- }
- btnClick(button) {
- if (!this.enabled) {
- return;
- }
- // keep the time of the most recent button click
- this.lastClick = Date.now();
- let shouldDismiss = true;
- if (button.handler) {
- // a handler has been provided, execute it
- // pass the handler the values from the inputs
- if (button.handler(this.getValues()) === false) {
- // if the return value of the handler is false then do not dismiss
- 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 => 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') {
- // this is an alert with radio buttons (single value select)
- // return the one value which is checked, otherwise undefined
- const checkedInput = this.d.inputs.find(i => i.checked);
- return checkedInput ? checkedInput.value : undefined;
- }
- if (this.inputType === 'checkbox') {
- // this is an alert with checkboxes (multiple value select)
- // return an array of all the checked values
- return this.d.inputs.filter(i => i.checked).map(i => i.value);
- }
- if (this.d.inputs.length === 0) {
- // this is an alert without any options/inputs at all
- return undefined;
- }
- // this is an alert with text inputs
- // return an object of all the values with the input name as the key
- const values = {};
- this.d.inputs.forEach(i => {
- values[i.name] = i.value;
- });
- return values;
- }
- ngOnDestroy() {
- (void 0) /* assert */;
- this.gestureBlocker.destroy();
- }
- }
- AlertCmp.decorators = [
- { type: Component, args: [{
- 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" 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,
- },] },
- ];
- /** @nocollapse */
- AlertCmp.ctorParameters = () => [
- { type: ViewController, },
- { type: ElementRef, },
- { type: Config, },
- { type: GestureController, },
- { type: NavParams, },
- { type: Renderer, },
- { type: Platform, },
- ];
- AlertCmp.propDecorators = {
- 'keyUp': [{ type: HostListener, args: ['body:keyup', ['$event'],] },],
- };
- let alertIds = -1;
- //# sourceMappingURL=alert-component.js.map
|