mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-20 12:29:55 +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 = {}) {
|
||||
opts.showBackdrop = isPresent(opts.showBackdrop) ? !!opts.showBackdrop : true;
|
||||
opts.dismissOnPageChange = isPresent(opts.dismissOnPageChange) ? !!opts.dismissOnPageChange : false;
|
||||
|
||||
super(LoadingCmp, opts);
|
||||
this.viewType = 'loading';
|
||||
this.isOverlay = true;
|
||||
this.usePortal = true;
|
||||
|
||||
// by default, loading indicators should not fire lifecycle events of other views
|
||||
// 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 {NavRouter} from './nav-router';
|
||||
import {pascalCaseToDashCase, isTrueProperty, isBlank} from '../../util/util';
|
||||
import {Portal} from './nav-portal';
|
||||
import {raf} from '../../util/dom';
|
||||
import {SwipeBackGesture} from './swipe-back';
|
||||
import {Transition} from '../../transitions/transition';
|
||||
@ -109,6 +110,7 @@ export class NavController extends Ion {
|
||||
private _trans: Transition;
|
||||
private _sbGesture: SwipeBackGesture;
|
||||
private _sbThreshold: number;
|
||||
private _portal: Portal;
|
||||
|
||||
protected _sbEnabled: boolean;
|
||||
protected _ids: number = -1;
|
||||
@ -170,6 +172,10 @@ export class NavController extends Ion {
|
||||
provide(NavController, {useValue: this})
|
||||
]);
|
||||
}
|
||||
|
||||
setPortal(val: Portal) {
|
||||
this._portal = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the root for the current navigation stack
|
||||
@ -412,7 +418,7 @@ export class NavController extends Ion {
|
||||
if (rootNav['_tabs']) {
|
||||
// TODO: must have until this goes in
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -433,7 +439,12 @@ export class NavController extends Ion {
|
||||
keyboardClose: false,
|
||||
direction: 'back',
|
||||
animation: enteringView.getTransitionName('back')
|
||||
});
|
||||
});
|
||||
|
||||
if (enteringView.usePortal && this._portal) {
|
||||
this._portal.present(enteringView);
|
||||
return;
|
||||
}
|
||||
|
||||
// start the transition
|
||||
return rootNav._insertViews(-1, [enteringView], opts);
|
||||
@ -534,7 +545,7 @@ export class NavController extends Ion {
|
||||
|
||||
if (this._views[i] === enteringView) {
|
||||
// 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
|
||||
|
||||
// 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
|
||||
let enteringView = this.getByState(STATE_INIT_ENTER);
|
||||
|
||||
if (!enteringView) {
|
||||
// oh knows! no entering view to go to!
|
||||
if (!enteringView && this._portal) {
|
||||
// oh nos! no entering view to go to!
|
||||
// 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
|
||||
// for the next nav we could transition to instead
|
||||
@ -1248,6 +1259,14 @@ export class NavController extends Ion {
|
||||
|
||||
// see if we should add the swipe back gesture listeners or not
|
||||
this._sbCheck();
|
||||
|
||||
if (this._portal) {
|
||||
this._portal._views.forEach(view => {
|
||||
if (view.data && view.data.dismissOnPageChange) {
|
||||
view.dismiss();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} else {
|
||||
// darn, so this wasn't the most recent transition
|
||||
@ -1640,7 +1659,7 @@ export class NavController extends Ion {
|
||||
|
||||
} else {
|
||||
// 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') {
|
||||
@ -1680,5 +1699,6 @@ const STATE_REMOVE = 'remove';
|
||||
const STATE_REMOVE_AFTER_TRANS = 'remove_after_trans';
|
||||
const STATE_FORCE_ACTIVE = 'force_active';
|
||||
const INIT_ZINDEX = 100;
|
||||
const PORTAL_ZINDEX = 9999;
|
||||
|
||||
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 {Config} from '../../config/config';
|
||||
import {Keyboard} from '../../util/keyboard';
|
||||
import {isTrueProperty} from '../../util/util';
|
||||
import {NavController} from './nav-controller';
|
||||
import {Portal} from './nav-portal';
|
||||
import {ViewController} from './view-controller';
|
||||
|
||||
/**
|
||||
@ -104,7 +105,8 @@ import {ViewController} from './view-controller';
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ion-nav',
|
||||
template: '<div #contents></div>'
|
||||
template: '<div #contents></div><div portal></div>',
|
||||
directives: [Portal]
|
||||
})
|
||||
export class Nav extends NavController {
|
||||
private _root: Type;
|
||||
@ -172,5 +174,9 @@ export class Nav extends NavController {
|
||||
this.push(this._root);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ViewChild(Portal)
|
||||
private set _navPortal(val: Portal) {
|
||||
this.setPortal(val);
|
||||
}
|
||||
}
|
||||
|
@ -1236,6 +1236,8 @@ export function run() {
|
||||
setElementClass: function(){},
|
||||
setElementStyle: function(){}
|
||||
};
|
||||
|
||||
nav._portal = new NavController(null, null, config, null, elementRef, null, null, null, null, null);
|
||||
|
||||
return nav;
|
||||
}
|
||||
|
@ -77,6 +77,11 @@ export class ViewController {
|
||||
*/
|
||||
isOverlay: boolean = false;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
usePortal: boolean = false;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
Reference in New Issue
Block a user