Skip to content

Commit

Permalink
fix(modal): app.navPop() can dismiss modals
Browse files Browse the repository at this point in the history
fixes #8692
  • Loading branch information
manucorporat committed Dec 2, 2016
1 parent 24d45d5 commit 5567191
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 41 deletions.
39 changes: 39 additions & 0 deletions src/components/app/app-root.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Ion } from '../ion';
import { OverlayPortal } from '../nav/overlay-portal';
import { Platform } from '../../platform/platform';
import { nativeTimeout } from '../../util/dom';
import { assert } from '../../util/util';

export const AppRootToken = new OpaqueToken('USERROOT');

Expand Down Expand Up @@ -103,12 +104,50 @@ export class IonicApp extends Ion implements OnInit {
if (portal === AppPortal.TOAST) {
return this._toastPortal;
}
// Modals need their own overlay becuase we don't want an ActionSheet
// or Alert to trigger lifecycle events inside a modal
if (portal === AppPortal.MODAL) {
return this._modalPortal;
}
return this._overlayPortal;
}

/**
* @private
*/
_getActivePortal(): OverlayPortal {
const defaultPortal = this._overlayPortal;
const modalPortal = this._modalPortal;

assert(defaultPortal, 'default must be valid');
assert(modalPortal, 'modal must be valid');

const hasModal = modalPortal.length() > 0;
const hasDefault = defaultPortal.length() > 0;

if (!hasModal && !hasDefault) {
return null;

} else if (hasModal && hasDefault) {
var defaultIndex = defaultPortal.getActive().getZIndex();
var modalIndex = modalPortal.getActive().getZIndex();

if (defaultIndex > modalIndex) {
return defaultPortal;
} else {
assert(modalIndex > defaultIndex, 'modal and default zIndex can not be equal');
return modalPortal;
}

} if (hasModal) {
return modalPortal;

} else if (hasDefault) {
return defaultPortal;
}

}

/**
* @private
*/
Expand Down
57 changes: 33 additions & 24 deletions src/components/app/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Title } from '@angular/platform-browser';

import { AppPortal, IonicApp } from './app-root';
import { ClickBlock } from '../../util/click-block';
import { runInDev } from '../../util/util';
import { Config } from '../../config/config';
import { isNav, isTabs, NavOptions, DIRECTION_FORWARD, DIRECTION_BACK } from '../../navigation/nav-util';
import { NavController } from '../../navigation/nav-controller';
Expand Down Expand Up @@ -72,6 +73,14 @@ export class App {
// register this back button action with a default priority
_platform.registerBackButtonAction(this.navPop.bind(this));
this._disableScrollAssist = _config.getBoolean('disableScrollAssist', false);

runInDev(() => {
// During developement, navPop can be triggered by calling
// window.ClickBackButton();
if (!window['HWBackButton']) {
window['HWBackButton'] = this.navPop.bind(this);
}
});
}

/**
Expand Down Expand Up @@ -228,6 +237,10 @@ export class App {
* @private
*/
navPop(): Promise<any> {
if (!this._rootNav || !this.isEnabled()) {
return Promise.resolve();
}

// function used to climb up all parent nav controllers
function navPop(nav: any): Promise<any> {
if (nav) {
Expand Down Expand Up @@ -259,34 +272,30 @@ export class App {

// app must be enabled and there must be a
// root nav controller for go back to work
if (this._rootNav && this.isEnabled()) {
const portal = this._appRoot._getPortal();

// first check if the root navigation has any overlays
// opened in it's portal, like alert/actionsheet/popup
if (portal.length() > 0) {
// there is an overlay view in the portal
// let's pop this one off to go back
console.debug('app, goBack pop overlay');
return portal.pop();
}
const portal = this._appRoot._getActivePortal();

// first check if the root navigation has any overlays
// opened in it's portal, like alert/actionsheet/popup
if (portal) {
// there is an overlay view in the portal
// let's pop this one off to go back
console.debug('app, goBack pop overlay');
return portal.pop();
}

// next get the active nav, check itself and climb up all
// of its parent navs until it finds a nav that can pop
let navPromise = navPop(this.getActiveNav());
if (navPromise === null) {
// no views to go back to
// let's exit the app
if (this._config.getBoolean('navExitApp', true)) {
console.debug('app, goBack exitApp');
this._platform.exitApp();
}
// next get the active nav, check itself and climb up all
// of its parent navs until it finds a nav that can pop
let navPromise = navPop(this.getActiveNav());
if (navPromise === null) {
// no views to go back to
// let's exit the app
if (this._config.getBoolean('navExitApp', true)) {
console.debug('app, goBack exitApp');
this._platform.exitApp();
}

return navPromise;
}

return Promise.resolve();
return navPromise;
}

}
Expand Down
35 changes: 18 additions & 17 deletions src/navigation/view-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,31 +44,31 @@ export class ViewController {
* Observable to be subscribed to when the current component will become active
* @returns {Observable} Returns an observable
*/
willEnter: EventEmitter<any>;
willEnter: EventEmitter<any> = new EventEmitter();

/**
* Observable to be subscribed to when the current component has become active
* @returns {Observable} Returns an observable
*/
didEnter: EventEmitter<any>;
didEnter: EventEmitter<any> = new EventEmitter();

/**
* Observable to be subscribed to when the current component will no longer be active
* @returns {Observable} Returns an observable
*/
willLeave: EventEmitter<any>;
willLeave: EventEmitter<any> = new EventEmitter();

/**
* Observable to be subscribed to when the current component is no long active
* @returns {Observable} Returns an observable
*/
didLeave: EventEmitter<any>;
didLeave: EventEmitter<any> = new EventEmitter();

/**
* Observable to be subscribed to when the current component has been destroyed
* @returns {Observable} Returns an observable
*/
willUnload: EventEmitter<any>;
willUnload: EventEmitter<any> = new EventEmitter();

/** @private */
data: any;
Expand Down Expand Up @@ -105,12 +105,6 @@ export class ViewController {
this.data = (data instanceof NavParams ? data.data : (isPresent(data) ? data : {}));

this._cssClass = rootCssClass;

this.willEnter = new EventEmitter();
this.didEnter = new EventEmitter();
this.willLeave = new EventEmitter();
this.didLeave = new EventEmitter();
this.willUnload = new EventEmitter();
}

/**
Expand Down Expand Up @@ -220,13 +214,13 @@ export class ViewController {
*/
enableBack(): boolean {
// update if it's possible to go back from this nav item
if (this._nav) {
let previousItem = this._nav.getPrevious(this);
// the previous view may exist, but if it's about to be destroyed
// it shouldn't be able to go back to
return !!(previousItem);
if (!this._nav) {
return false;
}
return false;
// the previous view may exist, but if it's about to be destroyed
// it shouldn't be able to go back to
const previousItem = this._nav.getPrevious(this);
return !!(previousItem);
}

/**
Expand Down Expand Up @@ -278,6 +272,13 @@ export class ViewController {
}
}

/**
* @private
*/
getZIndex(): number {
return this._zIndex;
}

/**
* @private
* DOM WRITE
Expand Down
1 change: 1 addition & 0 deletions src/util/mock-providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export const mockIonicApp = function(app: App, config: Config, platform: Platfor
appRoot._loadingPortal = mockOverlayPortal(app, config, platform);
appRoot._toastPortal = mockOverlayPortal(app, config, platform);
appRoot._overlayPortal = mockOverlayPortal(app, config, platform);
appRoot._modalPortal = mockOverlayPortal(app, config, platform);

return appRoot;
};
Expand Down

0 comments on commit 5567191

Please sign in to comment.