mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-16 18:17:31 +08:00
@ -2,6 +2,8 @@ import { ComponentRef, NgZone } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
import { NavController, NavDirection } from '../../providers/nav-controller';
|
||||
import { RouterDirection } from '@ionic/core';
|
||||
import { RouteView, computeStackId, destroyView, getUrl, insertView, isTabSwitch, toSegments } from './stack-utils';
|
||||
|
||||
|
||||
export class StackController {
|
||||
@ -10,50 +12,65 @@ export class StackController {
|
||||
private views: RouteView[] = [];
|
||||
private runningTransition?: Promise<boolean>;
|
||||
private skipTransition = false;
|
||||
private tabsPrefix: string[] | undefined;
|
||||
private activeView: RouteView | undefined;
|
||||
private nextId = 0;
|
||||
|
||||
constructor(
|
||||
private stack: boolean,
|
||||
tabsPrefix: string | undefined,
|
||||
private containerEl: HTMLIonRouterOutletElement,
|
||||
private router: Router,
|
||||
private navCtrl: NavController,
|
||||
private zone: NgZone,
|
||||
) {}
|
||||
) {
|
||||
this.tabsPrefix = tabsPrefix ? toSegments(tabsPrefix) : undefined;
|
||||
}
|
||||
|
||||
createView(enteringRef: ComponentRef<any>, activatedRoute: ActivatedRoute): RouteView {
|
||||
const url = getUrl(this.router, activatedRoute);
|
||||
return {
|
||||
id: this.nextId++,
|
||||
ref: enteringRef,
|
||||
element: (enteringRef && enteringRef.location && enteringRef.location.nativeElement) as HTMLElement,
|
||||
url: this.getUrl(activatedRoute)
|
||||
stackId: computeStackId(this.tabsPrefix, url),
|
||||
url,
|
||||
};
|
||||
}
|
||||
|
||||
getExistingView(activatedRoute: ActivatedRoute): RouteView | undefined {
|
||||
const activatedUrlKey = this.getUrl(activatedRoute);
|
||||
const activatedUrlKey = getUrl(this.router, activatedRoute);
|
||||
return this.views.find(vw => vw.url === activatedUrlKey);
|
||||
}
|
||||
|
||||
async setActive(enteringView: RouteView, direction: NavDirection, animated: boolean) {
|
||||
const leavingView = this.getActive();
|
||||
async setActive(enteringView: RouteView) {
|
||||
let { direction, animated } = this.navCtrl.consumeTransition();
|
||||
const leavingView = this.activeView;
|
||||
if (isTabSwitch(enteringView, leavingView)) {
|
||||
direction = 'back';
|
||||
animated = false;
|
||||
}
|
||||
this.insertView(enteringView, direction);
|
||||
await this.transition(enteringView, leavingView, direction, animated, this.canGoBack(1), false);
|
||||
this.cleanup();
|
||||
}
|
||||
|
||||
canGoBack(deep: number): boolean {
|
||||
return this.views.length > deep;
|
||||
canGoBack(deep: number, stackId = this.getActiveStackId()): boolean {
|
||||
return this.getStack(stackId).length > deep;
|
||||
}
|
||||
|
||||
pop(deep: number) {
|
||||
pop(deep: number, stackId = this.getActiveStackId()) {
|
||||
this.zone.run(() => {
|
||||
const view = this.views[this.views.length - deep - 1];
|
||||
const views = this.getStack(stackId);
|
||||
const view = views[views.length - deep - 1];
|
||||
this.navCtrl.navigateBack(view.url);
|
||||
});
|
||||
}
|
||||
|
||||
startBackTransition() {
|
||||
startBackTransition(stackId?: string) {
|
||||
const views = this.getStack(stackId);
|
||||
this.transition(
|
||||
this.views[this.views.length - 2], // entering view
|
||||
this.views[this.views.length - 1], // leaving view
|
||||
views[views.length - 2], // entering view
|
||||
views[views.length - 1], // leaving view
|
||||
'back',
|
||||
true,
|
||||
true,
|
||||
@ -68,55 +85,41 @@ export class StackController {
|
||||
}
|
||||
}
|
||||
|
||||
getLastUrl(stackId?: string) {
|
||||
const views = this.getStack(stackId);
|
||||
return views.length > 0 ? views[views.length - 1] : undefined;
|
||||
}
|
||||
|
||||
private insertView(enteringView: RouteView, direction: NavDirection) {
|
||||
// no stack
|
||||
if (!this.stack) {
|
||||
this.views = [enteringView];
|
||||
return;
|
||||
}
|
||||
private getActiveStackId(): string | undefined {
|
||||
return this.activeView ? this.activeView.stackId : undefined;
|
||||
}
|
||||
|
||||
// stack setRoot
|
||||
if (direction === 'root') {
|
||||
this.views = [enteringView];
|
||||
return;
|
||||
}
|
||||
private getStack(stackId: string | undefined) {
|
||||
return this.views.filter(v => v.stackId === stackId);
|
||||
}
|
||||
|
||||
// stack
|
||||
const index = this.views.indexOf(enteringView);
|
||||
if (index >= 0) {
|
||||
this.views = this.views.slice(0, index + 1);
|
||||
} else {
|
||||
if (direction === 'forward') {
|
||||
this.views.push(enteringView);
|
||||
} else {
|
||||
this.views = [enteringView];
|
||||
}
|
||||
}
|
||||
private insertView(enteringView: RouteView, direction: RouterDirection) {
|
||||
this.activeView = enteringView;
|
||||
this.views = insertView(this.views, enteringView, direction);
|
||||
}
|
||||
|
||||
private cleanup() {
|
||||
const activeRoute = this.activeView;
|
||||
const views = this.views;
|
||||
this.viewsSnapshot
|
||||
.filter(view => !views.includes(view))
|
||||
.forEach(view => destroyView(view));
|
||||
|
||||
for (let i = 0; i < views.length - 1; i++) {
|
||||
const view = views[i];
|
||||
const element = view.element;
|
||||
element.setAttribute('aria-hidden', 'true');
|
||||
element.classList.add('ion-page-hidden');
|
||||
// TODO
|
||||
// view.ref.changeDetectorRef.detach();
|
||||
}
|
||||
views.forEach(view => {
|
||||
if (view !== activeRoute) {
|
||||
const element = view.element;
|
||||
element.setAttribute('aria-hidden', 'true');
|
||||
element.classList.add('ion-page-hidden');
|
||||
}
|
||||
});
|
||||
this.viewsSnapshot = views.slice();
|
||||
}
|
||||
|
||||
getActive(): RouteView | undefined {
|
||||
const views = this.views;
|
||||
return views.length > 0 ? views[views.length - 1] : undefined;
|
||||
}
|
||||
|
||||
private async transition(
|
||||
enteringView: RouteView | undefined,
|
||||
leavingView: RouteView | undefined,
|
||||
@ -158,23 +161,4 @@ export class StackController {
|
||||
await this.runningTransition;
|
||||
}
|
||||
}
|
||||
|
||||
private getUrl(activatedRoute: ActivatedRoute) {
|
||||
const urlTree = this.router.createUrlTree(['.'], { relativeTo: activatedRoute });
|
||||
return this.router.serializeUrl(urlTree);
|
||||
}
|
||||
}
|
||||
|
||||
function destroyView(view: RouteView) {
|
||||
if (view) {
|
||||
// TODO lifecycle event
|
||||
view.ref.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
export interface RouteView {
|
||||
url: string;
|
||||
element: HTMLElement;
|
||||
ref: ComponentRef<any>;
|
||||
savedData?: any;
|
||||
}
|
||||
|
Reference in New Issue
Block a user