mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-20 12:29:55 +08:00
@ -6,6 +6,7 @@ import { Ion } from '../ion';
|
|||||||
import { OverlayPortal } from '../nav/overlay-portal';
|
import { OverlayPortal } from '../nav/overlay-portal';
|
||||||
import { Platform } from '../../platform/platform';
|
import { Platform } from '../../platform/platform';
|
||||||
import { nativeTimeout } from '../../util/dom';
|
import { nativeTimeout } from '../../util/dom';
|
||||||
|
import { assert } from '../../util/util';
|
||||||
|
|
||||||
export const AppRootToken = new OpaqueToken('USERROOT');
|
export const AppRootToken = new OpaqueToken('USERROOT');
|
||||||
|
|
||||||
@ -103,12 +104,50 @@ export class IonicApp extends Ion implements OnInit {
|
|||||||
if (portal === AppPortal.TOAST) {
|
if (portal === AppPortal.TOAST) {
|
||||||
return this._toastPortal;
|
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) {
|
if (portal === AppPortal.MODAL) {
|
||||||
return this._modalPortal;
|
return this._modalPortal;
|
||||||
}
|
}
|
||||||
return this._overlayPortal;
|
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
|
* @private
|
||||||
*/
|
*/
|
||||||
|
@ -3,6 +3,7 @@ import { Title } from '@angular/platform-browser';
|
|||||||
|
|
||||||
import { AppPortal, IonicApp } from './app-root';
|
import { AppPortal, IonicApp } from './app-root';
|
||||||
import { ClickBlock } from '../../util/click-block';
|
import { ClickBlock } from '../../util/click-block';
|
||||||
|
import { runInDev } from '../../util/util';
|
||||||
import { Config } from '../../config/config';
|
import { Config } from '../../config/config';
|
||||||
import { isNav, isTabs, NavOptions, DIRECTION_FORWARD, DIRECTION_BACK } from '../../navigation/nav-util';
|
import { isNav, isTabs, NavOptions, DIRECTION_FORWARD, DIRECTION_BACK } from '../../navigation/nav-util';
|
||||||
import { NavController } from '../../navigation/nav-controller';
|
import { NavController } from '../../navigation/nav-controller';
|
||||||
@ -72,6 +73,14 @@ export class App {
|
|||||||
// register this back button action with a default priority
|
// register this back button action with a default priority
|
||||||
_platform.registerBackButtonAction(this.navPop.bind(this));
|
_platform.registerBackButtonAction(this.navPop.bind(this));
|
||||||
this._disableScrollAssist = _config.getBoolean('disableScrollAssist', false);
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -228,6 +237,10 @@ export class App {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
navPop(): Promise<any> {
|
navPop(): Promise<any> {
|
||||||
|
if (!this._rootNav || !this.isEnabled()) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
// function used to climb up all parent nav controllers
|
// function used to climb up all parent nav controllers
|
||||||
function navPop(nav: any): Promise<any> {
|
function navPop(nav: any): Promise<any> {
|
||||||
if (nav) {
|
if (nav) {
|
||||||
@ -259,34 +272,30 @@ export class App {
|
|||||||
|
|
||||||
// app must be enabled and there must be a
|
// app must be enabled and there must be a
|
||||||
// root nav controller for go back to work
|
// root nav controller for go back to work
|
||||||
if (this._rootNav && this.isEnabled()) {
|
const portal = this._appRoot._getActivePortal();
|
||||||
const portal = this._appRoot._getPortal();
|
|
||||||
|
|
||||||
// first check if the root navigation has any overlays
|
// first check if the root navigation has any overlays
|
||||||
// opened in it's portal, like alert/actionsheet/popup
|
// opened in it's portal, like alert/actionsheet/popup
|
||||||
if (portal.length() > 0) {
|
if (portal) {
|
||||||
// there is an overlay view in the portal
|
// there is an overlay view in the portal
|
||||||
// let's pop this one off to go back
|
// let's pop this one off to go back
|
||||||
console.debug('app, goBack pop overlay');
|
console.debug('app, goBack pop overlay');
|
||||||
return portal.pop();
|
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return navPromise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.resolve();
|
// 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -44,31 +44,31 @@ export class ViewController {
|
|||||||
* Observable to be subscribed to when the current component will become active
|
* Observable to be subscribed to when the current component will become active
|
||||||
* @returns {Observable} Returns an observable
|
* @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
|
* Observable to be subscribed to when the current component has become active
|
||||||
* @returns {Observable} Returns an observable
|
* @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
|
* Observable to be subscribed to when the current component will no longer be active
|
||||||
* @returns {Observable} Returns an observable
|
* @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
|
* Observable to be subscribed to when the current component is no long active
|
||||||
* @returns {Observable} Returns an observable
|
* @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
|
* Observable to be subscribed to when the current component has been destroyed
|
||||||
* @returns {Observable} Returns an observable
|
* @returns {Observable} Returns an observable
|
||||||
*/
|
*/
|
||||||
willUnload: EventEmitter<any>;
|
willUnload: EventEmitter<any> = new EventEmitter();
|
||||||
|
|
||||||
/** @private */
|
/** @private */
|
||||||
data: any;
|
data: any;
|
||||||
@ -105,12 +105,6 @@ export class ViewController {
|
|||||||
this.data = (data instanceof NavParams ? data.data : (isPresent(data) ? data : {}));
|
this.data = (data instanceof NavParams ? data.data : (isPresent(data) ? data : {}));
|
||||||
|
|
||||||
this._cssClass = rootCssClass;
|
this._cssClass = rootCssClass;
|
||||||
|
|
||||||
this.willEnter = new EventEmitter();
|
|
||||||
this.didEnter = new EventEmitter();
|
|
||||||
this.willLeave = new EventEmitter();
|
|
||||||
this.didLeave = new EventEmitter();
|
|
||||||
this.willUnload = new EventEmitter();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -220,13 +214,13 @@ export class ViewController {
|
|||||||
*/
|
*/
|
||||||
enableBack(): boolean {
|
enableBack(): boolean {
|
||||||
// update if it's possible to go back from this nav item
|
// update if it's possible to go back from this nav item
|
||||||
if (this._nav) {
|
if (!this._nav) {
|
||||||
let previousItem = this._nav.getPrevious(this);
|
return false;
|
||||||
// the previous view may exist, but if it's about to be destroyed
|
|
||||||
// it shouldn't be able to go back to
|
|
||||||
return !!(previousItem);
|
|
||||||
}
|
}
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -278,6 +272,13 @@ export class ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
getZIndex(): number {
|
||||||
|
return this._zIndex;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* DOM WRITE
|
* DOM WRITE
|
||||||
|
@ -55,6 +55,7 @@ export const mockIonicApp = function(app: App, config: Config, platform: Platfor
|
|||||||
appRoot._loadingPortal = mockOverlayPortal(app, config, platform);
|
appRoot._loadingPortal = mockOverlayPortal(app, config, platform);
|
||||||
appRoot._toastPortal = mockOverlayPortal(app, config, platform);
|
appRoot._toastPortal = mockOverlayPortal(app, config, platform);
|
||||||
appRoot._overlayPortal = mockOverlayPortal(app, config, platform);
|
appRoot._overlayPortal = mockOverlayPortal(app, config, platform);
|
||||||
|
appRoot._modalPortal = mockOverlayPortal(app, config, platform);
|
||||||
|
|
||||||
return appRoot;
|
return appRoot;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user