From 5cd0f0ceb95bf2efdb6931d9f0e5de1a790a268f Mon Sep 17 00:00:00 2001 From: Ekaterina Chantsova Date: Fri, 13 Dec 2024 17:44:36 +0200 Subject: [PATCH 1/2] Fixed truncateWithTooltip directive behaviour on different mouse events --- .../truncate-with-tooltip.directive.ts | 75 ++++++------------- 1 file changed, 21 insertions(+), 54 deletions(-) diff --git a/ui-ngx/src/app/shared/directives/truncate-with-tooltip.directive.ts b/ui-ngx/src/app/shared/directives/truncate-with-tooltip.directive.ts index d37841be6f..9d8f3599fa 100644 --- a/ui-ngx/src/app/shared/directives/truncate-with-tooltip.directive.ts +++ b/ui-ngx/src/app/shared/directives/truncate-with-tooltip.directive.ts @@ -14,25 +14,18 @@ /// limitations under the License. /// -import { - AfterViewInit, - Directive, - ElementRef, - Input, - OnDestroy, - OnInit, - Renderer2, -} from '@angular/core'; -import { fromEvent, Subject } from 'rxjs'; -import { filter, takeUntil, tap } from 'rxjs/operators'; +import { AfterViewInit, Directive, ElementRef, Input, OnInit, Renderer2 } from '@angular/core'; import { MatTooltip, TooltipPosition } from '@angular/material/tooltip'; import { coerceBoolean } from '@shared/decorators/coercion'; @Directive({ selector: '[tbTruncateWithTooltip]', - providers: [MatTooltip], + hostDirectives: [{ + directive: MatTooltip, + inputs: ['matTooltipClass', 'matTooltipTouchGestures'], + }] }) -export class TruncateWithTooltipDirective implements OnInit, AfterViewInit, OnDestroy { +export class TruncateWithTooltipDirective implements OnInit, AfterViewInit { @Input('tbTruncateWithTooltip') text: string; @@ -44,48 +37,31 @@ export class TruncateWithTooltipDirective implements OnInit, AfterViewInit, OnDe @Input() position: TooltipPosition = 'above'; - private destroy$ = new Subject(); - constructor( - private elementRef: ElementRef, + private elementRef: ElementRef, private renderer: Renderer2, private tooltip: MatTooltip ) {} ngOnInit(): void { - this.observeMouseEvents(); this.applyTruncationStyles(); + this.tooltip.position = this.position; + this.showTooltipOnOverflow(this); } ngAfterViewInit(): void { - this.tooltip.position = this.position; + this.tooltip.message = this.text || this.elementRef.nativeElement.innerText; } - ngOnDestroy(): void { - if (this.tooltip._isTooltipVisible()) { - this.hideTooltip(); - } - this.destroy$.next(); - this.destroy$.complete(); - } - - private observeMouseEvents(): void { - fromEvent(this.elementRef.nativeElement, 'mouseenter') - .pipe( - filter(() => this.tooltipEnabled), - filter(() => this.isOverflown(this.elementRef.nativeElement)), - tap(() => this.showTooltip()), - takeUntil(this.destroy$), - ) - .subscribe(); - fromEvent(this.elementRef.nativeElement, 'mouseleave') - .pipe( - filter(() => this.tooltipEnabled), - filter(() => this.tooltip._isTooltipVisible()), - tap(() => this.hideTooltip()), - takeUntil(this.destroy$), - ) - .subscribe(); + private showTooltipOnOverflow(ctx: TruncateWithTooltipDirective) { + ctx.tooltip.show = (function(old) { + function extendsFunction() { + if (ctx.tooltipEnabled && ctx.isOverflown()) { + old.apply(ctx.tooltip, arguments); + } + } + return extendsFunction; + })(ctx.tooltip.show); } private applyTruncationStyles(): void { @@ -94,16 +70,7 @@ export class TruncateWithTooltipDirective implements OnInit, AfterViewInit, OnDe this.renderer.setStyle(this.elementRef.nativeElement, 'text-overflow', 'ellipsis'); } - private isOverflown(element: HTMLElement): boolean { - return element.clientWidth < element.scrollWidth; - } - - private showTooltip(): void { - this.tooltip.message = this.text || this.elementRef.nativeElement.innerText; - this.tooltip.show(); - } - - private hideTooltip(): void { - this.tooltip.hide(); + private isOverflown(): boolean { + return this.elementRef.nativeElement.clientWidth < this.elementRef.nativeElement.scrollWidth; } } From cb5b15802ff844a97df75af26996502a5376d719 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 17 Dec 2024 11:18:28 +0200 Subject: [PATCH 2/2] UI: Refactoring directive tbTruncateWithTooltip to signal and watch content --- .../truncate-with-tooltip.directive.ts | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/ui-ngx/src/app/shared/directives/truncate-with-tooltip.directive.ts b/ui-ngx/src/app/shared/directives/truncate-with-tooltip.directive.ts index 9d8f3599fa..51f0b78df1 100644 --- a/ui-ngx/src/app/shared/directives/truncate-with-tooltip.directive.ts +++ b/ui-ngx/src/app/shared/directives/truncate-with-tooltip.directive.ts @@ -14,9 +14,11 @@ /// limitations under the License. /// -import { AfterViewInit, Directive, ElementRef, Input, OnInit, Renderer2 } from '@angular/core'; +import { booleanAttribute, Directive, ElementRef, input, OnInit, Renderer2 } from '@angular/core'; import { MatTooltip, TooltipPosition } from '@angular/material/tooltip'; -import { coerceBoolean } from '@shared/decorators/coercion'; +import { ContentObserver } from '@angular/cdk/observers'; +import { merge } from 'rxjs'; +import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop'; @Directive({ selector: '[tbTruncateWithTooltip]', @@ -25,38 +27,37 @@ import { coerceBoolean } from '@shared/decorators/coercion'; inputs: ['matTooltipClass', 'matTooltipTouchGestures'], }] }) -export class TruncateWithTooltipDirective implements OnInit, AfterViewInit { +export class TruncateWithTooltipDirective implements OnInit { - @Input('tbTruncateWithTooltip') - text: string; + text = input(undefined, {alias: 'tbTruncateWithTooltip'}); - @Input() - @coerceBoolean() - tooltipEnabled = true; + tooltipEnabled = input(true, {transform: booleanAttribute}); - @Input() - position: TooltipPosition = 'above'; + position = input('above'); constructor( private elementRef: ElementRef, private renderer: Renderer2, - private tooltip: MatTooltip - ) {} + private tooltip: MatTooltip, + private contentObserver: ContentObserver + ) { + merge(toObservable(this.text), this.contentObserver.observe(this.elementRef)).pipe( + takeUntilDestroyed() + ).subscribe(() => { + this.tooltip.message = this.text() || this.elementRef.nativeElement.innerText + }) + } ngOnInit(): void { this.applyTruncationStyles(); - this.tooltip.position = this.position; + this.tooltip.position = this.position(); this.showTooltipOnOverflow(this); } - ngAfterViewInit(): void { - this.tooltip.message = this.text || this.elementRef.nativeElement.innerText; - } - private showTooltipOnOverflow(ctx: TruncateWithTooltipDirective) { ctx.tooltip.show = (function(old) { function extendsFunction() { - if (ctx.tooltipEnabled && ctx.isOverflown()) { + if (ctx.tooltipEnabled() && ctx.isOverflown()) { old.apply(ctx.tooltip, arguments); } }