import { ComponentFactoryResolver, ComponentRef, Directive, HostListener, Inject, Input, OnChanges, OnDestroy, OnInit, ViewContainerRef, } from '@angular/core'; import { DOCUMENT, } from '@angular/common'; import { TooltipMiniComponent, } from './tooltip-mini.component'; import { BrowserDetectorService, } from './../../../helpers/services/index'; @Directive({ selector: '[tooltipMini]', }) export class TooltipMiniDirective implements OnInit, OnChanges, OnDestroy { @Input() public tooltipMini: string; @Input() public onClickVisibleTime = 1500; @Input() public disableOffScreenHandling = false; @Input() public tooltipZIndex = 4; public tooltipMiniComponent: ComponentRef; public onClickTriggered = false; constructor( private _viewContainerRef: ViewContainerRef, private _componentFactoryResolver: ComponentFactoryResolver, @Inject(DOCUMENT) private _document: Document, private _browserDetectorService: BrowserDetectorService, ) {} public ngOnInit() { const componentFactory = this._componentFactoryResolver.resolveComponentFactory( TooltipMiniComponent, ); this.tooltipMiniComponent = this._viewContainerRef.createComponent( componentFactory, ); this._document.body.appendChild( this.tooltipMiniComponent.location.nativeElement, ); this.initTooltipComponentVariables(); } public ngOnChanges() { this.initTooltipComponentVariables(); } public ngOnDestroy() { this.tooltipMiniComponent.destroy(); } public initTooltipComponentVariables() { if (this.tooltipMiniComponent) { this.tooltipMiniComponent.instance.text = this.tooltipMini; this.tooltipMiniComponent.instance.changeDetectorRef.markForCheck(); } } public updateTooltipLocation() { const containerBoundingRect = this._viewContainerRef.element .nativeElement.getBoundingClientRect(); const bodyBoundingRect = this._document.body.getBoundingClientRect(); const expectedLeft = containerBoundingRect.left + (containerBoundingRect.width / 2) - bodyBoundingRect.left; this.tooltipMiniComponent.location.nativeElement .style.display = 'block'; this.tooltipMiniComponent.location.nativeElement .style.position = 'absolute'; this.tooltipMiniComponent.location.nativeElement .style.transform = 'translate(-50%, -100%)'; this.tooltipMiniComponent.location.nativeElement .style.left = expectedLeft + 'px'; this.tooltipMiniComponent.location.nativeElement .style.top = containerBoundingRect.top - bodyBoundingRect.top + 'px'; this.tooltipMiniComponent.location.nativeElement.style.zIndex = this.tooltipZIndex; if (!this.disableOffScreenHandling) { this.handleBeingOffScreen(); } } public handleBeingOffScreen() { setTimeout(() => { const boundingRect = this.tooltipMiniComponent.location .nativeElement.getBoundingClientRect(); if (boundingRect.left < 0) { this.tooltipMiniComponent.instance.expandsToRight = true; this.tooltipMiniComponent.instance .changeDetectorRef.markForCheck(); } else if (boundingRect.right > this._document.body.offsetWidth) { this.tooltipMiniComponent.instance.expandsToLeft = true; this.tooltipMiniComponent.instance .changeDetectorRef.markForCheck(); } }); } public changeTooltipVisibility(visible: boolean) { if (visible) { this.updateTooltipLocation(); } this.tooltipMiniComponent.instance.visible = visible; this.tooltipMiniComponent.instance.changeDetectorRef.markForCheck(); } @HostListener('mouseover') public onHover() { if (!this.onClickTriggered && !this._browserDetectorService.isIOS()) { this.changeTooltipVisibility(true); } } @HostListener('mouseout') public onMouseOut() { if (!this.onClickTriggered) { this.changeTooltipVisibility(false); } } @HostListener('click') public onClick() { this.changeTooltipVisibility(true); this.onClickTriggered = true; setTimeout(() => { this.changeTooltipVisibility(false); this.onClickTriggered = false; }, this.onClickVisibleTime); } }