mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-09 18:03:21 +00:00
feat: debounce clipboard directive tooltip to prevent flickering
This commit is contained in:
@@ -96,21 +96,24 @@ describe('CopyClipboardDirective', () => {
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should show tooltip when hover element', () => {
|
||||
it('should show tooltip when hover element', fakeAsync(() => {
|
||||
testingUtils.hoverOverByCSS('span');
|
||||
tick(200);
|
||||
fixture.detectChanges();
|
||||
expect(testingUtils.getByCSS('.adf-copy-tooltip')).not.toBeNull();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not show tooltip when element it is not hovered', () => {
|
||||
it('should not show tooltip when element it is not hovered', fakeAsync(() => {
|
||||
testingUtils.hoverOverByCSS('span');
|
||||
tick(200);
|
||||
fixture.detectChanges();
|
||||
expect(testingUtils.getByCSS('.adf-copy-tooltip')).not.toBeNull();
|
||||
|
||||
testingUtils.mouseLeaveByCSS('span');
|
||||
tick(150);
|
||||
fixture.detectChanges();
|
||||
expect(testingUtils.getByCSS('.adf-copy-tooltip')).toBeNull();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should copy the content of element when click it', fakeAsync(() => {
|
||||
spyOn(navigator.clipboard, 'writeText');
|
||||
@@ -135,4 +138,31 @@ describe('CopyClipboardDirective', () => {
|
||||
fixture.detectChanges();
|
||||
expect(navigator.clipboard.writeText).not.toHaveBeenCalled();
|
||||
}));
|
||||
|
||||
it('should cleanup tooltip on destroy', fakeAsync(() => {
|
||||
testingUtils.hoverOverByCSS('span');
|
||||
tick(200);
|
||||
fixture.detectChanges();
|
||||
expect(testingUtils.getByCSS('.adf-copy-tooltip')).not.toBeNull();
|
||||
|
||||
// Manually trigger the directive's destroy method
|
||||
const directive = fixture.componentInstance.clipboardDirective;
|
||||
directive.ngOnDestroy();
|
||||
|
||||
// Tooltip should be cleaned up
|
||||
expect(testingUtils.getByCSS('.adf-copy-tooltip')).toBeNull();
|
||||
}));
|
||||
|
||||
it('should prevent flickering on rapid mouse movements', fakeAsync(() => {
|
||||
testingUtils.hoverOverByCSS('span');
|
||||
tick(50);
|
||||
testingUtils.mouseLeaveByCSS('span');
|
||||
tick(50);
|
||||
testingUtils.hoverOverByCSS('span');
|
||||
tick(200);
|
||||
fixture.detectChanges();
|
||||
|
||||
const tooltips = testingUtils.getAllByCSS('.adf-copy-tooltip');
|
||||
expect(tooltips.length).toBeLessThanOrEqual(1);
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Directive, Input, HostListener, Component, ViewContainerRef, ViewEncapsulation, OnInit } from '@angular/core';
|
||||
import { Directive, Input, HostListener, Component, ViewContainerRef, ViewEncapsulation, OnInit, ComponentRef, OnDestroy } from '@angular/core';
|
||||
import { ClipboardService } from './clipboard.service';
|
||||
import { TranslatePipe } from '@ngx-translate/core';
|
||||
|
||||
@@ -23,7 +23,7 @@ import { TranslatePipe } from '@ngx-translate/core';
|
||||
selector: '[adf-clipboard]',
|
||||
exportAs: 'adfClipboard'
|
||||
})
|
||||
export class ClipboardDirective {
|
||||
export class ClipboardDirective implements OnDestroy {
|
||||
/** Translation key or message for the tooltip. */
|
||||
// eslint-disable-next-line @angular-eslint/no-input-rename
|
||||
@Input('adf-clipboard')
|
||||
@@ -37,19 +37,67 @@ export class ClipboardDirective {
|
||||
// eslint-disable-next-line @angular-eslint/no-input-rename
|
||||
@Input('clipboard-notification') message: string;
|
||||
|
||||
constructor(private clipboardService: ClipboardService, public viewContainerRef: ViewContainerRef) {}
|
||||
private tooltipComponentRef: ComponentRef<ClipboardComponent>;
|
||||
private mouseEnterTimeout: ReturnType<typeof setTimeout>;
|
||||
private mouseLeaveTimeout: ReturnType<typeof setTimeout>;
|
||||
|
||||
constructor(
|
||||
private clipboardService: ClipboardService,
|
||||
public viewContainerRef: ViewContainerRef
|
||||
) {}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.clearTimeouts();
|
||||
this.hideTooltip();
|
||||
}
|
||||
|
||||
@HostListener('mouseenter')
|
||||
showTooltip() {
|
||||
if (this.placeholder) {
|
||||
const componentRef = this.viewContainerRef.createComponent(ClipboardComponent).instance;
|
||||
componentRef.placeholder = this.placeholder;
|
||||
if (this.mouseLeaveTimeout) {
|
||||
clearTimeout(this.mouseLeaveTimeout);
|
||||
this.mouseLeaveTimeout = null;
|
||||
}
|
||||
|
||||
if (this.tooltipComponentRef) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.mouseEnterTimeout = setTimeout(() => {
|
||||
if (this.placeholder && !this.tooltipComponentRef) {
|
||||
this.tooltipComponentRef = this.viewContainerRef.createComponent(ClipboardComponent);
|
||||
this.tooltipComponentRef.instance.placeholder = this.placeholder;
|
||||
}
|
||||
}, 150);
|
||||
}
|
||||
|
||||
@HostListener('mouseleave')
|
||||
closeTooltip() {
|
||||
this.viewContainerRef.remove();
|
||||
if (this.mouseEnterTimeout) {
|
||||
clearTimeout(this.mouseEnterTimeout);
|
||||
this.mouseEnterTimeout = null;
|
||||
}
|
||||
|
||||
this.mouseLeaveTimeout = setTimeout(() => {
|
||||
this.hideTooltip();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
private hideTooltip(): void {
|
||||
if (this.tooltipComponentRef) {
|
||||
this.tooltipComponentRef.destroy();
|
||||
this.tooltipComponentRef = null;
|
||||
}
|
||||
}
|
||||
|
||||
private clearTimeouts(): void {
|
||||
if (this.mouseEnterTimeout) {
|
||||
clearTimeout(this.mouseEnterTimeout);
|
||||
this.mouseEnterTimeout = null;
|
||||
}
|
||||
if (this.mouseLeaveTimeout) {
|
||||
clearTimeout(this.mouseLeaveTimeout);
|
||||
this.mouseLeaveTimeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('keydown.enter', ['$event'])
|
||||
|
||||
Reference in New Issue
Block a user