UNPKG

ngx-smart-popover

Version:

Simple popover control for your angular (v4+) applications using bootstrap4 with smart reflection logic when overflowing the viewport. This is a continuation of ngx-popover (https://github.com/pleerock/ngx-popover). If you want to use it without bootstrap

1,146 lines (1,138 loc) 42.8 kB
import { EventEmitter, Component, ElementRef, ChangeDetectorRef, Renderer2, Input, ViewChild, HostListener, Directive, ViewContainerRef, ComponentFactoryResolver, ApplicationRef, Injector, Output, NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; /** * @fileoverview added by tsickle * Generated from: lib/popover.placement.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class PopoverPlacement { } PopoverPlacement.Bottom = 'bottom'; PopoverPlacement.BottomLeft = 'bottom-left'; PopoverPlacement.BottomRight = 'bottom-right'; PopoverPlacement.Left = 'left'; PopoverPlacement.Right = 'right'; PopoverPlacement.Top = 'top'; PopoverPlacement.TopLeft = 'top-left'; PopoverPlacement.TopRight = 'top-right'; /** * @fileoverview added by tsickle * Generated from: lib/popover-content.component.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class PopoverContentComponent { // ------------------------------------------------------------------------- // Constructor // ------------------------------------------------------------------------- /** * @param {?} element * @param {?} cdr * @param {?} renderer */ constructor(element, cdr, renderer) { this.element = element; this.cdr = cdr; this.renderer = renderer; this.placement = PopoverPlacement.Top; this.animation = true; this.closeOnClickOutside = false; this.closeOnMouseOutside = false; this.appendToBody = false; this.size = 'small'; this.onCloseFromOutside = new EventEmitter(); this.top = -10000; this.left = -10000; this.isIn = false; this.opacity = 0; this.transitionEnabled = false; this.windowWidth = window.innerWidth; this.windowHeight = window.innerHeight; // ------------------------------------------------------------------------- // Anonymous // ------------------------------------------------------------------------- /** * Closes dropdown if user clicks outside of this directive. */ this.onDocumentMouseDown = (/** * @param {?} event * @return {?} */ (event) => { /** @type {?} */ const element = this.element.nativeElement; if (!element || !this.popover) { return; } if (element.contains(event.target) || this.popover.getElement().contains(event.target)) { return; } this.onCloseFromOutside.emit(undefined); }); } // ------------------------------------------------------------------------- // Lifecycle callbacks // ------------------------------------------------------------------------- /** * @return {?} */ ngAfterViewInit() { if (this.closeOnClickOutside) { this.listenClickFunc = this.renderer.listen('document', 'mousedown', (/** * @param {?} event * @return {?} */ (event) => this.onDocumentMouseDown(event))); } if (this.closeOnMouseOutside) { this.listenMouseFunc = this.renderer.listen('document', 'mouseover', (/** * @param {?} event * @return {?} */ (event) => this.onDocumentMouseDown(event))); } // Always close on mobile touch event outside. this.listenTouchFunc = this.renderer.listen('document', 'touchstart', (/** * @param {?} event * @return {?} */ (event) => this.onDocumentMouseDown(event))); this.show(); this.cdr.detectChanges(); } /** * @return {?} */ ngOnDestroy() { if (this.closeOnClickOutside && this.listenClickFunc) { this.listenClickFunc(); } if (this.closeOnMouseOutside && this.listenMouseFunc) { this.listenMouseFunc(); } if (!!this.listenTouchFunc) { this.listenTouchFunc(); } } // ------------------------------------------------------------------------- // Public Methods // ------------------------------------------------------------------------- /** * @param {?} event * @return {?} */ onResize(event) { this.windowWidth = window.innerWidth; this.windowHeight = window.innerHeight; } /** * @return {?} */ updatePosition() { // if visible, reposition if (this.opacity) { /** @type {?} */ const p = this.positionElements(this.popover.getElement(), this.popoverDiv.nativeElement, this.placement); this.top = p.top; this.left = p.left; } } /** * @return {?} */ show() { if (!this.popover || !this.popover.getElement()) { return; } /** @type {?} */ const p = this.positionElements(this.popover.getElement(), this.popoverDiv.nativeElement, this.placement); this.top = p.top; this.left = p.left; this.isIn = true; this.transitionEnabled = true; this.opacity = 1; } /** * @return {?} */ hide() { this.top = -10000; this.left = -10000; this.isIn = true; this.popover.hide(); } /** * @return {?} */ hideFromPopover() { this.top = -10000; this.left = -10000; this.isIn = true; this.transitionEnabled = false; this.opacity = 0; } // ------------------------------------------------------------------------- // Protected Methods // ------------------------------------------------------------------------- /** * @protected * @param {?} hostEl * @param {?} targetEl * @param {?} positionStr * @param {?=} appendToBody * @return {?} */ positionElements(hostEl, targetEl, positionStr, appendToBody = false) { /** @type {?} */ const positionStrParts = ((/** @type {?} */ (positionStr))).split(' '); /** @type {?} */ let pos0 = positionStrParts[0]; /** @type {?} */ const pos1 = positionStrParts[1] || 'center'; /** @type {?} */ const hostElPos = this.appendToBody || appendToBody ? this.offset(hostEl) : this.position(hostEl); /** @type {?} */ const targetElWidth = targetEl.offsetWidth; /** @type {?} */ const targetElHeight = targetEl.offsetHeight; this.effectivePlacement = pos0 = this.getEffectivePlacement(pos0, hostEl, targetEl); /** @type {?} */ const shiftWidth = { center: (/** * @return {?} */ function () { return hostElPos.left + hostElPos.width / 2 - targetElWidth / 2; }), left: (/** * @return {?} */ function () { return hostElPos.left; }), right: (/** * @return {?} */ function () { return hostElPos.left + hostElPos.width; }), topOrBottomRight: (/** * @return {?} */ function () { return hostElPos.left + hostElPos.width / 2; }), topOrBottomLeft: (/** * @return {?} */ function () { return hostElPos.left - targetElWidth + hostElPos.width / 2; }) }; /** @type {?} */ const shiftHeight = { center: (/** * @return {?} */ function () { return hostElPos.top + hostElPos.height / 2 - targetElHeight / 2; }), top: (/** * @return {?} */ function () { return hostElPos.top; }), bottom: (/** * @return {?} */ function () { return hostElPos.top + hostElPos.height; }) }; /** @type {?} */ let targetElPos; switch (pos0) { case PopoverPlacement.Right: targetElPos = { top: shiftHeight[pos1](), left: shiftWidth[pos0]() }; break; case PopoverPlacement.Left: targetElPos = { top: shiftHeight[pos1](), left: hostElPos.left - targetElWidth }; break; case PopoverPlacement.Bottom: targetElPos = { top: shiftHeight[pos0](), left: shiftWidth[pos1]() }; break; case PopoverPlacement.TopLeft: targetElPos = { top: hostElPos.top - targetElHeight, left: shiftWidth['topOrBottomLeft']() }; break; case PopoverPlacement.TopRight: targetElPos = { top: hostElPos.top - targetElHeight, left: shiftWidth['topOrBottomRight']() }; break; case PopoverPlacement.BottomLeft: targetElPos = { top: shiftHeight[PopoverPlacement.Bottom](), left: shiftWidth['topOrBottomLeft']() }; break; case PopoverPlacement.BottomRight: targetElPos = { top: shiftHeight[PopoverPlacement.Bottom](), left: shiftWidth['topOrBottomRight']() }; break; default: targetElPos = { top: hostElPos.top - targetElHeight, left: shiftWidth[pos1]() }; break; } return targetElPos; } /** * @protected * @param {?} nativeEl * @return {?} */ position(nativeEl) { /** @type {?} */ let offsetParentBCR = { top: 0, left: 0 }; /** @type {?} */ const elBCR = this.offset(nativeEl); /** @type {?} */ const offsetParentEl = this.parentOffsetEl(nativeEl); if (offsetParentEl !== window.document) { offsetParentBCR = this.offset(offsetParentEl); offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop; offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft; } /** @type {?} */ const boundingClientRect = nativeEl.getBoundingClientRect(); return { width: boundingClientRect.width || nativeEl.offsetWidth, height: boundingClientRect.height || nativeEl.offsetHeight, top: elBCR.top - offsetParentBCR.top, left: elBCR.left - offsetParentBCR.left }; } /** * @protected * @param {?} nativeEl * @return {?} */ offset(nativeEl) { /** @type {?} */ const boundingClientRect = nativeEl.getBoundingClientRect(); return { width: boundingClientRect.width || nativeEl.offsetWidth, height: boundingClientRect.height || nativeEl.offsetHeight, top: boundingClientRect.top + (window.pageYOffset || window.document.documentElement.scrollTop), left: boundingClientRect.left + (window.pageXOffset || window.document.documentElement.scrollLeft) }; } /** * @protected * @param {?} nativeEl * @param {?} cssProp * @return {?} */ getStyle(nativeEl, cssProp) { if (((/** @type {?} */ (nativeEl))).currentStyle) { // IE return ((/** @type {?} */ (nativeEl))).currentStyle[cssProp]; } if (window.getComputedStyle) { return ((/** @type {?} */ (window.getComputedStyle)))(nativeEl)[cssProp]; } // finally try and get inline style return ((/** @type {?} */ (nativeEl.style)))[cssProp]; } /** * @protected * @param {?} nativeEl * @return {?} */ isStaticPositioned(nativeEl) { return (this.getStyle(nativeEl, 'position') || 'static') === 'static'; } /** * @protected * @param {?} nativeEl * @return {?} */ parentOffsetEl(nativeEl) { /** @type {?} */ let offsetParent = nativeEl.offsetParent || window.document; while (offsetParent && offsetParent !== window.document && this.isStaticPositioned(offsetParent)) { offsetParent = offsetParent.offsetParent; } return offsetParent || window.document; } // Check for overflow of the viewport and reflect the position if necessary. /** * @protected * @param {?} placement * @param {?} hostElement * @param {?} targetElement * @return {?} */ getEffectivePlacement(placement, hostElement, targetElement) { /** @type {?} */ const hostElBoundingRect = hostElement.getBoundingClientRect(); /** @type {?} */ const desiredPlacement = placement || PopoverPlacement.Top; // Determines if a popover overflows in a direction when in a specific position. /** @type {?} */ const overflows = { positionTop: { top: hostElBoundingRect.top - targetElement.offsetHeight < 0, right: hostElBoundingRect.left + hostElBoundingRect.width / 2 + targetElement.offsetWidth / 2 > this.windowWidth, left: hostElBoundingRect.left + hostElBoundingRect.width / 2 - targetElement.offsetWidth / 2 < 0 }, positionTopRight: { top: hostElBoundingRect.top - targetElement.offsetHeight < 0, right: hostElBoundingRect.right + targetElement.offsetWidth > this.windowWidth }, positionRight: { top: hostElBoundingRect.top + hostElBoundingRect.height / 2 - targetElement.offsetHeight / 2 < 0, right: hostElBoundingRect.right + targetElement.offsetWidth > this.windowWidth, bottom: hostElBoundingRect.top + hostElBoundingRect.height / 2 + targetElement.offsetHeight / 2 > this.windowHeight }, positionBottomRight: { right: hostElBoundingRect.right + targetElement.offsetWidth > this.windowWidth, bottom: hostElBoundingRect.bottom + targetElement.offsetHeight > this.windowHeight }, positionBottom: { right: hostElBoundingRect.left + hostElBoundingRect.width / 2 + targetElement.offsetWidth / 2 > this.windowWidth, bottom: hostElBoundingRect.bottom + targetElement.offsetHeight > this.windowHeight, left: hostElBoundingRect.left + hostElBoundingRect.width / 2 - targetElement.offsetWidth / 2 < 0 }, positionBottomLeft: { bottom: hostElBoundingRect.bottom + targetElement.offsetHeight > this.windowHeight, left: hostElBoundingRect.left - targetElement.offsetWidth < 0 }, positionLeft: { left: hostElBoundingRect.left < targetElement.offsetWidth, top: hostElBoundingRect.top + hostElBoundingRect.height / 2 - targetElement.offsetHeight / 2 < 0, bottom: hostElBoundingRect.top + hostElBoundingRect.height / 2 + targetElement.offsetHeight / 2 > this.windowHeight }, positionTopLeft: { top: hostElBoundingRect.top - targetElement.offsetHeight < 0, left: hostElBoundingRect.left - targetElement.offsetWidth < 0 } }; if (desiredPlacement === PopoverPlacement.Top) { // If it overflows on the top AND left, go to bottom-right. if (overflows.positionTop.top && overflows.positionTop.left) { return PopoverPlacement.BottomRight; // If it overflows on the top AND right, go to bottom-left. } else if (overflows.positionTop.top && overflows.positionTop.right) { return PopoverPlacement.BottomLeft; // If it only overflows on the top, go to bottom. } else if (overflows.positionTop.top) { return PopoverPlacement.Bottom; // If it only overflows to the right, go to top-left. } else if (overflows.positionTop.right) { return PopoverPlacement.TopLeft; // If it only overflows to the left, go to top-right. } else if (overflows.positionTop.left) { return PopoverPlacement.TopRight; } else { return PopoverPlacement.Top; } } if (desiredPlacement === PopoverPlacement.TopRight) { // If it overflows on the top AND the right, try in the order: bottom, Bottom-left, left. if (overflows.positionTopRight.top && overflows.positionTopRight.right) { if (overflows.positionBottom.bottom) { return PopoverPlacement.Left; } else if (overflows.positionBottom.right) { return PopoverPlacement.BottomLeft; } else { return PopoverPlacement.Bottom; } // If it only overflows on the top, try in the order: right, bottom-right. } else if (overflows.positionTopRight.top) { if (overflows.positionRight.top) { return PopoverPlacement.BottomRight; } else { return PopoverPlacement.Right; } // If it only overflows on the right, try in the order: top, top-left. } else if (overflows.positionTopRight.right) { if (overflows.positionTop.right) { return PopoverPlacement.TopLeft; } else { return PopoverPlacement.Top; } } else { return PopoverPlacement.TopRight; } } if (desiredPlacement === PopoverPlacement.Right) { // If it overflows on the right AND the top, try in the order: bottom-right, bottom, bottom-left. if (overflows.positionRight.right && overflows.positionRight.top) { if (overflows.positionBottomRight.right && overflows.positionBottom.right) { return PopoverPlacement.BottomLeft; } else if (overflows.positionBottomRight.right) { return PopoverPlacement.Bottom; } else { return PopoverPlacement.BottomRight; } // If it overflows on the right AND the bottom, try in the order: top-right, top, top-left. } else if (overflows.positionRight.right && overflows.positionRight.bottom) { if (overflows.positionTopRight.right && overflows.positionTop.right) { return PopoverPlacement.TopLeft; } else if (overflows.positionTopRight.right) { return PopoverPlacement.Top; } else { return PopoverPlacement.TopRight; } // If it only overflows on the right, try all top positions from right to left, then try all bottom positions right to left. } else if (overflows.positionRight.right) { if (overflows.positionTop.top) { if (overflows.positionBottom.right) { return PopoverPlacement.BottomLeft; } else if (overflows.positionBottomRight.right) { return PopoverPlacement.Bottom; } else { return PopoverPlacement.BottomRight; } } else { if (overflows.positionTop.right) { return PopoverPlacement.TopLeft; } else if (overflows.positionTopRight.right) { return PopoverPlacement.Top; } else { return PopoverPlacement.TopRight; } } // If it only over flows on the top, go bottom-right. } else if (overflows.positionRight.top) { return PopoverPlacement.BottomRight; // If it only overflows on the bottom, go top-right. } else if (overflows.positionRight.bottom) { return PopoverPlacement.TopRight; } else { return PopoverPlacement.Right; } } if (desiredPlacement === PopoverPlacement.BottomRight) { // If it overflows on the bottom AND the right, try in the order: top, top-left, left. if (overflows.positionBottomRight.bottom && overflows.positionBottomRight.right) { if (overflows.positionTop.top) { return PopoverPlacement.Left; } else if (overflows.positionTop.right) { return PopoverPlacement.TopLeft; } else { return PopoverPlacement.Top; } // If it only overflows on the bottom, try in the order: right, top-right. } else if (overflows.positionBottomRight.bottom) { if (overflows.positionRight.bottom) { return PopoverPlacement.TopRight; } else { return PopoverPlacement.Right; } // If it only overflows on the right, try in the order: bottom, bottom-left. } else if (overflows.positionBottomRight.right) { if (overflows.positionBottom.right) { return PopoverPlacement.BottomLeft; } else { return PopoverPlacement.Bottom; } } else { return PopoverPlacement.BottomRight; } } if (desiredPlacement === PopoverPlacement.Bottom) { // If it overflows on the bottom AND left, go to top-right. if (overflows.positionBottom.bottom && overflows.positionBottom.left) { return PopoverPlacement.TopRight; // If it overflows on the bottom AND right, go to top-left. } else if (overflows.positionBottom.bottom && overflows.positionBottom.right) { return PopoverPlacement.TopLeft; // If it only overflows on the bottom, go to top. } else if (overflows.positionBottom.bottom) { return PopoverPlacement.Top; // If it only overflows to the right, go to bottom-left. } else if (overflows.positionBottom.right) { return PopoverPlacement.BottomLeft; // If it only overflows to the left, go to bottom-right. } else if (overflows.positionBottom.left) { return PopoverPlacement.BottomRight; } else { return PopoverPlacement.Bottom; } } if (desiredPlacement === PopoverPlacement.BottomLeft) { // If it overflows on the bottom AND the left, try in the order: top, top-right, right. if (overflows.positionBottomLeft.bottom && overflows.positionBottomLeft.left) { if (overflows.positionTop.top) { return PopoverPlacement.Right; } else if (overflows.positionTop.left) { return PopoverPlacement.TopRight; } else { return PopoverPlacement.Top; } // If it only overflows on the bottom, try in the order: left, top-left. } else if (overflows.positionBottomLeft.bottom) { if (overflows.positionLeft.bottom) { return PopoverPlacement.TopLeft; } else { return PopoverPlacement.Left; } // If it only overflows on the left, try in the order: bottom, bottom-right. } else if (overflows.positionBottomLeft.left) { if (overflows.positionBottom.left) { return PopoverPlacement.BottomRight; } else { return PopoverPlacement.Bottom; } } else { return PopoverPlacement.BottomLeft; } } if (desiredPlacement === PopoverPlacement.Left) { // If it overflows on the left AND the top, try in the order: bottom-left, bottom, bottom-right. if (overflows.positionLeft.left && overflows.positionLeft.top) { if (overflows.positionBottomLeft.left && overflows.positionBottom.left) { return PopoverPlacement.BottomRight; } else if (overflows.positionBottomRight.right) { return PopoverPlacement.Bottom; } else { return PopoverPlacement.BottomLeft; } // If it overflows on the left AND the bottom, try in the order: top-left, top, top-right. } else if (overflows.positionLeft.left && overflows.positionLeft.bottom) { if (overflows.positionTopLeft.left && overflows.positionTop.left) { return PopoverPlacement.TopRight; } else if (overflows.positionTopLeft.left) { return PopoverPlacement.Top; } else { return PopoverPlacement.TopLeft; } // If it only overflows on the left, try all top positions from left to right, then try all bottom positions left to right. } else if (overflows.positionLeft.left) { if (overflows.positionTop.top) { if (overflows.positionBottom.left) { return PopoverPlacement.BottomRight; } else if (overflows.positionBottomLeft.left) { return PopoverPlacement.Bottom; } else { return PopoverPlacement.BottomLeft; } } else { if (overflows.positionTop.left) { return PopoverPlacement.TopRight; } else if (overflows.positionTopLeft.left) { return PopoverPlacement.Top; } else { return PopoverPlacement.TopLeft; } } // If it only over flows on the top, go bottom-left. } else if (overflows.positionLeft.top) { return PopoverPlacement.BottomLeft; // If it only overflows on the bottom, go top-left. } else if (overflows.positionLeft.bottom) { return PopoverPlacement.TopLeft; } else { return PopoverPlacement.Left; } } if (desiredPlacement === PopoverPlacement.TopLeft) { // If it overflows on the top AND the left, try in the order: bottom, Bottom-right, right. if (overflows.positionTopLeft.top && overflows.positionTopLeft.left) { if (overflows.positionBottom.bottom) { return PopoverPlacement.Right; } else if (overflows.positionBottom.left) { return PopoverPlacement.BottomRight; } else { return PopoverPlacement.Bottom; } // If it only overflows on the top, try in the order: left, bottom-left. } else if (overflows.positionTopLeft.top) { if (overflows.positionLeft.top) { return PopoverPlacement.BottomLeft; } else { return PopoverPlacement.Left; } // If it only overflows on the left, try in the order: top, top-right. } else if (overflows.positionTopLeft.left) { if (overflows.positionTop.left) { return PopoverPlacement.TopRight; } else { return PopoverPlacement.Top; } } else { return PopoverPlacement.TopLeft; } } return desiredPlacement; } } PopoverContentComponent.decorators = [ { type: Component, args: [{ selector: 'popover-content', template: ` <div #popoverDiv class="bs-popover-{{ effectivePlacement }} popover-content popover {{ parentClass }}" [ngClass]="{ 'sm': size === 'small', 'md-sm': size === 'medium-small', 'md': size === 'medium', 'lg': size === 'large', 'in': isIn }" [style.top.px]="top" [style.left.px]="left" [style.transition]="(transitionEnabled ? '0.15s opacity' : '')" [style.opacity]="opacity" [style.display]="'block'" [attr.aria-hidden]="opacity === 0" role="popover"> <div [hidden]="!closeOnMouseOutside" class="virtual-area"></div> <div class="arrow"></div> <div class="popover-header" [hidden]="!title">{{ title }}</div> <div class="popover-body"> <ng-content></ng-content> {{ content }} </div> </div> ` }] } ]; /** @nocollapse */ PopoverContentComponent.ctorParameters = () => [ { type: ElementRef }, { type: ChangeDetectorRef }, { type: Renderer2 } ]; PopoverContentComponent.propDecorators = { content: [{ type: Input }], placement: [{ type: Input }], title: [{ type: Input }], parentClass: [{ type: Input }], animation: [{ type: Input }], closeOnClickOutside: [{ type: Input }], closeOnMouseOutside: [{ type: Input }], appendToBody: [{ type: Input }], size: [{ type: Input }], popoverDiv: [{ type: ViewChild, args: ['popoverDiv', { static: true },] }], onResize: [{ type: HostListener, args: ['window:resize', ['$event'],] }] }; /** * @fileoverview added by tsickle * Generated from: lib/popover.directive.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * \@group Basic Toolkit * \@component Popover Directive */ class PopoverDirective { // ------------------------------------------------------------------------- // Constructor // ------------------------------------------------------------------------- /** * @param {?} viewContainerRef * @param {?} cdr * @param {?} resolver * @param {?} appRef * @param {?} injector */ constructor(viewContainerRef, cdr, resolver, appRef, injector) { this.viewContainerRef = viewContainerRef; this.cdr = cdr; this.resolver = resolver; this.appRef = appRef; this.injector = injector; // ------------------------------------------------------------------------- // Properties // ------------------------------------------------------------------------- this.popoverContentComponent = PopoverContentComponent; this.popoverOnHover = true; this.popoverDismissTimeout = 0; this.onShown = new EventEmitter(); this.onHidden = new EventEmitter(); } // ------------------------------------------------------------------------- // Event listeners // ------------------------------------------------------------------------- /** * @param {?} evt * @return {?} */ showOrHideOnClick(evt) { if (this.popoverOnHover) { return; } if (this.popoverDisabled) { return; } evt.stopImmediatePropagation(); this.toggle(); } /** * @param {?} evt * @return {?} */ showOrHideOnTouch(evt) { evt.stopImmediatePropagation(); if (!this.popoverOnHover) { return; } if (this.popoverDisabled) { return; } this.toggle(); } /** * @return {?} */ showOnHover() { if (!this.popoverOnHover) { return; } if (this.popoverDisabled) { return; } this.show(); } /** * @return {?} */ hideOnHover() { if (this.popoverCloseOnMouseOutside) { return; // don't do anything since we do not control this } if (!this.popoverOnHover) { return; } if (this.popoverDisabled) { return; } this.hide(); } /** * @param {?} changes * @return {?} */ ngOnChanges(changes) { if (changes['popoverDisabled']) { if (changes['popoverDisabled'].currentValue) { this.hide(); } } } /** * @protected * @param {?} component * @return {?} */ createComponent(component) { /** @type {?} */ const factory = this.resolver.resolveComponentFactory(component); // Create a component reference from the component /** @type {?} */ const componentRef = this.appendToBody ? factory.create(this.injector) : this.viewContainerRef.createComponent(factory); if (this.appendToBody) { // Attach component to the appRef so that it's inside the ng component tree this.appRef.attachView(componentRef.hostView); // Get DOM element from component /** @type {?} */ const domElem = (/** @type {?} */ (((/** @type {?} */ (componentRef.hostView))) .rootNodes[0])); // Append DOM element to the body document.body.appendChild(domElem); } return componentRef; } /** * @protected * @param {?} componentRef * @return {?} */ removeComponent(componentRef) { if (this.popover) { if (this.appendToBody) { this.appRef.detachView(componentRef.hostView); } componentRef.destroy(); } } // ------------------------------------------------------------------------- // Public Methods // ------------------------------------------------------------------------- /** * @return {?} */ toggle() { if (!this.visible) { this.show(); } else { this.hide(); } } /** * @return {?} */ show() { if (this.visible) { return; } this.visible = true; if (typeof this.content === 'string') { if (!this.visible) { return; } this.popover = this.createComponent(this.popoverContentComponent); /** @type {?} */ const popover = (/** @type {?} */ (this.popover.instance)); popover.popover = this; popover.content = (/** @type {?} */ (this.content)); if (this.popoverPlacement !== undefined) { popover.placement = this.popoverPlacement; } if (this.popoverAnimation !== undefined) { popover.animation = this.popoverAnimation; } if (this.popoverTitle !== undefined) { popover.title = this.popoverTitle; } if (this.popoverCloseOnClickOutside !== undefined) { popover.closeOnClickOutside = this.popoverCloseOnClickOutside; } if (this.popoverCloseOnMouseOutside !== undefined) { popover.closeOnMouseOutside = this.popoverCloseOnMouseOutside; } if (this.popoverSize) { popover.size = this.popoverSize; } popover.appendToBody = this.appendToBody; popover.onCloseFromOutside.subscribe((/** * @return {?} */ () => this.hide())); // if dismissTimeout option is set, then this popover will be dismissed in dismissTimeout time if (this.popoverDismissTimeout > 0) { setTimeout((/** * @return {?} */ () => this.hide()), this.popoverDismissTimeout); } } else { /** @type {?} */ const popover = (/** @type {?} */ (this.content)); popover.popover = this; if (this.popoverPlacement !== undefined) { popover.placement = this.popoverPlacement; } if (this.popoverAnimation !== undefined) { popover.animation = this.popoverAnimation; } if (this.popoverTitle !== undefined) { popover.title = this.popoverTitle; } if (this.popoverCloseOnClickOutside !== undefined) { popover.closeOnClickOutside = this.popoverCloseOnClickOutside; } if (this.popoverCloseOnMouseOutside !== undefined) { popover.closeOnMouseOutside = this.popoverCloseOnMouseOutside; } if (this.popoverSize) { popover.size = this.popoverSize; } popover.appendToBody = this.appendToBody; popover.onCloseFromOutside.subscribe((/** * @return {?} */ () => this.hide())); // if dismissTimeout option is set, then this popover will be dismissed in dismissTimeout time if (this.popoverDismissTimeout > 0) { setTimeout((/** * @return {?} */ () => this.hide()), this.popoverDismissTimeout); } popover.show(); } this.cdr.detectChanges(); this.onShown.emit(this); } /** * @return {?} */ hide() { if (!this.visible) { return; } this.visible = false; this.removeComponent(this.popover); if (this.content instanceof PopoverContentComponent) { ((/** @type {?} */ (this.content))).hideFromPopover(); } this.cdr.detectChanges(); this.onHidden.emit(this); } /** * @return {?} */ getElement() { return this.viewContainerRef.element.nativeElement; } } PopoverDirective.decorators = [ { type: Directive, args: [{ selector: '[popover]', exportAs: 'popover' },] } ]; /** @nocollapse */ PopoverDirective.ctorParameters = () => [ { type: ViewContainerRef }, { type: ChangeDetectorRef }, { type: ComponentFactoryResolver }, { type: ApplicationRef }, { type: Injector } ]; PopoverDirective.propDecorators = { content: [{ type: Input, args: ['popover',] }], popoverSize: [{ type: Input }], popoverDisabled: [{ type: Input }], popoverAnimation: [{ type: Input }], popoverPlacement: [{ type: Input }], popoverTitle: [{ type: Input }], popoverOnHover: [{ type: Input }], popoverCloseOnClickOutside: [{ type: Input }], popoverCloseOnMouseOutside: [{ type: Input }], popoverDismissTimeout: [{ type: Input }], appendToBody: [{ type: Input }], onShown: [{ type: Output }], onHidden: [{ type: Output }], showOrHideOnClick: [{ type: HostListener, args: ['click', ['$event'],] }], showOrHideOnTouch: [{ type: HostListener, args: ['touchend', ['$event'],] }], showOnHover: [{ type: HostListener, args: ['focusin',] }, { type: HostListener, args: ['mouseenter',] }], hideOnHover: [{ type: HostListener, args: ['focusout',] }, { type: HostListener, args: ['mouseleave',] }] }; /** * @fileoverview added by tsickle * Generated from: lib/popover.module.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class PopoverModule { } PopoverModule.decorators = [ { type: NgModule, args: [{ declarations: [ PopoverDirective, PopoverContentComponent ], imports: [ CommonModule, ], exports: [ PopoverContentComponent, PopoverDirective ], entryComponents: [ PopoverContentComponent ] },] } ]; /** * @fileoverview added by tsickle * Generated from: public_api.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @fileoverview added by tsickle * Generated from: ngx-smart-popover.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ export { PopoverContentComponent, PopoverDirective, PopoverModule, PopoverPlacement }; //# sourceMappingURL=ngx-smart-popover.js.map