mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-20 20:33:32 +08:00

BREAKING CHANGES: - Overlay components, such as Alert or Modals, should now be created using its injected provider. - Overlays now have the `present()` method on the overlay’s instance, rather than using `nav.present(overlayInstance)`. - All overlays now present on top of all app content, to include menus. - Below is an example of the change to `Alert`, but the pattern is the same for all overlays: ActionSheet, Loading, Modal, Picker, Popover, Toast WAS: ``` import { NavController, Alert } from ‘ionic-angular’; constructor(private nav: NavController) { } doAlert() { let alert = Alert.create({ title: 'Alert', }); this.nav.present(alert); } ``` NOW: ``` import { AlertController } from ‘ionic-angular’; constructor(private alertCtrl: AlertController) { } doAlert() { let alert = this.alertCtrl.create({ title: 'Alert' }); alert.present(); } ```
263 lines
8.2 KiB
TypeScript
263 lines
8.2 KiB
TypeScript
import { Component, Renderer, ElementRef, HostListener, ViewEncapsulation } from '@angular/core';
|
|
|
|
import { Animation } from '../../animations/animation';
|
|
import { Config } from '../../config/config';
|
|
import { Form } from '../../util/form';
|
|
import { Key } from '../../util/key';
|
|
import { NavParams } from '../nav/nav-params';
|
|
import { Transition, TransitionOptions } from '../../transitions/transition';
|
|
import { ViewController } from '../nav/view-controller';
|
|
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
@Component({
|
|
selector: 'ion-action-sheet',
|
|
template: `
|
|
<ion-backdrop (click)="bdClick()"></ion-backdrop>
|
|
<div class="action-sheet-wrapper">
|
|
<div class="action-sheet-container">
|
|
<div class="action-sheet-group">
|
|
<div class="action-sheet-title" id="{{hdrId}}" *ngIf="d.title">{{d.title}}</div>
|
|
<div class="action-sheet-sub-title" id="{{descId}}" *ngIf="d.subTitle">{{d.subTitle}}</div>
|
|
<button category="action-sheet-button" (click)="click(b)" *ngFor="let b of d.buttons" class="disable-hover" [ngClass]="b.cssClass">
|
|
<ion-icon [name]="b.icon" *ngIf="b.icon" class="action-sheet-icon"></ion-icon>
|
|
{{b.text}}
|
|
</button>
|
|
</div>
|
|
<div class="action-sheet-group" *ngIf="d.cancelButton">
|
|
<button category="action-sheet-button" (click)="click(d.cancelButton)" class="action-sheet-cancel disable-hover" [ngClass]="d.cancelButton.cssClass">
|
|
<ion-icon [name]="d.cancelButton.icon" *ngIf="d.cancelButton.icon" class="action-sheet-icon"></ion-icon>
|
|
{{d.cancelButton.text}}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`,
|
|
host: {
|
|
'role': 'dialog',
|
|
'[attr.aria-labelledby]': 'hdrId',
|
|
'[attr.aria-describedby]': 'descId'
|
|
},
|
|
encapsulation: ViewEncapsulation.None,
|
|
})
|
|
export class ActionSheetCmp {
|
|
private d: any;
|
|
private descId: string;
|
|
private enabled: boolean;
|
|
private hdrId: string;
|
|
private id: number;
|
|
|
|
constructor(
|
|
private _viewCtrl: ViewController,
|
|
private _config: Config,
|
|
private _elementRef: ElementRef,
|
|
private _form: Form,
|
|
params: NavParams,
|
|
renderer: Renderer
|
|
) {
|
|
this.d = params.data;
|
|
|
|
if (this.d.cssClass) {
|
|
renderer.setElementClass(_elementRef.nativeElement, this.d.cssClass, true);
|
|
}
|
|
|
|
this.id = (++actionSheetIds);
|
|
if (this.d.title) {
|
|
this.hdrId = 'acst-hdr-' + this.id;
|
|
}
|
|
if (this.d.subTitle) {
|
|
this.descId = 'acst-subhdr-' + this.id;
|
|
}
|
|
}
|
|
|
|
ionViewLoaded() {
|
|
// normalize the data
|
|
let buttons: any[] = [];
|
|
|
|
this.d.buttons.forEach((button: any) => {
|
|
if (typeof button === 'string') {
|
|
button = { text: button };
|
|
}
|
|
if (!button.cssClass) {
|
|
button.cssClass = '';
|
|
}
|
|
|
|
if (button.role === 'cancel') {
|
|
this.d.cancelButton = button;
|
|
|
|
} else {
|
|
if (button.role === 'destructive') {
|
|
button.cssClass = (button.cssClass + ' ' || '') + 'action-sheet-destructive';
|
|
} else if (button.role === 'selected') {
|
|
button.cssClass = (button.cssClass + ' ' || '') + 'action-sheet-selected';
|
|
}
|
|
buttons.push(button);
|
|
}
|
|
});
|
|
|
|
this.d.buttons = buttons;
|
|
}
|
|
|
|
ionViewDidEnter() {
|
|
this._form.focusOut();
|
|
|
|
let focusableEle = this._elementRef.nativeElement.querySelector('button');
|
|
if (focusableEle) {
|
|
focusableEle.focus();
|
|
}
|
|
this.enabled = true;
|
|
}
|
|
|
|
@HostListener('body:keyup', ['$event'])
|
|
private _keyUp(ev: KeyboardEvent) {
|
|
if (this.enabled && this._viewCtrl.isLast()) {
|
|
if (ev.keyCode === Key.ESCAPE) {
|
|
console.debug('actionsheet, escape button');
|
|
this.bdClick();
|
|
}
|
|
}
|
|
}
|
|
|
|
click(button: any, dismissDelay?: number) {
|
|
if (! this.enabled ) {
|
|
return;
|
|
}
|
|
|
|
let shouldDismiss = true;
|
|
|
|
if (button.handler) {
|
|
// a handler has been provided, execute it
|
|
if (button.handler() === false) {
|
|
// if the return value of the handler is false then do not dismiss
|
|
shouldDismiss = false;
|
|
}
|
|
}
|
|
|
|
if (shouldDismiss) {
|
|
setTimeout(() => {
|
|
this.dismiss(button.role);
|
|
}, dismissDelay || this._config.get('pageTransitionDelay'));
|
|
}
|
|
}
|
|
|
|
bdClick() {
|
|
if (this.enabled && this.d.enableBackdropDismiss) {
|
|
if (this.d.cancelButton) {
|
|
this.click(this.d.cancelButton, 1);
|
|
|
|
} else {
|
|
this.dismiss('backdrop');
|
|
}
|
|
}
|
|
}
|
|
|
|
dismiss(role: any): Promise<any> {
|
|
return this._viewCtrl.dismiss(null, role);
|
|
}
|
|
}
|
|
|
|
|
|
class ActionSheetSlideIn extends Transition {
|
|
constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) {
|
|
super(enteringView, leavingView, opts);
|
|
|
|
let ele = enteringView.pageRef().nativeElement;
|
|
let backdrop = new Animation(ele.querySelector('ion-backdrop'));
|
|
let wrapper = new Animation(ele.querySelector('.action-sheet-wrapper'));
|
|
|
|
backdrop.fromTo('opacity', 0.01, 0.4);
|
|
wrapper.fromTo('translateY', '100%', '0%');
|
|
|
|
this.easing('cubic-bezier(.36,.66,.04,1)').duration(400).add(backdrop).add(wrapper);
|
|
}
|
|
}
|
|
Transition.register('action-sheet-slide-in', ActionSheetSlideIn);
|
|
|
|
|
|
class ActionSheetSlideOut extends Transition {
|
|
constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) {
|
|
super(enteringView, leavingView, opts);
|
|
|
|
let ele = leavingView.pageRef().nativeElement;
|
|
let backdrop = new Animation(ele.querySelector('ion-backdrop'));
|
|
let wrapper = new Animation(ele.querySelector('.action-sheet-wrapper'));
|
|
|
|
backdrop.fromTo('opacity', 0.4, 0);
|
|
wrapper.fromTo('translateY', '0%', '100%');
|
|
|
|
this.easing('cubic-bezier(.36,.66,.04,1)').duration(300).add(backdrop).add(wrapper);
|
|
}
|
|
}
|
|
Transition.register('action-sheet-slide-out', ActionSheetSlideOut);
|
|
|
|
|
|
class ActionSheetMdSlideIn extends Transition {
|
|
constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) {
|
|
super(enteringView, leavingView, opts);
|
|
|
|
let ele = enteringView.pageRef().nativeElement;
|
|
let backdrop = new Animation(ele.querySelector('ion-backdrop'));
|
|
let wrapper = new Animation(ele.querySelector('.action-sheet-wrapper'));
|
|
|
|
backdrop.fromTo('opacity', 0.01, 0.26);
|
|
wrapper.fromTo('translateY', '100%', '0%');
|
|
|
|
this.easing('cubic-bezier(.36,.66,.04,1)').duration(400).add(backdrop).add(wrapper);
|
|
}
|
|
}
|
|
Transition.register('action-sheet-md-slide-in', ActionSheetMdSlideIn);
|
|
|
|
|
|
class ActionSheetMdSlideOut extends Transition {
|
|
constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) {
|
|
super(enteringView, leavingView, opts);
|
|
|
|
let ele = leavingView.pageRef().nativeElement;
|
|
let backdrop = new Animation(ele.querySelector('ion-backdrop'));
|
|
let wrapper = new Animation(ele.querySelector('.action-sheet-wrapper'));
|
|
|
|
backdrop.fromTo('opacity', 0.26, 0);
|
|
wrapper.fromTo('translateY', '0%', '100%');
|
|
|
|
this.easing('cubic-bezier(.36,.66,.04,1)').duration(450).add(backdrop).add(wrapper);
|
|
}
|
|
}
|
|
Transition.register('action-sheet-md-slide-out', ActionSheetMdSlideOut);
|
|
|
|
class ActionSheetWpSlideIn extends Transition {
|
|
constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) {
|
|
super(enteringView, leavingView, opts);
|
|
|
|
let ele = enteringView.pageRef().nativeElement;
|
|
let backdrop = new Animation(ele.querySelector('ion-backdrop'));
|
|
let wrapper = new Animation(ele.querySelector('.action-sheet-wrapper'));
|
|
|
|
backdrop.fromTo('opacity', 0.01, 0.16);
|
|
wrapper.fromTo('translateY', '100%', '0%');
|
|
|
|
this.easing('cubic-bezier(.36,.66,.04,1)').duration(400).add(backdrop).add(wrapper);
|
|
}
|
|
}
|
|
Transition.register('action-sheet-wp-slide-in', ActionSheetWpSlideIn);
|
|
|
|
|
|
class ActionSheetWpSlideOut extends Transition {
|
|
constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) {
|
|
super(enteringView, leavingView, opts);
|
|
|
|
let ele = leavingView.pageRef().nativeElement;
|
|
let backdrop = new Animation(ele.querySelector('ion-backdrop'));
|
|
let wrapper = new Animation(ele.querySelector('.action-sheet-wrapper'));
|
|
|
|
backdrop.fromTo('opacity', 0.1, 0);
|
|
wrapper.fromTo('translateY', '0%', '100%');
|
|
|
|
this.easing('cubic-bezier(.36,.66,.04,1)').duration(450).add(backdrop).add(wrapper);
|
|
}
|
|
}
|
|
Transition.register('action-sheet-wp-slide-out', ActionSheetWpSlideOut);
|
|
|
|
let actionSheetIds = -1;
|