1 | import { Directive, ElementRef, EventEmitter, Input, Output, Renderer2, ViewContainerRef } from '@angular/core';
|
2 | import { PopoverConfig } from './popover.config';
|
3 | import { ComponentLoaderFactory } from 'ngx-bootstrap/component-loader';
|
4 | import { PopoverContainerComponent } from './popover-container.component';
|
5 | import { PositioningService } from 'ngx-bootstrap/positioning';
|
6 | import { timer } from 'rxjs';
|
7 | import { parseTriggers } from 'ngx-bootstrap/utils';
|
8 | let id = 0;
|
9 |
|
10 |
|
11 |
|
12 | export class PopoverDirective {
|
13 | constructor(_config, _elementRef, _renderer, _viewContainerRef, cis, _positionService) {
|
14 | this._elementRef = _elementRef;
|
15 | this._renderer = _renderer;
|
16 | this._positionService = _positionService;
|
17 |
|
18 | this.popoverId = id++;
|
19 |
|
20 | this.adaptivePosition = true;
|
21 | |
22 |
|
23 |
|
24 | this.placement = 'top';
|
25 | |
26 |
|
27 |
|
28 | this.outsideClick = false;
|
29 | |
30 |
|
31 |
|
32 |
|
33 | this.triggers = 'click';
|
34 | |
35 |
|
36 |
|
37 | this.containerClass = '';
|
38 | |
39 |
|
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 |
|
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 |
|
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 |
|
77 |
|
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 |
|
93 |
|
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 |
|
160 |
|
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 |
|
175 |
|
176 |
|
177 | toggle() {
|
178 | if (this.isOpen) {
|
179 | return this.hide();
|
180 | }
|
181 | this.show();
|
182 | }
|
183 | ngOnInit() {
|
184 |
|
185 |
|
186 |
|
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 | }
|
202 | PopoverDirective.decorators = [
|
203 | { type: Directive, args: [{ selector: '[popover]', exportAs: 'bs-popover' },] }
|
204 | ];
|
205 | PopoverDirective.ctorParameters = () => [
|
206 | { type: PopoverConfig },
|
207 | { type: ElementRef },
|
208 | { type: Renderer2 },
|
209 | { type: ViewContainerRef },
|
210 | { type: ComponentLoaderFactory },
|
211 | { type: PositioningService }
|
212 | ];
|
213 | PopoverDirective.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 |
|
\ | No newline at end of file |