' +
@@ -39,7 +85,10 @@ import {extend} from '../../util/util';
})
class ActionSheetCmp {
- constructor(params: NavParams, renderer: Renderer) {
+ constructor(
+ private _viewCtrl: ViewController,
+ params: NavParams, renderer: Renderer
+ ) {
this.d = params.data;
if (this.d.cssClass) {
@@ -47,121 +96,64 @@ class ActionSheetCmp {
}
}
- cancel() {
- this.d.cancel && this.d.cancel();
- return this.close();
- }
+ click(button) {
+ let shouldDismiss = true;
- destructive() {
- if (this.d.destructiveButtonClicked()) {
- return this.close();
+ 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) {
+ this.dismiss();
}
}
- buttonClicked(index) {
- if (this.d.buttonClicked(index)) {
- return this.close();
- }
+ dismiss() {
+ this._viewCtrl.dismiss(this);
+ }
+
+ onPageLoaded() {
+ // normalize the data
+ let buttons = [];
+
+ this.d.buttons.forEach(button => {
+ if (typeof button === 'string') {
+ button = { text: button };
+ }
+
+ if (button.style === 'cancel') {
+ this.d.cancelButton = button;
+
+ } else {
+ if (button.style === 'destructive') {
+ button.cssClass = (button.cssClass + ' ' || '') + 'action-sheet-destructive';
+ }
+ buttons.push(button);
+ }
+ });
+
+ this.d.buttons = buttons;
+
+ let self = this;
+ self.keyUp = function(ev) {
+ if (ev.keyCode === 27) {
+ console.debug('actionsheet escape');
+ self.dismiss();
+ }
+ };
+
+ document.addEventListener('keyup', this.keyUp);
+ }
+
+ onPageDidLeave() {
+ document.removeEventListener('keyup', this.keyUp);
}
}
-/**
- * @name ActionSheet
- * @description
- * The Action Sheet is a slide-up pane that lets the user choose from a set of options. Dangerous options are made obvious.
- * There are easy ways to cancel out of the action sheet, such as tapping the backdrop or even hitting escape on the keyboard for desktop testing.
- *
- * @usage
- * ```ts
- * openMenu() {
- *
- * this.actionSheet.open({
- * buttons: [
- * { text: 'Share This' },
- * { text: 'Move' }
- * ],
- * destructiveText: 'Delete',
- * titleText: 'Modify your album',
- * cancelText: 'Cancel',
- * cancel: function() {
- * console.log('Canceled');
- * },
- * destructiveButtonClicked: () => {
- * console.log('Destructive clicked');
- * },
- * buttonClicked: function(index) {
- * console.log('Button clicked', index);
- * if(index == 1) { return false; }
- * return true;
- * }
- *
- * }).then(actionSheetRef => {
- * this.actionSheetRef = actionSheetRef;
- * });
- *
- * }
- * ```
- *
- * @demo /docs/v2/demos/action-sheet/
- * @see {@link /docs/v2/components#action-sheets ActionSheet Component Docs}
- */
-@Injectable()
-export class ActionSheet {
-
- constructor(config: Config) {
- //this.ctrl = ctrl;
- this.config = config;
- }
-
- /**
- * Create and open a new Action Sheet. This is the
- * public API, and most often you will only use ActionSheet.open()
- *
- * @param {Object} [opts={}] An object containing optional settings.
- * - `[Object]` `buttons` Which buttons to show. Each button is an object with a `text` field.
- * - `{string}` `titleText` The title to show on the action sheet.
- * - `{string=}` `cancelText` the text for a 'cancel' button on the action sheet.
- * - `{string=}` `destructiveText` The text for a 'danger' on the action sheet.
- * - `{function=}` `cancel` Called if the cancel button is pressed, the backdrop is tapped or
- * the hardware back button is pressed.
- * - `{function=}` `buttonClicked` Called when one of the non-destructive buttons is clicked,
- * with the index of the button that was clicked and the button object. Return true to close
- * the action sheet, or false to keep it opened.
- * - `{function=}` `destructiveButtonClicked` Called when the destructive button is clicked.
- * Return true to close the action sheet, or false to keep it opened.
- * - `{String}` `enterAnimation` The class used to animate an actionSheet that is entering.
- * - `{String}` `leaveAnimation` The class used to animate an actionSheet that is leaving.
- * @return {Promise} Promise that resolves when the action sheet is open.
- */
- open(opts={}) {
- opts = extend({
- pageType: OVERLAY_TYPE,
- enterAnimation: this.config.get('actionSheetEnter'),
- leaveAnimation: this.config.get('actionSheetLeave'),
- cancelIcon: this.config.get('actionSheetCancelIcon'),
- destructiveIcon: this.config.get('actionSheetDestructiveIcon')
- }, opts);
-
- return this.ctrl.open(ActionSheetCmp, opts, opts);
- }
-
- /**
- * Retrieves an actionSheet instance.
- *
- * @param {String} [handle] The handle used to open the instance to be retrieved.
- * @returns {ActionSheet} An actionSheet instance.
- */
- get(handle) {
- if (handle) {
- return this.ctrl.getByHandle(handle);
- }
- return this.ctrl.getByType(OVERLAY_TYPE);
- }
-
-}
-
-const OVERLAY_TYPE = 'action-sheet';
-
class ActionSheetSlideIn extends Animation {
diff --git a/ionic/components/action-sheet/test/basic/index.ts b/ionic/components/action-sheet/test/basic/index.ts
index 0de8f0c928..ccebdce40a 100644
--- a/ionic/components/action-sheet/test/basic/index.ts
+++ b/ionic/components/action-sheet/test/basic/index.ts
@@ -1,41 +1,66 @@
-import {App, ActionSheet} from 'ionic/ionic';
+import {App, Page, ActionSheet, NavController} from 'ionic/ionic';
-@App({
+@Page({
templateUrl: 'main.html'
})
-class E2EApp {
+class E2EPage {
- constructor(actionSheet: ActionSheet) {
- this.actionSheet = actionSheet;
+ constructor(nav: NavController) {
+ this.nav = nav;
}
- openActionSheet() {
+ openActionSheet(ev) {
+ this.result = '';
- this.actionSheet.open({
+ let actionSheet = ActionSheet.create({
buttons: [
- { text: 'Share This' },
- { text: 'Move' }
- ],
- destructiveText: 'Delete',
- titleText: 'Modify your album',
- cancelText: 'Cancel',
- cancel: function() {
- console.log('Canceled');
- },
- destructiveButtonClicked: () => {
- console.log('Destructive clicked');
- },
- buttonClicked: function(index) {
- console.log('Button clicked', index);
- if(index == 1) { return false; }
- return true;
- }
+ {
+ text: 'Cancel',
+ style: 'cancel', // will always sort to be on the bottom
+ handler: () => {
+ console.log('cancel this clicked');
+ this.result = 'Canceled';
+ }
+ },
+ {
+ text: 'Archive',
+ handler: () => {
+ console.log('Archive clicked');
+ this.result = 'Archived';
+ }
+ },
+ {
+ text: 'No close',
+ handler: () => {
+ console.log('do not close clicked');
- }).then(actionSheetRef => {
- this.actionSheetRef = actionSheetRef;
+ // returning false does not allow the actionsheet to be closed
+ return false;
+ }
+ },
+ {
+ text: 'Destructive',
+ style: 'destructive',
+ handler: () => {
+ console.log('Destructive clicked');
+ this.result = 'Destructive';
+ }
+ }
+ ]
});
+ this.nav.present(actionSheet);
}
}
+
+
+@App({
+ template: ''
+})
+class E2EApp {
+ constructor() {
+ this.root = E2EPage;
+ }
+}
diff --git a/ionic/components/action-sheet/test/basic/main.html b/ionic/components/action-sheet/test/basic/main.html
index 7658c8dfe6..db7de5ed05 100644
--- a/ionic/components/action-sheet/test/basic/main.html
+++ b/ionic/components/action-sheet/test/basic/main.html
@@ -1,4 +1,12 @@
+
+ Action Sheet
+
+
Open Action Sheet
+
+
+ Result: {{result}}
+
diff --git a/ionic/components/alert/alert.ts b/ionic/components/alert/alert.ts
index db2164d6b8..e124a4ce5a 100644
--- a/ionic/components/alert/alert.ts
+++ b/ionic/components/alert/alert.ts
@@ -1,57 +1,50 @@
import {Component, ElementRef, Renderer} from 'angular2/core';
import {NgClass, NgIf, NgFor, FORM_DIRECTIVES} from 'angular2/common';
-import {NavController, NavParams} from '../nav/nav-controller';
+import {NavParams} from '../nav/nav-controller';
import {ViewController} from '../nav/view-controller';
import {Animation} from '../../animations/animation';
import {Button} from '../button/button';
-import {extend, isDefined} from '../../util/util';
+import {isDefined} from '../../util/util';
export class Alert extends ViewController {
- constructor(opts={}) {
- super(AlertCmp, opts);
+ constructor(data={}) {
+ data.inputs = data.inputs || [];
+ data.buttons = data.buttons || [];
- this.data.inputs = this.data.inputs || [];
- this.data.buttons = this.data.buttons || [];
+ super(AlertCmp, data);
+ this.viewType = 'alert';
}
getTransitionName(direction) {
let key = (direction === 'back' ? 'alertLeave' : 'alertEnter');
- return this._nav.config.get(key);
+ return this._nav && this._nav.config.get(key);
}
setTitle(title) {
- this.data.title = title;
+ this._data.title = title;
}
setSubTitle(subTitle) {
- this.data.subTitle = subTitle;
+ this._data.subTitle = subTitle;
}
setBody(body) {
- this.data.body = body;
+ this._data.body = body;
}
addInput(input) {
- this.data.inputs.push(input);
+ this._data.inputs.push(input);
}
addButton(button) {
- this.data.buttons.push(button);
+ this._data.buttons.push(button);
}
- onDismiss(handler) {
- this.data.onDismiss = handler;
- }
-
- dismiss() {
- this._nav.dismiss(this);
- }
-
- static create(opts={}) {
- return new Alert(opts);
+ static create(data={}) {
+ return new Alert(data);
}
}
@@ -102,9 +95,10 @@ class AlertCmp {
let shouldDismiss = true;
if (button.handler) {
- // a handler has been provided, run it
+ // 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 is a false then do not close
+ // if the return value of the handler is false then do not dismiss
shouldDismiss = false;
}
}
@@ -126,7 +120,7 @@ class AlertCmp {
return values;
}
- onPageWillEnter() {
+ onPageLoaded() {
// normalize the data
this.d.buttons = this.d.buttons.map(button => {
if (typeof button === 'string') {
@@ -137,9 +131,9 @@ class AlertCmp {
this.d.inputs = this.d.inputs.map((input, index) => {
return {
- name: input.name || index,
+ name: isDefined(input.name) ? input.name : index,
label: input.label,
- placeholder: input.placeholder || '',
+ placeholder: isDefined(input.placeholder) ? input.placeholder : '',
type: input.type || 'text',
value: isDefined(input.value) ? input.value : ''
}
@@ -173,7 +167,6 @@ class AlertCmp {
}
onPageDidLeave() {
- this.d.onDismiss && this.d.onDismiss(this.getValues());
document.removeEventListener('keyup', this.keyUp);
}
}
diff --git a/ionic/components/alert/test/basic/index.ts b/ionic/components/alert/test/basic/index.ts
index adccde6271..1a6a3aecf8 100644
--- a/ionic/components/alert/test/basic/index.ts
+++ b/ionic/components/alert/test/basic/index.ts
@@ -8,7 +8,6 @@ class E2EPage {
constructor(nav: NavController) {
this.nav = nav;
- this.testAlertOpen = false;
this.testConfirmOpen = false;
this.testPromptOpen = false;
this.testConfirmResult = '';
@@ -19,15 +18,10 @@ class E2EPage {
let alert = Alert.create({
title: 'Alert!',
subTitle: 'Subtitle!!!',
- buttons: ['Ok'],
- onDismiss: () => {
- this.testAlertOpen = false;
- }
+ buttons: ['Ok']
});
this.nav.present(alert);
-
- this.testAlertOpen = true;
}
doConfirm() {
@@ -39,6 +33,7 @@ class E2EPage {
handler: () => {
console.log('Confirm Cancel');
this.testConfirmResult = 'Cancel';
+ this.testConfirmOpen = false;
}
});
alert.addButton({
@@ -46,13 +41,10 @@ class E2EPage {
handler: () => {
console.log('Confirm Ok');
this.testConfirmResult = 'Ok';
+ this.testConfirmOpen = false;
}
});
- alert.onDismiss(data => {
- this.testConfirmOpen = false;
- });
-
this.nav.present(alert).then(() => {
this.testConfirmOpen = true;
});
@@ -87,14 +79,11 @@ class E2EPage {
text: 'Ok',
handler: data => {
console.log('Prompt data:', data);
+ this.testPromptOpen = false;
+ this.testPromptResult = data;
}
});
- alert.onDismiss(data => {
- this.testPromptOpen = false;
- this.testPromptResult = data;
- });
-
this.nav.present(alert).then(() => {
this.testPromptOpen = true;
});
diff --git a/ionic/components/alert/test/basic/main.html b/ionic/components/alert/test/basic/main.html
index a5924ef37a..14b8b911cb 100644
--- a/ionic/components/alert/test/basic/main.html
+++ b/ionic/components/alert/test/basic/main.html
@@ -10,7 +10,6 @@
Prompt
- Alert Opened: {{testAlertOpen}}
Confirm Opened: {{testConfirmOpen}}
Confirm Result: {{testConfirmResult}}
Prompt Opened: {{testPromptOpen}}
diff --git a/ionic/components/modal/modal.ts b/ionic/components/modal/modal.ts
index 6da84092ed..a45b19a07a 100644
--- a/ionic/components/modal/modal.ts
+++ b/ionic/components/modal/modal.ts
@@ -1,35 +1,53 @@
-import {Injectable, Type} from 'angular2/core';
-
+import {NavController, NavParams} from '../nav/nav-controller';
+import {ViewController} from '../nav/view-controller';
import {Config} from '../../config/config';
import {Animation} from '../../animations/animation';
-import {extend} from '../../util';
/**
* @name Modal
* @description
* The Modal is a content pane that can go over the user's current page.
- * Usually used for making a choice or editing an item. A modal can be opened
- * similar to how {@link /docs/v2/api/components/nav/NavController/#push NavController.push} works,
- * where it is passed a Page component, along with optional Page params,
- * and options for presenting the modal.
+ * Usually it is used for making a choice or editing an item. A modal uses the
+ * `NavController` to "present" itself in the root nav stack. It is added to the
+ * stack similar to how
+ * {@link /docs/v2/api/components/nav/NavController/#push NavController.push}
+ * works, where it is passed a Page component, along with optional Page params
+ *
+ * When a modal (or any other overlay such as an alert or actionsheet) is
+ * "presented" to a nav controller, the overlay is added to the app's root nav.
+ * After the modal has been presented, from within the component instance The
+ * modal can later be closed or "dimsissed" by using the ViewController's
+ * `dismiss` method. Additinoally, you can dismiss any overlay by using `pop`
+ * on the root nav controller.
+ *
+ * A modal can also emit data, which is useful when it is used to add or edit
+ * data. For example, a profile page could slide up in a modal, and on submit,
+ * the submit button could emit the updated profile data, then dismiss the modal.
+ * From that point, anything which is subscribed to the modal's `data` event
+ * would receive the modal's data.
*
* @usage
* ```ts
+ * import {Modal, NavController} from 'ionic/ionic';
+ *
* class MyApp {
*
- * constructor(modal: Modal) {
- * this.modal = modal;
+ * constructor(nav: NavController) {
+ * this.nav = nav;
* }
*
- * openContactModal() {
- * this.modal.open(ContactUs);
+ * presentContactModal() {
+ * let contactModal = Modal.create(ContactUs);
+ * this.nav.present(contactModal);
* }
*
- * openProfileModal() {
- * this.modal.open(Profile, { userId: 8675309 }, {
- * enterAnimation: 'my-fade-in',
- * leaveAnimation: 'my-fade-out',
- * handle: 'profile-modal'
+ * presentProfileModal() {
+ * let profileModal = Modal.create(Profile, { userId: 8675309 });
+ * this.nav.present(profileModal, {
+ * animation: 'my-fade-in'
+ * });
+ * profileModal.data.subscribe(data => {
+ * console.log(data);
* });
* }
*
@@ -38,64 +56,24 @@ import {extend} from '../../util';
* @demo /docs/v2/demos/modal/
* @see {@link /docs/v2/components#modals Modal Component Docs}
*/
-@Injectable()
-export class Modal {
+export class Modal extends ViewController {
- constructor(config: Config) {
- //this.ctrl = ctrl;
- this.config = config;
+ constructor(componentType, data={}) {
+ super(componentType, data);
+ this.viewType = 'modal';
}
- /**
- * Opens a new modal using the page component is was pass as the first
- * argument. This is similar to how NavController's `push` method works.
- * Currently you must have `` in the `@App` component's template
- * for the modal to work correctly. (This is something that will
- * be hopefully be removed in the near future.)
- *
- * @param pageComponent The Page component to load in the modal.
- * @param {Object} [params={}] Optional data which can be passed to the page
- * component, which can be read from the constructor's `NavParams`.
- * @param {Object} [opts={}] Additional options for this one modal instance of.
- * Options include `enterAnimation` and `leaveAnimation`, which
- * allows customization of which animation to use.
- * @returns {Promise} Returns a promise which resolves when the modal has
- * loaded and its entering animation has completed. The resolved promise's
- * value is the instance of the newly created modal.
- */
- open(pageComponent: Type, params={}, opts={}) {
- opts = extend({
- pageType: OVERLAY_TYPE,
- enterAnimation: this.config.get('modalEnter'),
- leaveAnimation: this.config.get('modalLeave'),
- }, opts);
-
- return this.ctrl.open(pageComponent, params, opts);
+ getTransitionName(direction) {
+ let key = (direction === 'back' ? 'modalLeave' : 'modalEnter');
+ return this._nav && this._nav.config.get(key);
}
- /**
- * Get the instance of a modal. This is usually helpful to getting ahold of a
- * certain modal, from anywhere within the app, and closing it. By calling
- * just `get()` without a `handle` argument, it'll return the active modal
- * on top (it is possible to have multipe modals opened at the same time).
- * If getting just the active modal isn't enough, when creating
- * a modal, it's options can be given a `handle`, which is simply a string-based
- * name for the modal instance. You can later get a reference to that modal's
- * instance by calling this method with the same handle name.
- * @param [handle] Optional string name given in the modal's options when it was opened.
- * @returns Returns the instance of the modal if it is found, otherwise `null`.
- */
- get(handle) {
- if (handle) {
- return this.ctrl.getByHandle(handle);
- }
- return this.ctrl.getByType(OVERLAY_TYPE);
+ static create(componentType, data={}) {
+ return new Modal(componentType, data);
}
}
-const OVERLAY_TYPE = 'modal';
-
/**
* Animations for modals
@@ -108,6 +86,13 @@ class ModalSlideIn extends Animation {
.duration(400)
.fromTo('translateY', '100%', '0%')
.before.addClass('show-page');
+
+ if (enteringView.hasNavbar()) {
+ // entering page has a navbar
+ let enteringNavBar = new Animation(enteringView.navbarRef());
+ enteringNavBar.before.addClass('show-navbar');
+ this.add(enteringNavBar);
+ }
}
}
Animation.register('modal-slide-in', ModalSlideIn);
@@ -134,6 +119,13 @@ class ModalMDSlideIn extends Animation {
.fromTo('translateY', '40px', '0px')
.fadeIn()
.before.addClass('show-page');
+
+ if (enteringView.hasNavbar()) {
+ // entering page has a navbar
+ let enteringNavBar = new Animation(enteringView.navbarRef());
+ enteringNavBar.before.addClass('show-navbar');
+ this.add(enteringNavBar);
+ }
}
}
Animation.register('modal-md-slide-in', ModalMDSlideIn);
diff --git a/ionic/components/modal/test/basic/index.ts b/ionic/components/modal/test/basic/index.ts
index 0fdab060a2..6140dba8df 100644
--- a/ionic/components/modal/test/basic/index.ts
+++ b/ionic/components/modal/test/basic/index.ts
@@ -1,15 +1,14 @@
import {App, Page, Config, Platform} from 'ionic/ionic';
-import {Modal, ActionSheet, NavController, NavParams, Animation} from 'ionic/ionic';
+import {Modal, ActionSheet, NavController, NavParams, Animation, ViewController} from 'ionic/ionic';
-@App({
+@Page({
templateUrl: 'main.html'
})
-class E2EApp {
-
- constructor(modal: Modal, config: Config, platform: Platform) {
- this.modal = modal;
+class E2EPage {
+ constructor(nav: NavController, config: Config, platform: Platform) {
+ this.nav = nav;
console.log('platforms', platform.platforms());
console.log('mode', config.get('mode'));
@@ -29,32 +28,29 @@ class E2EApp {
});
}
- openModal() {
- this.modal.open(ModalPassParams, { userId: 3141209 });
- }
+ presentModal() {
+ let modal = Modal.create(ModalPassData, { userId: 8675309 });
+ this.nav.present(modal);
- openToolbarModal() {
- this.modal.open(ToolbarModal).then(modalRef => {
- // modal has finished opening
- // modalRef is a reference to the modal instance
- modalRef.onClose = (modalData) => {
- // somehow modalRef.close(modalData) was called w/ modalData
- console.log('modalRef.onClose', modalData)
- }
+ modal.data.subscribe(data => {
+ console.log('data', data);
});
}
- openModalChildNav() {
- this.modal.open(ContactUs, null, {
- handle: 'my-awesome-modal'
- });
+ presentModalChildNav() {
+ let modal = Modal.create(ContactUs);
+ this.nav.present(modal);
}
- openModalCustomAnimation() {
- this.modal.open(ContactUs, null, {
- handle: 'my-awesome-modal',
- enterAnimation: 'my-fade-in',
- leaveAnimation: 'my-fade-out'
+ presentToolbarModal() {
+ let modal = Modal.create(ToolbarModal);
+ this.nav.present(modal);
+ }
+
+ presentModalCustomAnimation() {
+ let modal = Modal.create(ContactUs);
+ this.nav.present(modal, {
+ animation: 'my-fade-in'
});
}
}
@@ -62,44 +58,65 @@ class E2EApp {
@Page({
template: `
-