feat(overlay): fire the cancel handler when dismissing from backdrop

Renamed action sheet’s button.style to button.role, and added
button.role to alerts. Pass the button’s role in the dismiss method.
Related #5251
This commit is contained in:
Adam Bradley
2016-01-29 16:11:25 -06:00
parent b472c6cd43
commit 1c618b51eb
6 changed files with 93 additions and 53 deletions

View File

@ -19,16 +19,18 @@ import {ViewController} from '../nav/view-controller';
* hitting the escape key on desktop. * hitting the escape key on desktop.
* *
* An action sheet is created from an array of `buttons`, with each button * An action sheet is created from an array of `buttons`, with each button
* including properties for its `text`, and optionally a `style` and `handler`. * including properties for its `text`, and optionally a `handler` and `role`.
* If a handler returns `false` then the action sheet will not be dismissed. An * If a handler returns `false` then the action sheet will not be dismissed. An
* action sheet can also optionally have a `title` and a `subTitle`. * action sheet can also optionally have a `title` and a `subTitle`.
* *
* A button's `style` property can either be `destructive` or `cancel`. Buttons * A button's `role` property can either be `destructive` or `cancel`. Buttons
* without a style property will have a default style for its platform. Buttons * without a role property will have a default look for its platform. Buttons
* with the `cancel` style will always load as the bottom button, no matter where * with the `cancel` role will always load as the bottom button, no matter where
* it shows up in the array. All other buttons will show up in the order they * it shows up in the array. All other buttons will show up in the order they
* have been added to the `buttons` array. Note: We recommend that `destructive` * have been added to the `buttons` array. Note: We recommend that `destructive`
* buttons show be the first button in the array, making it the button on top. * buttons show be the first button in the array, making it the button on top.
* Additionally, if the action sheet is dismissed by tapping the backdrop, then
* it will fire the handler from the button with the cancel role.
* *
* Its shorthand is to add all the action sheet's options from within the * Its shorthand is to add all the action sheet's options from within the
* `ActionSheet.create(opts)` first argument. Otherwise the action sheet's * `ActionSheet.create(opts)` first argument. Otherwise the action sheet's
@ -46,7 +48,7 @@ import {ViewController} from '../nav/view-controller';
* buttons: [ * buttons: [
* { * {
* text: 'Destructive', * text: 'Destructive',
* style: 'destructive', * role: 'destructive',
* handler: () => { * handler: () => {
* console.log('Destructive clicked'); * console.log('Destructive clicked');
* } * }
@ -59,7 +61,7 @@ import {ViewController} from '../nav/view-controller';
* }, * },
* { * {
* text: 'Cancel', * text: 'Cancel',
* style: 'cancel', * role: 'cancel',
* handler: () => { * handler: () => {
* console.log('Cancel clicked'); * console.log('Cancel clicked');
* } * }
@ -137,7 +139,7 @@ import {ViewController} from '../nav/view-controller';
@Component({ @Component({
selector: 'ion-action-sheet', selector: 'ion-action-sheet',
template: template:
'<div (click)="dismiss()" tappable disable-activated class="backdrop" role="presentation"></div>' + '<div (click)="bdClick()" tappable disable-activated class="backdrop" role="presentation"></div>' +
'<div class="action-sheet-wrapper">' + '<div class="action-sheet-wrapper">' +
'<div class="action-sheet-container">' + '<div class="action-sheet-container">' +
'<div class="action-sheet-group">' + '<div class="action-sheet-group">' +
@ -179,28 +181,6 @@ class ActionSheetCmp {
} }
} }
click(button) {
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();
}, this._config.get('pageTransitionDelay'));
}
}
dismiss(): Promise<any> {
return this._viewCtrl.dismiss(null);
}
onPageLoaded() { onPageLoaded() {
// normalize the data // normalize the data
let buttons = []; let buttons = [];
@ -213,11 +193,24 @@ class ActionSheetCmp {
button.cssClass = ''; button.cssClass = '';
} }
// deprecated warning
if (button.style === 'cancel') { if (button.style === 'cancel') {
console.warn('Alert "style" property has been renamed to "role"');
button.role = 'cancel';
this.d.cancelButton = button;
}
if (button.role === 'cancel') {
this.d.cancelButton = button; this.d.cancelButton = button;
} else { } else {
// deprecated warning
if (button.style === 'destructive') { if (button.style === 'destructive') {
button.role = 'destructive';
button.cssClass = (button.cssClass + ' ' || '') + 'action-sheet-destructive';
}
if (button.role === 'destructive') {
button.cssClass = (button.cssClass + ' ' || '') + 'action-sheet-destructive'; button.cssClass = (button.cssClass + ' ' || '') + 'action-sheet-destructive';
} }
buttons.push(button); buttons.push(button);
@ -230,13 +223,44 @@ class ActionSheetCmp {
self.keyUp = function(ev: KeyboardEvent) { self.keyUp = function(ev: KeyboardEvent) {
if (ev.keyCode === 27) { if (ev.keyCode === 27) {
console.debug('actionsheet escape'); console.debug('actionsheet escape');
self.dismiss(); self.bdClick();
} }
}; };
document.addEventListener('keyup', this.keyUp); document.addEventListener('keyup', this.keyUp);
} }
click(button, dismissDelay?) {
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.d.cancelButton) {
this.click(this.d.cancelButton, 1);
} else {
this.dismiss('backdrop');
}
}
dismiss(role): Promise<any> {
return this._viewCtrl.dismiss(null, role);
}
onPageDidLeave() { onPageDidLeave() {
document.removeEventListener('keyup', this.keyUp); document.removeEventListener('keyup', this.keyUp);
} }

View File

@ -5,10 +5,9 @@ import {App, Page, ActionSheet, NavController} from 'ionic/ionic';
templateUrl: 'main.html' templateUrl: 'main.html'
}) })
class E2EPage { class E2EPage {
result: string = '';
constructor(nav: NavController) { constructor(private nav: NavController) {}
this.nav = nav;
}
presentActionSheet1() { presentActionSheet1() {
this.result = ''; this.result = '';
@ -18,7 +17,7 @@ class E2EPage {
buttons: [ buttons: [
{ {
text: 'Destructive', text: 'Destructive',
style: 'destructive', role: 'destructive',
handler: () => { handler: () => {
console.log('Destructive clicked'); console.log('Destructive clicked');
this.result = 'Destructive'; this.result = 'Destructive';
@ -42,7 +41,7 @@ class E2EPage {
}, },
{ {
text: 'Cancel', text: 'Cancel',
style: 'cancel', // will always sort to be on the bottom role: 'cancel', // will always sort to be on the bottom
handler: () => { handler: () => {
console.log('Cancel clicked'); console.log('Cancel clicked');
this.result = 'Canceled'; this.result = 'Canceled';
@ -68,7 +67,7 @@ class E2EPage {
}, },
{ {
text: 'Cancel', text: 'Cancel',
style: 'cancel', role: 'cancel',
handler: () => { handler: () => {
console.log('cancel this clicked'); console.log('cancel this clicked');
this.result = 'Canceled'; this.result = 'Canceled';
@ -76,7 +75,7 @@ class E2EPage {
}, },
{ {
text: 'Destructive', text: 'Destructive',
style: 'destructive', role: 'destructive',
handler: () => { handler: () => {
console.log('Destructive clicked'); console.log('Destructive clicked');
this.result = 'Destructive'; this.result = 'Destructive';

View File

@ -25,12 +25,17 @@ import {ViewController} from '../nav/view-controller';
* array, from left to right. Note: The right most button (the last one in the * array, from left to right. Note: The right most button (the last one in the
* array) is the main button. * array) is the main button.
* *
* Optionally, a `role` property can be added to a button, such as `cancel`.
* If a `cancel` role is on one of the buttons, then if the alert is dismissed
* by tapping the backdrop, then it will fire the handler from the button
* with a cancel role.
*
* Alerts can also include inputs whos data can be passed back to the app. * Alerts can also include inputs whos data can be passed back to the app.
* Inputs can be used to prompt users for information. * Inputs can be used to prompt users for information.
* *
* Its shorthand is to add all the alert's options from within the * Its shorthand is to add all the alert's options from within the
* `Alert.create(opts)` first argument. Otherwise the alert's * `Alert.create(opts)` first argument. Otherwise the alert's instance
* instance has methods to add options, such as `setTitle()` or `addButton()`. * has methods to add options, such as `setTitle()` or `addButton()`.
* *
* @usage * @usage
* ```ts * ```ts
@ -54,6 +59,7 @@ import {ViewController} from '../nav/view-controller';
* buttons: [ * buttons: [
* { * {
* text: 'Cancel', * text: 'Cancel',
* role: 'cancel',
* handler: () => { * handler: () => {
* console.log('Cancel clicked'); * console.log('Cancel clicked');
* } * }
@ -86,6 +92,7 @@ import {ViewController} from '../nav/view-controller';
* buttons: [ * buttons: [
* { * {
* text: 'Cancel', * text: 'Cancel',
* role: 'cancel',
* handler: data => { * handler: data => {
* console.log('Cancel clicked'); * console.log('Cancel clicked');
* } * }
@ -230,7 +237,7 @@ export class Alert extends ViewController {
@Component({ @Component({
selector: 'ion-alert', selector: 'ion-alert',
template: template:
'<div (click)="dismiss()" tappable disable-activated class="backdrop" role="presentation"></div>' + '<div (click)="bdClick()" tappable disable-activated class="backdrop" role="presentation"></div>' +
'<div class="alert-wrapper">' + '<div class="alert-wrapper">' +
'<div class="alert-head">' + '<div class="alert-head">' +
'<h2 id="{{hdrId}}" class="alert-title" *ngIf="d.title" [innerHTML]="d.title"></h2>' + '<h2 id="{{hdrId}}" class="alert-title" *ngIf="d.title" [innerHTML]="d.title"></h2>' +
@ -370,7 +377,7 @@ class AlertCmp {
} else if (ev.keyCode === 27) { } else if (ev.keyCode === 27) {
console.debug('alert escape'); console.debug('alert escape');
self.dismiss(); self.bdClick();
} }
}; };
@ -391,7 +398,7 @@ class AlertCmp {
} }
} }
btnClick(button) { btnClick(button, dismissDelay?) {
let shouldDismiss = true; let shouldDismiss = true;
if (button.handler) { if (button.handler) {
@ -405,8 +412,8 @@ class AlertCmp {
if (shouldDismiss) { if (shouldDismiss) {
setTimeout(() => { setTimeout(() => {
this.dismiss(); this.dismiss(button.role);
}, this._config.get('pageTransitionDelay')); }, dismissDelay || this._config.get('pageTransitionDelay'));
} }
} }
@ -421,8 +428,18 @@ class AlertCmp {
checkedInput.checked = !checkedInput.checked; checkedInput.checked = !checkedInput.checked;
} }
dismiss(): Promise<any> { bdClick() {
return this._viewCtrl.dismiss(this.getValues()); let cancelBtn = this.d.buttons.find(b => b.role === 'cancel');
if (cancelBtn) {
this.btnClick(cancelBtn, 1);
} else {
this.dismiss('backdrop');
}
}
dismiss(role): Promise<any> {
return this._viewCtrl.dismiss(this.getValues(), role);
} }
getValues() { getValues() {

View File

@ -6,8 +6,7 @@ import {App, Page, Alert, NavController} from 'ionic/ionic';
}) })
class E2EPage { class E2EPage {
constructor(nav: NavController) { constructor(private nav: NavController) {
this.nav = nav;
this.testConfirmOpen = false; this.testConfirmOpen = false;
this.testPromptOpen = false; this.testPromptOpen = false;
this.testConfirmResult = ''; this.testConfirmResult = '';
@ -31,6 +30,7 @@ class E2EPage {
alert.setMessage('Message <strong>text</strong>!!!'); alert.setMessage('Message <strong>text</strong>!!!');
alert.addButton({ alert.addButton({
text: 'Cancel', text: 'Cancel',
role: 'cancel',
handler: () => { handler: () => {
console.log('Confirm Cancel'); console.log('Confirm Cancel');
this.testConfirmResult = 'Cancel'; this.testConfirmResult = 'Cancel';
@ -88,8 +88,8 @@ class E2EPage {
this.testPromptOpen = true; this.testPromptOpen = true;
}); });
alert.onDismiss(data => { alert.onDismiss((data, role) => {
console.log('onDismiss data', data); console.log('onDismiss, data:', data, 'role:', role);
}); });
} }

View File

@ -114,7 +114,7 @@ export class NavRouter extends RouterOutlet {
class ResolvedInstruction extends Instruction { class ResolvedInstruction extends Instruction {
constructor(public component: ComponentInstruction, public child: Instruction, constructor(public component: ComponentInstruction, public child: Instruction,
public auxInstruction: {[key: string]: Instruction}) { public auxInstruction: {[key: string]: Instruction}) {
super(); super(component, child, auxInstruction);
} }
resolveComponent(): Promise<ComponentInstruction> { resolveComponent(): Promise<ComponentInstruction> {

View File

@ -83,8 +83,8 @@ export class ViewController {
this._onDismiss = callback; this._onDismiss = callback;
} }
dismiss(data) { dismiss(data, role?) {
this._onDismiss && this._onDismiss(data); this._onDismiss && this._onDismiss(data, role);
return this._nav.remove(this._nav.indexOf(this), 1, this._leavingOpts); return this._nav.remove(this._nav.indexOf(this), 1, this._leavingOpts);
} }