thingsboard/ui-ngx/src/app/shared/directives/truncate-tooltip.directive.ts
2024-07-22 19:32:42 +03:00

110 lines
3.0 KiB
TypeScript

///
/// Copyright © 2016-2024 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// 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 { MatTooltip, TooltipPosition } from '@angular/material/tooltip';
@Directive({
standalone: true,
selector: '[tbTruncateTooltip]',
providers: [MatTooltip],
})
export class TruncateTooltipDirective implements OnInit, AfterViewInit, OnDestroy {
@Input('tbTruncateTooltip') text: string;
@Input() tooltipEnabled = true;
@Input() position: TooltipPosition = 'above';
private destroy$ = new Subject<void>();
constructor(
private elementRef: ElementRef,
private renderer: Renderer2,
private tooltip: MatTooltip
) {}
ngOnInit(): void {
this.observeMouseEvents();
this.applyTruncationStyles();
}
ngAfterViewInit(): void {
if (!this.text) {
this.text = this.elementRef.nativeElement.innerText;
}
this.tooltip.position = this.position;
}
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 applyTruncationStyles(): void {
this.renderer.setStyle(this.elementRef.nativeElement, 'white-space', 'nowrap');
this.renderer.setStyle(this.elementRef.nativeElement, 'overflow', 'hidden');
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.renderer.setAttribute(this.elementRef.nativeElement, 'matTooltip', this.text);
this.tooltip.show();
}
private hideTooltip(): void {
this.tooltip.hide();
}
}