import { ConnectedPosition , Overlay , OverlayPositionBuilder , OverlayRef , PositionStrategy } from '@angular/cdk/overlay' ; import { ComponentPortal } from '@angular/cdk/portal' ; import { ChangeDetectorRef , ComponentRef , Directive , ElementRef , HostListener , Input , OnDestroy , OnInit , Optional , Renderer2 , ViewRef , } from '@angular/core' ; import { HelpTooltipComponent } from '../components/tooltip/help-tooltip.component' ; import { OverwolfService } from '../services/overwolf.service' ; @ Directive ( { selector : '[helpTooltip]' , } ) export class HelpTooltipDirective implements OnInit , OnDestroy { _text = '' ; @ Input ( 'helpTooltipPosition' ) position : 'bottom' | 'right' | 'left' | 'top' | 'bottom-left' = 'bottom' ; @ Input ( 'helpTooltip' ) set text ( value ) { if ( value === this . _text ) { console . debug ( 'same value, returning' , value ) ; return ; } this . _text = value ; if ( ! this . _text && this . overlayRef ) { this . overlayRef ?. detach ( ) ; } else if ( this . tooltipRef ) { this . tooltipRef . instance . text = this . _text ; } } @ Input ( ) bindTooltipToGameWindow = false ; @ Input ( ) stayOpenOnClick = false ; @ Input ( ) helpTooltipVisibleBeforeHover = false ; @ Input ( ) helpTooltipClasses : string ; @ Input ( 'helpTooltipShowArrow' ) showArrow = false ; @ Input ( 'helpTooltipOnlyShowOnClick' ) onlyShowOnClick = false ; @ Input ( 'helpTooltipClickTimeout' ) clickTimeout = 2000 ; private tooltipPortal : ComponentPortal < any > ; private overlayRef : OverlayRef ; private positionStrategy : PositionStrategy ; private tooltipRef : ComponentRef < HelpTooltipComponent > ; private target : ElementRef ; constructor ( private readonly overlayPositionBuilder , private readonly elementRef , private readonly overlay , private readonly cdr , @ Optional ( ) private readonly ow , private readonly renderer ) { } ngOnInit ( ) { this . target = this . elementRef . nativeElement . querySelector ( '[helpTooltipTarget]' ) || this . elementRef ; const positionArrays = this . position === 'bottom' ? [ { originX : 'center' , originY : 'bottom' , overlayX : 'center' , overlayY : 'top' , } , { originX : 'start' , originY : 'top' , overlayX : 'start' , overlayY : 'bottom' , } , { originX : 'start' , originY : 'bottom' , overlayX : 'start' , overlayY : 'top' , } , ] : this . position === 'right' ? [ { originX : 'end' , originY : 'center' , overlayX : 'start' , overlayY : 'center' , } , ] : this . position === 'top' ? [ { originX : 'center' , originY : 'top' , overlayX : 'center' , overlayY : 'bottom' , } , ] : this . position === 'bottom-left' ? [ { originX : 'end' , originY : 'bottom' , overlayX : 'end' , overlayY : 'top' , } , ] : [ { originX : 'start' , originY : 'center' , overlayX : 'end' , overlayY : 'center' , } , ] ; this . positionStrategy = this . overlayPositionBuilder . flexibleConnectedTo ( this . target ) . withFlexibleDimensions ( false ) . withPush ( false ) . withViewportMargin ( 10 ) . withPositions ( positionArrays ) ; this . overlayRef = this . overlay . create ( { positionStrategy : this . positionStrategy , scrollStrategy : this . overlay . scrollStrategies . reposition ( ) , } ) ; if ( ! ( this . cdr as ViewRef ) ?. destroyed ) { this . cdr . detectChanges ( ) ; } if ( this . helpTooltipVisibleBeforeHover ) { this . onMouseEnter ( ) ; } } @ HostListener ( 'window:beforeunload' ) ngOnDestroy ( ) { if ( this . overlayRef ) { this . overlayRef ?. detach ( ) ; } } @ HostListener ( 'mouseenter' ) async onMouseEnter ( override = false ) { console . debug ( 'mouseenter?' , this . _text , override , this . onlyShowOnClick ) ; if ( ! this . _text || ( ! override && this . onlyShowOnClick ) ) { return ; } console . debug ( 'mouseenter' ) ; if ( this . overlayRef ) { this . overlayRef ?. detach ( ) ; } this . tooltipPortal = new ComponentPortal ( HelpTooltipComponent ) ; try { this . tooltipRef = this . overlayRef . attach ( this . tooltipPortal ) ; } catch ( e ) { this . overlayRef ?. detach ( ) ; this . tooltipRef = this . overlayRef . attach ( this . tooltipPortal ) ; } this . tooltipRef . instance . text = this . _text ; this . tooltipRef . instance . showArrow = this . showArrow ; this . tooltipRef . instance . classes = this . helpTooltipClasses ; this . tooltipRef . instance . setTarget ( this . target ) ; this . positionStrategy . apply ( ) ; if ( ! ( this . cdr as ViewRef ) ?. destroyed ) { this . cdr . detectChanges ( ) ; } if ( this . bindTooltipToGameWindow && this . ow ?. isOwEnabled ( ) ) { const window = await this . ow . getCurrentWindow ( ) ; const gameInfo = await this . ow . getRunningGameInfo ( ) ; if ( this . tooltipRef ) { const tooltipLeft = window . left + ( this . overlayRef . hostElement . getBoundingClientRect ( ) as any ) . x + ( this . tooltipRef . location . nativeElement . getBoundingClientRect ( ) as any ) . x ; if ( tooltipLeft < 0 ) { this . renderer . setStyle ( this . tooltipRef . location . nativeElement , 'marginLeft' , `${ - tooltipLeft }px` ) ; } const tooltipRight = window . left + ( this . overlayRef . hostElement . getBoundingClientRect ( ) as any ) . x + ( this . tooltipRef . location . nativeElement . getBoundingClientRect ( ) as any ) . x + ( this . tooltipRef . location . nativeElement . getBoundingClientRect ( ) as any ) . width ; if ( gameInfo && tooltipRight > gameInfo . logicalWidth ) { this . renderer . setStyle ( this . tooltipRef . location . nativeElement , 'marginLeft' , `${ gameInfo . logicalWidth - tooltipRight }px` ) ; } } } } @ HostListener ( 'click' ) onMouseClick ( ) { console . debug ( 'click' , this . onlyShowOnClick , this . clickTimeout ) ; if ( this . onlyShowOnClick ) { this . onMouseEnter ( true ) ; setTimeout ( ( ) => this . onMouseLeave ( true ) , this . clickTimeout ) ; return ; } if ( this . stayOpenOnClick ) { return ; } if ( this . overlayRef ?. hasAttached ( ) ) { this . overlayRef ?. detach ( ) ; if ( ! ( this . cdr as ViewRef ) ?. destroyed ) { this . cdr . detectChanges ( ) ; } } if ( this . tooltipRef ) { this . tooltipRef = undefined ; } } @ HostListener ( 'mouseleave' ) onMouseLeave ( override = false ) { if ( this . onlyShowOnClick && ! override ) { return ; } console . debug ( 'mouseleave' ) ; if ( this . overlayRef ?. hasAttached ( ) ) { this . overlayRef ?. detach ( ) ; if ( ! ( this . cdr as ViewRef ) ?. destroyed ) { this . cdr . detectChanges ( ) ; } } if ( this . tooltipRef ) { this . tooltipRef = undefined ; } } @ HostListener ( 'window:mousewheel' ) onMouseWheel ( ) { if ( this . overlayRef ?. hasAttached ( ) ) { this . overlayRef ?. detach ( ) ; if ( ! ( this . cdr as ViewRef ) ?. destroyed ) { this . cdr . detectChanges ( ) ; } } if ( this . tooltipRef ) { this . tooltipRef = undefined ; } } }