mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-20 20:33:32 +08:00
feat(loading): add internal stack for the loading service
this allows the user to push multiple loading indicators on top of each other without interfering with the page stack, as well as navigation between pages behind the loading indicator. references #5426
This commit is contained in:
@ -99,10 +99,12 @@ export class Loading extends ViewController {
|
|||||||
|
|
||||||
constructor(opts: LoadingOptions = {}) {
|
constructor(opts: LoadingOptions = {}) {
|
||||||
opts.showBackdrop = isPresent(opts.showBackdrop) ? !!opts.showBackdrop : true;
|
opts.showBackdrop = isPresent(opts.showBackdrop) ? !!opts.showBackdrop : true;
|
||||||
|
opts.dismissOnPageChange = isPresent(opts.dismissOnPageChange) ? !!opts.dismissOnPageChange : false;
|
||||||
|
|
||||||
super(LoadingCmp, opts);
|
super(LoadingCmp, opts);
|
||||||
this.viewType = 'loading';
|
this.viewType = 'loading';
|
||||||
this.isOverlay = true;
|
this.isOverlay = true;
|
||||||
|
this.usePortal = true;
|
||||||
|
|
||||||
// by default, loading indicators should not fire lifecycle events of other views
|
// by default, loading indicators should not fire lifecycle events of other views
|
||||||
// for example, when an loading indicators enters, the current active view should
|
// for example, when an loading indicators enters, the current active view should
|
||||||
|
@ -8,6 +8,7 @@ import {Keyboard} from '../../util/keyboard';
|
|||||||
import {NavParams} from './nav-params';
|
import {NavParams} from './nav-params';
|
||||||
import {NavRouter} from './nav-router';
|
import {NavRouter} from './nav-router';
|
||||||
import {pascalCaseToDashCase, isTrueProperty, isBlank} from '../../util/util';
|
import {pascalCaseToDashCase, isTrueProperty, isBlank} from '../../util/util';
|
||||||
|
import {Portal} from './nav-portal';
|
||||||
import {raf} from '../../util/dom';
|
import {raf} from '../../util/dom';
|
||||||
import {SwipeBackGesture} from './swipe-back';
|
import {SwipeBackGesture} from './swipe-back';
|
||||||
import {Transition} from '../../transitions/transition';
|
import {Transition} from '../../transitions/transition';
|
||||||
@ -109,6 +110,7 @@ export class NavController extends Ion {
|
|||||||
private _trans: Transition;
|
private _trans: Transition;
|
||||||
private _sbGesture: SwipeBackGesture;
|
private _sbGesture: SwipeBackGesture;
|
||||||
private _sbThreshold: number;
|
private _sbThreshold: number;
|
||||||
|
private _portal: Portal;
|
||||||
|
|
||||||
protected _sbEnabled: boolean;
|
protected _sbEnabled: boolean;
|
||||||
protected _ids: number = -1;
|
protected _ids: number = -1;
|
||||||
@ -171,6 +173,10 @@ export class NavController extends Ion {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setPortal(val: Portal) {
|
||||||
|
this._portal = val;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the root for the current navigation stack
|
* Set the root for the current navigation stack
|
||||||
* @param {Type} page The name of the component you want to push on the navigation stack
|
* @param {Type} page The name of the component you want to push on the navigation stack
|
||||||
@ -412,7 +418,7 @@ export class NavController extends Ion {
|
|||||||
if (rootNav['_tabs']) {
|
if (rootNav['_tabs']) {
|
||||||
// TODO: must have until this goes in
|
// TODO: must have until this goes in
|
||||||
// https://github.com/angular/angular/issues/5481
|
// https://github.com/angular/angular/issues/5481
|
||||||
console.error('A parent <ion-nav> is required for ActionSheet/Alert/Modal');
|
console.error('A parent <ion-nav> is required for ActionSheet/Alert/Modal/Loading');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,6 +441,11 @@ export class NavController extends Ion {
|
|||||||
animation: enteringView.getTransitionName('back')
|
animation: enteringView.getTransitionName('back')
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (enteringView.usePortal && this._portal) {
|
||||||
|
this._portal.present(enteringView);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// start the transition
|
// start the transition
|
||||||
return rootNav._insertViews(-1, [enteringView], opts);
|
return rootNav._insertViews(-1, [enteringView], opts);
|
||||||
}
|
}
|
||||||
@ -534,7 +545,7 @@ export class NavController extends Ion {
|
|||||||
|
|
||||||
if (this._views[i] === enteringView) {
|
if (this._views[i] === enteringView) {
|
||||||
// cool, so the last valid view is also our entering view!!
|
// cool, so the last valid view is also our entering view!!
|
||||||
// this means we should animate that bad boy in so its the active view
|
// this means we should animate that bad boy in so it's the active view
|
||||||
// return a promise and resolve when the transition has completed
|
// return a promise and resolve when the transition has completed
|
||||||
|
|
||||||
// get the leaving view which the _insert() already set
|
// get the leaving view which the _insert() already set
|
||||||
@ -730,8 +741,8 @@ export class NavController extends Ion {
|
|||||||
// get the view thats ready to enter
|
// get the view thats ready to enter
|
||||||
let enteringView = this.getByState(STATE_INIT_ENTER);
|
let enteringView = this.getByState(STATE_INIT_ENTER);
|
||||||
|
|
||||||
if (!enteringView) {
|
if (!enteringView && this._portal) {
|
||||||
// oh knows! no entering view to go to!
|
// oh nos! no entering view to go to!
|
||||||
// if there is no previous view that would enter in this nav stack
|
// if there is no previous view that would enter in this nav stack
|
||||||
// and the option is set to climb up the nav parent looking
|
// and the option is set to climb up the nav parent looking
|
||||||
// for the next nav we could transition to instead
|
// for the next nav we could transition to instead
|
||||||
@ -1249,6 +1260,14 @@ export class NavController extends Ion {
|
|||||||
// see if we should add the swipe back gesture listeners or not
|
// see if we should add the swipe back gesture listeners or not
|
||||||
this._sbCheck();
|
this._sbCheck();
|
||||||
|
|
||||||
|
if (this._portal) {
|
||||||
|
this._portal._views.forEach(view => {
|
||||||
|
if (view.data && view.data.dismissOnPageChange) {
|
||||||
|
view.dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// darn, so this wasn't the most recent transition
|
// darn, so this wasn't the most recent transition
|
||||||
// so while this one did end, there's another more recent one
|
// so while this one did end, there's another more recent one
|
||||||
@ -1640,7 +1659,7 @@ export class NavController extends Ion {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
// this is the initial view
|
// this is the initial view
|
||||||
enteringView.setZIndex(INIT_ZINDEX, this._renderer);
|
enteringView.setZIndex(this._portal ? INIT_ZINDEX : PORTAL_ZINDEX, this._renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (direction === 'back') {
|
} else if (direction === 'back') {
|
||||||
@ -1680,5 +1699,6 @@ const STATE_REMOVE = 'remove';
|
|||||||
const STATE_REMOVE_AFTER_TRANS = 'remove_after_trans';
|
const STATE_REMOVE_AFTER_TRANS = 'remove_after_trans';
|
||||||
const STATE_FORCE_ACTIVE = 'force_active';
|
const STATE_FORCE_ACTIVE = 'force_active';
|
||||||
const INIT_ZINDEX = 100;
|
const INIT_ZINDEX = 100;
|
||||||
|
const PORTAL_ZINDEX = 9999;
|
||||||
|
|
||||||
let ctrlIds = -1;
|
let ctrlIds = -1;
|
||||||
|
30
ionic/components/nav/nav-portal.ts
Normal file
30
ionic/components/nav/nav-portal.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import {Directive, ElementRef, Input, Optional, NgZone, Compiler, AppViewManager, Renderer, Type, ContentChild} from 'angular2/core';
|
||||||
|
|
||||||
|
import {IonicApp} from '../app/app';
|
||||||
|
import {Config} from '../../config/config';
|
||||||
|
import {Keyboard} from '../../util/keyboard';
|
||||||
|
import {NavController} from './nav-controller';
|
||||||
|
import {ViewController} from './view-controller';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
@Directive({
|
||||||
|
selector: '[portal]'
|
||||||
|
})
|
||||||
|
export class Portal extends NavController {
|
||||||
|
constructor(
|
||||||
|
@Optional() hostNavCtrl: NavController,
|
||||||
|
@Optional() viewCtrl: ViewController,
|
||||||
|
app: IonicApp,
|
||||||
|
config: Config,
|
||||||
|
keyboard: Keyboard,
|
||||||
|
elementRef: ElementRef,
|
||||||
|
compiler: Compiler,
|
||||||
|
viewManager: AppViewManager,
|
||||||
|
zone: NgZone,
|
||||||
|
renderer: Renderer
|
||||||
|
) {
|
||||||
|
super(hostNavCtrl, app, config, keyboard, elementRef, null, compiler, viewManager, zone, renderer);
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,11 @@
|
|||||||
import {Component, ElementRef, Input, Optional, NgZone, Compiler, AppViewManager, Renderer, Type} from 'angular2/core';
|
import {Component, ElementRef, Input, Optional, NgZone, Compiler, AppViewManager, Renderer, Type, ViewChild} from 'angular2/core';
|
||||||
|
|
||||||
import {IonicApp} from '../app/app';
|
import {IonicApp} from '../app/app';
|
||||||
import {Config} from '../../config/config';
|
import {Config} from '../../config/config';
|
||||||
import {Keyboard} from '../../util/keyboard';
|
import {Keyboard} from '../../util/keyboard';
|
||||||
import {isTrueProperty} from '../../util/util';
|
import {isTrueProperty} from '../../util/util';
|
||||||
import {NavController} from './nav-controller';
|
import {NavController} from './nav-controller';
|
||||||
|
import {Portal} from './nav-portal';
|
||||||
import {ViewController} from './view-controller';
|
import {ViewController} from './view-controller';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -104,7 +105,8 @@ import {ViewController} from './view-controller';
|
|||||||
*/
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ion-nav',
|
selector: 'ion-nav',
|
||||||
template: '<div #contents></div>'
|
template: '<div #contents></div><div portal></div>',
|
||||||
|
directives: [Portal]
|
||||||
})
|
})
|
||||||
export class Nav extends NavController {
|
export class Nav extends NavController {
|
||||||
private _root: Type;
|
private _root: Type;
|
||||||
@ -173,4 +175,8 @@ export class Nav extends NavController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ViewChild(Portal)
|
||||||
|
private set _navPortal(val: Portal) {
|
||||||
|
this.setPortal(val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1237,6 +1237,8 @@ export function run() {
|
|||||||
setElementStyle: function(){}
|
setElementStyle: function(){}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nav._portal = new NavController(null, null, config, null, elementRef, null, null, null, null, null);
|
||||||
|
|
||||||
return nav;
|
return nav;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +77,11 @@ export class ViewController {
|
|||||||
*/
|
*/
|
||||||
isOverlay: boolean = false;
|
isOverlay: boolean = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
usePortal: boolean = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user