UNPKG

7.69 kBJavaScriptView Raw
1import { Directive, ElementRef, EventEmitter, Input, Output, Renderer2, ViewContainerRef } from '@angular/core';
2import { PopoverConfig } from './popover.config';
3import { ComponentLoaderFactory } from 'ngx-bootstrap/component-loader';
4import { PopoverContainerComponent } from './popover-container.component';
5import { PositioningService } from 'ngx-bootstrap/positioning';
6import { timer } from 'rxjs';
7import { parseTriggers } from 'ngx-bootstrap/utils';
8let id = 0;
9/**
10 * A lightweight, extensible directive for fancy popover creation.
11 */
12export class PopoverDirective {
13 constructor(_config, _elementRef, _renderer, _viewContainerRef, cis, _positionService) {
14 this._elementRef = _elementRef;
15 this._renderer = _renderer;
16 this._positionService = _positionService;
17 /** unique id popover - use for aria-describedby */
18 this.popoverId = id++;
19 /** sets disable adaptive position */
20 this.adaptivePosition = true;
21 /**
22 * Placement of a popover. Accepts: "top", "bottom", "left", "right"
23 */
24 this.placement = 'top';
25 /**
26 * Close popover on outside click
27 */
28 this.outsideClick = false;
29 /**
30 * Specifies events that should trigger. Supports a space separated list of
31 * event names.
32 */
33 this.triggers = 'click';
34 /**
35 * Css class for popover container
36 */
37 this.containerClass = '';
38 /**
39 * Delay before showing the tooltip
40 */
41 this.delay = 0;
42 this._isInited = false;
43 this._popover = cis
44 .createLoader(_elementRef, _viewContainerRef, _renderer)
45 .provide({ provide: PopoverConfig, useValue: _config });
46 Object.assign(this, _config);
47 this.onShown = this._popover.onShown;
48 this.onHidden = this._popover.onHidden;
49 // fix: no focus on button on Mac OS #1795
50 if (typeof window !== 'undefined') {
51 _elementRef.nativeElement.addEventListener('click', function () {
52 try {
53 _elementRef.nativeElement.focus();
54 }
55 catch (err) {
56 return;
57 }
58 });
59 }
60 }
61 /**
62 * Returns whether or not the popover is currently being shown
63 */
64 get isOpen() {
65 return this._popover.isShown;
66 }
67 set isOpen(value) {
68 if (value) {
69 this.show();
70 }
71 else {
72 this.hide();
73 }
74 }
75 /**
76 * Set attribute aria-describedBy for element directive and
77 * set id for the popover
78 */
79 setAriaDescribedBy() {
80 this._ariaDescribedby = this.isOpen ? `ngx-popover-${this.popoverId}` : void 0;
81 if (this._ariaDescribedby) {
82 if (this._popover.instance) {
83 this._popover.instance.popoverId = this._ariaDescribedby;
84 }
85 this._renderer.setAttribute(this._elementRef.nativeElement, 'aria-describedby', this._ariaDescribedby);
86 }
87 else {
88 this._renderer.removeAttribute(this._elementRef.nativeElement, 'aria-describedby');
89 }
90 }
91 /**
92 * Opens an element’s popover. This is considered a “manual” triggering of
93 * the popover.
94 */
95 show() {
96 if (this._popover.isShown || !this.popover || this._delayTimeoutId) {
97 return;
98 }
99 this._positionService.setOptions({
100 modifiers: {
101 flip: {
102 enabled: this.adaptivePosition
103 },
104 preventOverflow: {
105 enabled: this.adaptivePosition
106 }
107 }
108 });
109 const showPopover = () => {
110 if (this._delayTimeoutId) {
111 this._delayTimeoutId = undefined;
112 }
113 this._popover
114 .attach(PopoverContainerComponent)
115 .to(this.container)
116 .position({ attachment: this.placement })
117 .show({
118 content: this.popover,
119 context: this.popoverContext,
120 placement: this.placement,
121 title: this.popoverTitle,
122 containerClass: this.containerClass
123 });
124 if (!this.adaptivePosition && this._popover._componentRef) {
125 this._positionService.calcPosition();
126 this._positionService.deletePositionElement(this._popover._componentRef.location);
127 }
128 this.isOpen = true;
129 this.setAriaDescribedBy();
130 };
131 const cancelDelayedTooltipShowing = () => {
132 if (this._popoverCancelShowFn) {
133 this._popoverCancelShowFn();
134 }
135 };
136 if (this.delay) {
137 const _timer = timer(this.delay).subscribe(() => {
138 showPopover();
139 cancelDelayedTooltipShowing();
140 });
141 if (this.triggers) {
142 parseTriggers(this.triggers)
143 .forEach((trigger) => {
144 if (!trigger.close) {
145 return;
146 }
147 this._popoverCancelShowFn = this._renderer.listen(this._elementRef.nativeElement, trigger.close, () => {
148 _timer.unsubscribe();
149 cancelDelayedTooltipShowing();
150 });
151 });
152 }
153 }
154 else {
155 showPopover();
156 }
157 }
158 /**
159 * Closes an element’s popover. This is considered a “manual” triggering of
160 * the popover.
161 */
162 hide() {
163 if (this._delayTimeoutId) {
164 clearTimeout(this._delayTimeoutId);
165 this._delayTimeoutId = undefined;
166 }
167 if (this.isOpen) {
168 this._popover.hide();
169 this.setAriaDescribedBy();
170 this.isOpen = false;
171 }
172 }
173 /**
174 * Toggles an element’s popover. This is considered a “manual” triggering of
175 * the popover.
176 */
177 toggle() {
178 if (this.isOpen) {
179 return this.hide();
180 }
181 this.show();
182 }
183 ngOnInit() {
184 // fix: seems there are an issue with `routerLinkActive`
185 // which result in duplicated call ngOnInit without call to ngOnDestroy
186 // read more: https://github.com/valor-software/ngx-bootstrap/issues/1885
187 if (this._isInited) {
188 return;
189 }
190 this._isInited = true;
191 this._popover.listen({
192 triggers: this.triggers,
193 outsideClick: this.outsideClick,
194 show: () => this.show(),
195 hide: () => this.hide()
196 });
197 }
198 ngOnDestroy() {
199 this._popover.dispose();
200 }
201}
202PopoverDirective.decorators = [
203 { type: Directive, args: [{ selector: '[popover]', exportAs: 'bs-popover' },] }
204];
205PopoverDirective.ctorParameters = () => [
206 { type: PopoverConfig },
207 { type: ElementRef },
208 { type: Renderer2 },
209 { type: ViewContainerRef },
210 { type: ComponentLoaderFactory },
211 { type: PositioningService }
212];
213PopoverDirective.propDecorators = {
214 adaptivePosition: [{ type: Input }],
215 popover: [{ type: Input }],
216 popoverContext: [{ type: Input }],
217 popoverTitle: [{ type: Input }],
218 placement: [{ type: Input }],
219 outsideClick: [{ type: Input }],
220 triggers: [{ type: Input }],
221 container: [{ type: Input }],
222 containerClass: [{ type: Input }],
223 isOpen: [{ type: Input }],
224 delay: [{ type: Input }],
225 onShown: [{ type: Output }],
226 onHidden: [{ type: Output }]
227};
228//# sourceMappingURL=popover.directive.js.map
\No newline at end of file