diff --git a/angular/src/directives/navigation/href-delegate.ts b/angular/src/directives/navigation/href-delegate.ts index 6c224d4fc92..272c1e61dda 100644 --- a/angular/src/directives/navigation/href-delegate.ts +++ b/angular/src/directives/navigation/href-delegate.ts @@ -1,20 +1,15 @@ import { Directive, ElementRef, HostListener, Input, Optional } from '@angular/core'; import { Router } from '@angular/router'; -import { NavController, NavIntent } from '../../providers/nav-controller'; +import { NavController, NavDirection } from '../../providers/nav-controller'; -export type RouterDirection = 'forward' | 'back' | 'root' | 'auto'; @Directive({ - selector: '[routerDirection],ion-anchor,ion-button,ion-item' + selector: '[routerLink],[routerDirection],ion-anchor,ion-button,ion-item' }) export class HrefDelegate { - @Input() routerDirection: RouterDirection = 'forward'; - - @Input() - set routerLink(_: any) { - this.elementRef.nativeElement.button = true; - } + @Input() routerLink: any; + @Input() routerDirection: NavDirection = 'forward'; @Input() set href(value: string) { @@ -33,19 +28,13 @@ export class HrefDelegate { @HostListener('click', ['$event']) onClick(ev: Event) { const url = this.href; - if (this.router && url != null && url[0] !== '#' && url.indexOf('://') === -1) { + if (this.routerDirection) { + this.navCtrl.setDirection(this.routerDirection); + } + + if (!this.routerLink && this.router && url != null && url[0] !== '#' && url.indexOf('://') === -1) { ev.preventDefault(); - this.navCtrl.setIntent(textToIntent(this.routerDirection)); this.router.navigateByUrl(url); } } } - -function textToIntent(direction: RouterDirection) { - switch (direction) { - case 'forward': return NavIntent.Forward; - case 'back': return NavIntent.Back; - case 'root': return NavIntent.Root; - default: return NavIntent.Auto; - } -} diff --git a/angular/src/directives/navigation/ion-back-button.ts b/angular/src/directives/navigation/ion-back-button.ts index 51ca6e31641..30aec164e4b 100644 --- a/angular/src/directives/navigation/ion-back-button.ts +++ b/angular/src/directives/navigation/ion-back-button.ts @@ -1,6 +1,6 @@ import { Directive, ElementRef, HostListener, Input, Optional } from '@angular/core'; import { Router } from '@angular/router'; -import { NavController, NavIntent } from '../../providers/nav-controller'; +import { NavController } from '../../providers/nav-controller'; import { IonRouterOutlet } from './ion-router-outlet'; @Directive({ @@ -29,8 +29,7 @@ export class IonBackButton { this.routerOutlet.pop(); ev.preventDefault(); } else if (this.router && this.defaultHref != null) { - this.navCtrl.setIntent(NavIntent.Back); - this.router.navigateByUrl(this.defaultHref); + this.navCtrl.navigateBack(this.defaultHref); ev.preventDefault(); } } diff --git a/angular/src/directives/navigation/stack-controller.ts b/angular/src/directives/navigation/stack-controller.ts index 332eb62dead..fd758490492 100644 --- a/angular/src/directives/navigation/stack-controller.ts +++ b/angular/src/directives/navigation/stack-controller.ts @@ -1,7 +1,7 @@ import { ComponentRef, NgZone } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; -import { NavController } from '../../providers/nav-controller'; +import { NavController, NavDirection } from '../../providers/nav-controller'; export class StackController { @@ -32,7 +32,7 @@ export class StackController { return this.views.find(vw => vw.url === activatedUrlKey); } - async setActive(enteringView: RouteView, direction: number, animated: boolean) { + async setActive(enteringView: RouteView, direction: NavDirection, animated: boolean) { const leavingView = this.getActive(); this.insertView(enteringView, direction); await this.transition(enteringView, leavingView, direction, animated, this.canGoBack(1), false); @@ -54,7 +54,7 @@ export class StackController { this.transition( this.views[this.views.length - 2], // entering view this.views[this.views.length - 1], // leaving view - -1, + 'back', true, true, true @@ -69,7 +69,7 @@ export class StackController { } - private insertView(enteringView: RouteView, direction: number) { + private insertView(enteringView: RouteView, direction: NavDirection) { // no stack if (!this.stack) { this.views = [enteringView]; @@ -77,7 +77,7 @@ export class StackController { } // stack setRoot - if (direction === 0) { + if (direction === 'root') { this.views = [enteringView]; return; } @@ -87,7 +87,7 @@ export class StackController { if (index >= 0) { this.views = this.views.slice(0, index + 1); } else { - if (direction === 1) { + if (direction === 'forward') { this.views.push(enteringView); } else { this.views = [enteringView]; @@ -120,7 +120,7 @@ export class StackController { private async transition( enteringView: RouteView | undefined, leavingView: RouteView | undefined, - direction: number, + direction: NavDirection, animated: boolean, showGoBack: boolean, progressAnimation: boolean @@ -145,7 +145,7 @@ export class StackController { await containerEl.componentOnReady(); this.runningTransition = containerEl.commit(enteringEl, leavingEl, { duration: !animated ? 0 : undefined, - direction: direction === 1 ? 'forward' : 'back', + direction: direction === 'forward' ? 'forward' : 'back', // TODO: refactor deepWait: true, showGoBack, progressAnimation diff --git a/angular/src/directives/navigation/tabs-delegate.ts b/angular/src/directives/navigation/tabs-delegate.ts index 406748fc216..2f46969fb1a 100644 --- a/angular/src/directives/navigation/tabs-delegate.ts +++ b/angular/src/directives/navigation/tabs-delegate.ts @@ -8,7 +8,7 @@ import { NavController } from '../../providers'; }) export class TabsDelegate { - @ContentChildren(TabDelegate) tabs: QueryList; + @ContentChildren(TabDelegate) tabs!: QueryList; constructor( @Optional() private navCtrl: NavController, @@ -23,9 +23,8 @@ export class TabsDelegate { return tabDelegate ? tabDelegate.getLastUrl() : undefined; } - @HostListener('ionTabButtonClick', ['$event']) - onTabbarClick(ev: any) { - const detail = ev.detail as TabButtonClickDetail; + @HostListener('ionTabButtonClick', ['$event.detail']) + onTabbarClick(detail: TabButtonClickDetail) { const { tab, href, selected } = detail; if (tab && href) { const url = selected diff --git a/angular/src/directives/virtual-scroll/virtual-scroll.ts b/angular/src/directives/virtual-scroll/virtual-scroll.ts index a26486e2126..3e7f6b2b085 100644 --- a/angular/src/directives/virtual-scroll/virtual-scroll.ts +++ b/angular/src/directives/virtual-scroll/virtual-scroll.ts @@ -20,9 +20,9 @@ import { VirtualContext } from './virtual-utils'; }) export class VirtualScroll { - @ContentChild(VirtualItem) itmTmp: VirtualItem; - @ContentChild(VirtualHeader) hdrTmp: VirtualHeader; - @ContentChild(VirtualFooter) ftrTmp: VirtualFooter; + @ContentChild(VirtualItem) itmTmp!: VirtualItem; + @ContentChild(VirtualHeader) hdrTmp!: VirtualHeader; + @ContentChild(VirtualFooter) ftrTmp!: VirtualFooter; constructor( private el: ElementRef, diff --git a/angular/src/providers/nav-controller.ts b/angular/src/providers/nav-controller.ts index 122f65100be..007e016b4c8 100644 --- a/angular/src/providers/nav-controller.ts +++ b/angular/src/providers/nav-controller.ts @@ -1,110 +1,96 @@ -import { Injectable, Optional } from '@angular/core'; +import { Injectable } from '@angular/core'; import { Location } from '@angular/common'; -import { NavigationExtras, Router, UrlTree } from '@angular/router'; -import { BackButtonEvent } from '@ionic/core'; +import { NavigationExtras, NavigationStart, Router, UrlTree } from '@angular/router'; +import { Platform } from './platform'; -export const enum NavIntent { - Auto, - Forward, - Back, - Root -} +export type NavDirection = 'forward' | 'back' | 'root' | 'auto'; @Injectable() export class NavController { - private intent: NavIntent = NavIntent.Root; - private animated = true; - private stack: string[] = []; + private direction: NavDirection = DEFAULT_DIRECTION; + private animated = DEFAULT_ANIMATED; + private guessDirection: NavDirection = 'root'; + private lastNavId = -1; constructor( private location: Location, - @Optional() private router?: Router + private router: Router, + platform: Platform ) { - window && window.document.addEventListener('ionBackButton', (ev) => { - (ev as BackButtonEvent).detail.register(0, () => this.goBack()); + // Subscribe to router events to detect direction + router.events.subscribe(ev => { + if (ev instanceof NavigationStart) { + const id = (ev.restoredState) ? ev.restoredState.navigationId : ev.id; + this.guessDirection = id < this.lastNavId ? 'back' : 'forward'; + this.lastNavId = id; + } }); + + // Subscribe to backButton events + platform.backButton.subscribeWithPriority(0, () => this.goBack()); } navigateForward(url: string | UrlTree | any[], animated?: boolean, extras?: NavigationExtras) { - this.setIntent(NavIntent.Forward, animated); + this.setDirection('forward', animated); if (Array.isArray(url)) { - return this.router!.navigate(url, extras); + return this.router.navigate(url, extras); } else { - return this.router!.navigateByUrl(url, extras); + return this.router.navigateByUrl(url, extras); } } navigateBack(url: string | UrlTree | any[], animated?: boolean, extras?: NavigationExtras) { - this.setIntent(NavIntent.Back, animated); - extras = { replaceUrl: true, ...extras }; + this.setDirection('back', animated); + // extras = { replaceUrl: true, ...extras }; if (Array.isArray(url)) { - return this.router!.navigate(url, extras); + return this.router.navigate(url, extras); } else { - return this.router!.navigateByUrl(url, extras); + return this.router.navigateByUrl(url, extras); } } navigateRoot(url: string | UrlTree | any[], animated?: boolean, extras?: NavigationExtras) { - this.setIntent(NavIntent.Root, animated); + this.setDirection('root', animated); if (Array.isArray(url)) { - return this.router!.navigate(url, extras); + return this.router.navigate(url, extras); } else { - return this.router!.navigateByUrl(url, extras); + return this.router.navigateByUrl(url, extras); } } goBack(animated?: boolean) { - this.setIntent(NavIntent.Back, animated); + this.setDirection('back', animated); return this.location.back(); } - setIntent(intent: NavIntent, animated?: boolean) { - this.intent = intent; + setDirection(direction: NavDirection, animated?: boolean) { + this.direction = direction; this.animated = (animated === undefined) - ? intent !== NavIntent.Root + ? direction !== 'root' : animated; } consumeTransition() { - const guessDirection = this.guessDirection(); - - let direction = 0; + let direction: NavDirection = 'root'; let animated = false; - if (this.intent === NavIntent.Auto) { - direction = guessDirection; - animated = direction !== 0; + if (this.direction === 'auto') { + direction = this.guessDirection; + animated = direction !== 'root'; } else { animated = this.animated; - direction = intentToDirection(this.intent); + direction = this.direction; } - this.intent = NavIntent.Root; - this.animated = false; + this.direction = DEFAULT_DIRECTION; + this.animated = DEFAULT_ANIMATED; return { direction, animated }; } - - private guessDirection() { - const index = this.stack.indexOf(document.location!.href); - if (index === -1) { - this.stack.push(document.location!.href); - return 1; - } else if (index < this.stack.length - 1) { - this.stack = this.stack.slice(0, index + 1); - return -1; - } - return 0; - } } -function intentToDirection(intent: NavIntent): number { - switch (intent) { - case NavIntent.Forward: return 1; - case NavIntent.Back: return -1; - default: return 0; - } -} +const DEFAULT_DIRECTION = 'auto'; +const DEFAULT_ANIMATED = false;