ngx-bootstrap
Version:
Angular Bootstrap
228 lines • 7.69 kB
JavaScript
import { Directive, ElementRef, EventEmitter, Input, Output, Renderer2, ViewContainerRef } from '@angular/core';
import { PopoverConfig } from './popover.config';
import { ComponentLoaderFactory } from 'ngx-bootstrap/component-loader';
import { PopoverContainerComponent } from './popover-container.component';
import { PositioningService } from 'ngx-bootstrap/positioning';
import { timer } from 'rxjs';
import { parseTriggers } from 'ngx-bootstrap/utils';
let id = 0;
/**
* A lightweight, extensible directive for fancy popover creation.
*/
export class PopoverDirective {
constructor(_config, _elementRef, _renderer, _viewContainerRef, cis, _positionService) {
this._elementRef = _elementRef;
this._renderer = _renderer;
this._positionService = _positionService;
/** unique id popover - use for aria-describedby */
this.popoverId = id++;
/** sets disable adaptive position */
this.adaptivePosition = true;
/**
* Placement of a popover. Accepts: "top", "bottom", "left", "right"
*/
this.placement = 'top';
/**
* Close popover on outside click
*/
this.outsideClick = false;
/**
* Specifies events that should trigger. Supports a space separated list of
* event names.
*/
this.triggers = 'click';
/**
* Css class for popover container
*/
this.containerClass = '';
/**
* Delay before showing the tooltip
*/
this.delay = 0;
this._isInited = false;
this._popover = cis
.createLoader(_elementRef, _viewContainerRef, _renderer)
.provide({ provide: PopoverConfig, useValue: _config });
Object.assign(this, _config);
this.onShown = this._popover.onShown;
this.onHidden = this._popover.onHidden;
// fix: no focus on button on Mac OS #1795
if (typeof window !== 'undefined') {
_elementRef.nativeElement.addEventListener('click', function () {
try {
_elementRef.nativeElement.focus();
}
catch (err) {
return;
}
});
}
}
/**
* Returns whether or not the popover is currently being shown
*/
get isOpen() {
return this._popover.isShown;
}
set isOpen(value) {
if (value) {
this.show();
}
else {
this.hide();
}
}
/**
* Set attribute aria-describedBy for element directive and
* set id for the popover
*/
setAriaDescribedBy() {
this._ariaDescribedby = this.isOpen ? `ngx-popover-${this.popoverId}` : void 0;
if (this._ariaDescribedby) {
if (this._popover.instance) {
this._popover.instance.popoverId = this._ariaDescribedby;
}
this._renderer.setAttribute(this._elementRef.nativeElement, 'aria-describedby', this._ariaDescribedby);
}
else {
this._renderer.removeAttribute(this._elementRef.nativeElement, 'aria-describedby');
}
}
/**
* Opens an element’s popover. This is considered a “manual” triggering of
* the popover.
*/
show() {
if (this._popover.isShown || !this.popover || this._delayTimeoutId) {
return;
}
this._positionService.setOptions({
modifiers: {
flip: {
enabled: this.adaptivePosition
},
preventOverflow: {
enabled: this.adaptivePosition
}
}
});
const showPopover = () => {
if (this._delayTimeoutId) {
this._delayTimeoutId = undefined;
}
this._popover
.attach(PopoverContainerComponent)
.to(this.container)
.position({ attachment: this.placement })
.show({
content: this.popover,
context: this.popoverContext,
placement: this.placement,
title: this.popoverTitle,
containerClass: this.containerClass
});
if (!this.adaptivePosition && this._popover._componentRef) {
this._positionService.calcPosition();
this._positionService.deletePositionElement(this._popover._componentRef.location);
}
this.isOpen = true;
this.setAriaDescribedBy();
};
const cancelDelayedTooltipShowing = () => {
if (this._popoverCancelShowFn) {
this._popoverCancelShowFn();
}
};
if (this.delay) {
const _timer = timer(this.delay).subscribe(() => {
showPopover();
cancelDelayedTooltipShowing();
});
if (this.triggers) {
parseTriggers(this.triggers)
.forEach((trigger) => {
if (!trigger.close) {
return;
}
this._popoverCancelShowFn = this._renderer.listen(this._elementRef.nativeElement, trigger.close, () => {
_timer.unsubscribe();
cancelDelayedTooltipShowing();
});
});
}
}
else {
showPopover();
}
}
/**
* Closes an element’s popover. This is considered a “manual” triggering of
* the popover.
*/
hide() {
if (this._delayTimeoutId) {
clearTimeout(this._delayTimeoutId);
this._delayTimeoutId = undefined;
}
if (this.isOpen) {
this._popover.hide();
this.setAriaDescribedBy();
this.isOpen = false;
}
}
/**
* Toggles an element’s popover. This is considered a “manual” triggering of
* the popover.
*/
toggle() {
if (this.isOpen) {
return this.hide();
}
this.show();
}
ngOnInit() {
// fix: seems there are an issue with `routerLinkActive`
// which result in duplicated call ngOnInit without call to ngOnDestroy
// read more: https://github.com/valor-software/ngx-bootstrap/issues/1885
if (this._isInited) {
return;
}
this._isInited = true;
this._popover.listen({
triggers: this.triggers,
outsideClick: this.outsideClick,
show: () => this.show(),
hide: () => this.hide()
});
}
ngOnDestroy() {
this._popover.dispose();
}
}
PopoverDirective.decorators = [
{ type: Directive, args: [{ selector: '[popover]', exportAs: 'bs-popover' },] }
];
PopoverDirective.ctorParameters = () => [
{ type: PopoverConfig },
{ type: ElementRef },
{ type: Renderer2 },
{ type: ViewContainerRef },
{ type: ComponentLoaderFactory },
{ type: PositioningService }
];
PopoverDirective.propDecorators = {
adaptivePosition: [{ type: Input }],
popover: [{ type: Input }],
popoverContext: [{ type: Input }],
popoverTitle: [{ type: Input }],
placement: [{ type: Input }],
outsideClick: [{ type: Input }],
triggers: [{ type: Input }],
container: [{ type: Input }],
containerClass: [{ type: Input }],
isOpen: [{ type: Input }],
delay: [{ type: Input }],
onShown: [{ type: Output }],
onHidden: [{ type: Output }]
};
//# sourceMappingURL=popover.directive.js.map