Skip to content

Commit

Permalink
Merged in task/dspace-cris-2023_02_x/DSC-1874 (pull request DSpace#2113)
Browse files Browse the repository at this point in the history
[DSC-1874] Improve related-items popover open/close behaviour

Approved-by: Stefano Maffei
  • Loading branch information
alisaismailati authored and steph-ieffam committed Aug 16, 2024
2 parents 13280ff + 1e01f38 commit e6c7d44
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@
[ngTemplateOutletContext]="{metadataView: metadataView}"></ng-container>
</div>
<ng-template class="d-flex" #linkToAuthority let-metadataView="metadataView">
<span [ngbPopover]="popContent"
[closeDelay]="500"
[openDelay]="1000"
<span [dsStickyPopover]="popContent"
[openDelay]="100"
[animation]="true"
[autoClose]="'outside'"
[autoClose]="true"
container="body"
triggers="mouseenter:mouseleave">
triggers="mouseenter">
<a rel="noopener noreferrer" data-test="linkToAuthority"
[routerLink]="['/items/' + metadataView.authority]">
<span dsEntityIcon
Expand Down
121 changes: 121 additions & 0 deletions src/app/shared/metadata-link-view/sticky-popover.directive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import {
ElementRef,
Directive,
Input,
TemplateRef,
Renderer2,
OnInit,
OnDestroy,
Injector,
ViewContainerRef,
NgZone,
ChangeDetectorRef,
ApplicationRef, Inject
} from '@angular/core';
import {NgbPopover, NgbPopoverConfig} from '@ng-bootstrap/ng-bootstrap';
import {DOCUMENT} from '@angular/common';
import {NavigationStart, Router} from '@angular/router';
import {Subscription} from 'rxjs';

/**
* Directive to create a sticky popover using NgbPopover.
* The popover remains open when the mouse is over its content and closes when the mouse leaves.
*/
@Directive({
selector: '[dsStickyPopover]'
})
export class StickyPopoverDirective extends NgbPopover implements OnInit, OnDestroy {
/** Template for the sticky popover content */
@Input() dsStickyPopover: TemplateRef<any>;

/** Subscriptions to manage router events */
subs: Subscription[] = [];

/** Flag to determine if the popover can be closed */
private canClosePopover: boolean;

/** Reference to the element the directive is applied to */
private readonly _elRef;

/** Renderer to listen to and manipulate DOM elements */
private readonly _render;

constructor(
_elementRef: ElementRef<HTMLElement>,
_renderer: Renderer2, injector: Injector,
viewContainerRef: ViewContainerRef,
config: NgbPopoverConfig,
_ngZone: NgZone,
@Inject(DOCUMENT) _document: Document,
_changeDetector: ChangeDetectorRef,
applicationRef: ApplicationRef,
private router: Router
) {
super(_elementRef, _renderer, injector, viewContainerRef, config, _ngZone, document, _changeDetector, applicationRef);
this._elRef = _elementRef;
this._render = _renderer;
this.triggers = 'manual';
this.container = 'body';
}

/**
* Sets up event listeners for mouse enter, mouse leave, and click events.
*/
ngOnInit(): void {
super.ngOnInit();
this.ngbPopover = this.dsStickyPopover;

this._render.listen(this._elRef.nativeElement, 'mouseenter', () => {
this.canClosePopover = true;
this.open();
});

this._render.listen(this._elRef.nativeElement, 'mouseleave', () => {
setTimeout(() => {
if (this.canClosePopover) {
this.close();
}
}, 100);
});

this._render.listen(this._elRef.nativeElement, 'click', () => {
this.close();
});

this.subs.push(
this.router.events.subscribe((event) => {
if (event instanceof NavigationStart) {
this.close();
}
})
);
}

/**
* Opens the popover and sets up event listeners for mouse over and mouse out events on the popover.
*/
open() {
super.open();
const popover = window.document.querySelector('.popover');
this._render.listen(popover, 'mouseover', () => {
this.canClosePopover = false;
});

this._render.listen(popover, 'mouseout', () => {
this.canClosePopover = true;
setTimeout(() => {
if (this.canClosePopover) {
this.close();
}
}, 0);
});
}

/**
* Unsubscribes from all subscriptions when the directive is destroyed.
*/
ngOnDestroy() {
super.ngOnDestroy();
this.subs.forEach((sub) => sub.unsubscribe());
}
}
2 changes: 2 additions & 0 deletions src/app/shared/shared.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ import { ThemedDefaultBrowseElementsComponent } from './browse-most-elements/def
import { MetadataLinkViewPopoverComponent } from './metadata-link-view/metadata-link-view-popover/metadata-link-view-popover.component';
import { MetadataLinkViewAvatarPopoverComponent } from './metadata-link-view/metadata-link-view-avatar-popover/metadata-link-view-avatar-popover.component';
import { MetadataLinkViewOrcidComponent } from './metadata-link-view/metadata-link-view-orcid/metadata-link-view-orcid.component';
import {StickyPopoverDirective} from './metadata-link-view/sticky-popover.directive';

const MODULES = [
CommonModule,
Expand Down Expand Up @@ -623,6 +624,7 @@ const DIRECTIVES = [
ContextHelpDirective,
EntityIconDirective,
MarkdownDirective,
StickyPopoverDirective
];

@NgModule({
Expand Down

0 comments on commit e6c7d44

Please sign in to comment.