UNPKG

@ionic/angular

Version:

Angular specific wrappers for @ionic/core

188 lines 8.81 kB
import { Directive, HostListener, Input, Optional } from '@angular/core'; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; import * as i2 from "../../providers/nav-controller"; import * as i3 from "@angular/router"; /** * Adds support for Ionic routing directions and animations to the base Angular router link directive. * * When the router link is clicked, the directive will assign the direction and * animation so that the routing integration will transition correctly. */ export class RouterLinkDelegateDirective { locationStrategy; navCtrl; elementRef; router; routerLink; routerDirection = 'forward'; routerAnimation; constructor(locationStrategy, navCtrl, elementRef, router, routerLink) { this.locationStrategy = locationStrategy; this.navCtrl = navCtrl; this.elementRef = elementRef; this.router = router; this.routerLink = routerLink; } ngOnInit() { this.updateTargetUrlAndHref(); this.updateTabindex(); /** * Ionic components like `ion-item` render a native anchor in their shadow DOM, * so a modifier click (ctrl/meta/shift/alt) or a non-`_self` target should let * the browser handle the navigation natively (new tab, new window, download) * instead of navigating in-app. * * We listen in the capture phase so this runs before Angular's `RouterLink` * handler and our own bubble-phase `onClick`. On a native-navigation intent it * stops propagation to cancel the in-app navigation, but leaves `preventDefault` * alone so the native anchor can still act. */ this.elementRef.nativeElement.addEventListener('click', this.onCaptureClick, { capture: true }); } ngOnChanges() { this.updateTargetUrlAndHref(); } ngOnDestroy() { this.elementRef.nativeElement.removeEventListener('click', this.onCaptureClick, { capture: true }); } onCaptureClick = (ev) => { if (this.opensNatively(ev)) { ev.stopImmediatePropagation(); } }; /** * True when the browser should handle the click natively instead of routing * in-app: a modifier was held (ctrl/meta/shift/alt), or the host targets * something other than `_self`. This mirrors the modifier set Angular's own * `RouterLink` guards on, so an Ionic `routerLink` behaves like a plain anchor * for new-tab, new-window, and download intents. */ opensNatively(ev) { if (ev instanceof MouseEvent && (ev.ctrlKey || ev.metaKey || ev.shiftKey || ev.altKey)) { return true; } const target = this.elementRef.nativeElement.target; return target != null && target !== '' && target !== '_self'; } /** * The `tabindex` is set to `0` by default on the host element when * the `routerLink` directive is used. This causes issues with Ionic * components that wrap an `a` or `button` element, such as `ion-item`. * See issue https://github.com/angular/angular/issues/28345 * * This method removes the `tabindex` attribute from the host element * to allow the Ionic component to manage the focus state correctly. */ updateTabindex() { // Ionic components that render a native anchor or button element const ionicComponents = [ 'ION-BACK-BUTTON', 'ION-BREADCRUMB', 'ION-BUTTON', 'ION-CARD', 'ION-FAB-BUTTON', 'ION-ITEM', 'ION-ITEM-OPTION', 'ION-MENU-BUTTON', 'ION-SEGMENT-BUTTON', 'ION-TAB-BUTTON', ]; const hostElement = this.elementRef.nativeElement; if (ionicComponents.includes(hostElement.tagName)) { if (hostElement.getAttribute('tabindex') === '0') { hostElement.removeAttribute('tabindex'); } } } updateTargetUrlAndHref() { if (this.routerLink?.urlTree) { const href = this.locationStrategy.prepareExternalUrl(this.router.serializeUrl(this.routerLink.urlTree)); this.elementRef.nativeElement.href = href; } } /** * @internal */ onClick(ev) { this.navCtrl.setDirection(this.routerDirection, undefined, undefined, this.routerAnimation); /** * This prevents the browser from * performing a page reload when pressing * an Ionic component with routerLink. * The page reload interferes with routing * and causes ion-back-button to disappear * since the local history is wiped on reload. */ ev.preventDefault(); } /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RouterLinkDelegateDirective, deps: [{ token: i1.LocationStrategy }, { token: i2.NavController }, { token: i0.ElementRef }, { token: i3.Router }, { token: i3.RouterLink, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); /** @nocollapse */ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.0", type: RouterLinkDelegateDirective, isStandalone: true, selector: ":not(a):not(area)[routerLink]", inputs: { routerDirection: "routerDirection", routerAnimation: "routerAnimation" }, host: { listeners: { "click": "onClick($event)" } }, usesOnChanges: true, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RouterLinkDelegateDirective, decorators: [{ type: Directive, args: [{ selector: ':not(a):not(area)[routerLink]', }] }], ctorParameters: () => [{ type: i1.LocationStrategy }, { type: i2.NavController }, { type: i0.ElementRef }, { type: i3.Router }, { type: i3.RouterLink, decorators: [{ type: Optional }] }], propDecorators: { routerDirection: [{ type: Input }], routerAnimation: [{ type: Input }], onClick: [{ type: HostListener, args: ['click', ['$event']] }] } }); export class RouterLinkWithHrefDelegateDirective { locationStrategy; navCtrl; elementRef; router; routerLink; routerDirection = 'forward'; routerAnimation; constructor(locationStrategy, navCtrl, elementRef, router, routerLink) { this.locationStrategy = locationStrategy; this.navCtrl = navCtrl; this.elementRef = elementRef; this.router = router; this.routerLink = routerLink; } ngOnInit() { this.updateTargetUrlAndHref(); } ngOnChanges() { this.updateTargetUrlAndHref(); } updateTargetUrlAndHref() { if (this.routerLink?.urlTree) { const href = this.locationStrategy.prepareExternalUrl(this.router.serializeUrl(this.routerLink.urlTree)); this.elementRef.nativeElement.href = href; } } /** * @internal */ onClick() { this.navCtrl.setDirection(this.routerDirection, undefined, undefined, this.routerAnimation); } /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RouterLinkWithHrefDelegateDirective, deps: [{ token: i1.LocationStrategy }, { token: i2.NavController }, { token: i0.ElementRef }, { token: i3.Router }, { token: i3.RouterLink, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); /** @nocollapse */ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.0", type: RouterLinkWithHrefDelegateDirective, isStandalone: true, selector: "a[routerLink],area[routerLink]", inputs: { routerDirection: "routerDirection", routerAnimation: "routerAnimation" }, host: { listeners: { "click": "onClick()" } }, usesOnChanges: true, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RouterLinkWithHrefDelegateDirective, decorators: [{ type: Directive, args: [{ selector: 'a[routerLink],area[routerLink]', }] }], ctorParameters: () => [{ type: i1.LocationStrategy }, { type: i2.NavController }, { type: i0.ElementRef }, { type: i3.Router }, { type: i3.RouterLink, decorators: [{ type: Optional }] }], propDecorators: { routerDirection: [{ type: Input }], routerAnimation: [{ type: Input }], onClick: [{ type: HostListener, args: ['click'] }] } }); //# sourceMappingURL=router-link-delegate.js.map