1 | import { Directive, ElementRef, NgZone, Input, NgModule } from '@angular/core';
|
2 | import { CommonModule } from '@angular/common';
|
3 | import { DomHandler } from 'primeng/dom';
|
4 |
|
5 | class Tooltip {
|
6 | constructor(el, zone) {
|
7 | this.el = el;
|
8 | this.zone = zone;
|
9 | this.tooltipPosition = 'right';
|
10 | this.tooltipEvent = 'hover';
|
11 | this.appendTo = 'body';
|
12 | this.tooltipZIndex = 'auto';
|
13 | this.escape = true;
|
14 | }
|
15 | get disabled() {
|
16 | return this._disabled;
|
17 | }
|
18 | set disabled(val) {
|
19 | this._disabled = val;
|
20 | this.deactivate();
|
21 | }
|
22 | ngAfterViewInit() {
|
23 | this.zone.runOutsideAngular(() => {
|
24 | if (this.tooltipEvent === 'hover') {
|
25 | this.mouseEnterListener = this.onMouseEnter.bind(this);
|
26 | this.mouseLeaveListener = this.onMouseLeave.bind(this);
|
27 | this.clickListener = this.onClick.bind(this);
|
28 | this.el.nativeElement.addEventListener('mouseenter', this.mouseEnterListener);
|
29 | this.el.nativeElement.addEventListener('mouseleave', this.mouseLeaveListener);
|
30 | this.el.nativeElement.addEventListener('click', this.clickListener);
|
31 | }
|
32 | else if (this.tooltipEvent === 'focus') {
|
33 | this.focusListener = this.onFocus.bind(this);
|
34 | this.blurListener = this.onBlur.bind(this);
|
35 | this.el.nativeElement.addEventListener('focus', this.focusListener);
|
36 | this.el.nativeElement.addEventListener('blur', this.blurListener);
|
37 | }
|
38 | });
|
39 | }
|
40 | onMouseEnter(e) {
|
41 | if (!this.container && !this.showTimeout) {
|
42 | this.activate();
|
43 | }
|
44 | }
|
45 | onMouseLeave(e) {
|
46 | this.deactivate();
|
47 | }
|
48 | onFocus(e) {
|
49 | this.activate();
|
50 | }
|
51 | onBlur(e) {
|
52 | this.deactivate();
|
53 | }
|
54 | onClick(e) {
|
55 | this.deactivate();
|
56 | }
|
57 | activate() {
|
58 | this.active = true;
|
59 | this.clearHideTimeout();
|
60 | if (this.showDelay)
|
61 | this.showTimeout = setTimeout(() => { this.show(); }, this.showDelay);
|
62 | else
|
63 | this.show();
|
64 | if (this.life) {
|
65 | let duration = this.showDelay ? this.life + this.showDelay : this.life;
|
66 | this.hideTimeout = setTimeout(() => { this.hide(); }, duration);
|
67 | }
|
68 | }
|
69 | deactivate() {
|
70 | this.active = false;
|
71 | this.clearShowTimeout();
|
72 | if (this.hideDelay) {
|
73 | this.clearHideTimeout();
|
74 | this.hideTimeout = setTimeout(() => { this.hide(); }, this.hideDelay);
|
75 | }
|
76 | else {
|
77 | this.hide();
|
78 | }
|
79 | }
|
80 | get text() {
|
81 | return this._text;
|
82 | }
|
83 | set text(text) {
|
84 | this._text = text;
|
85 | if (this.active) {
|
86 | if (this._text) {
|
87 | if (this.container && this.container.offsetParent) {
|
88 | this.updateText();
|
89 | this.align();
|
90 | }
|
91 | else {
|
92 | this.show();
|
93 | }
|
94 | }
|
95 | else {
|
96 | this.hide();
|
97 | }
|
98 | }
|
99 | }
|
100 | create() {
|
101 | if (this.container) {
|
102 | this.clearHideTimeout();
|
103 | this.remove();
|
104 | }
|
105 | this.container = document.createElement('div');
|
106 | let tooltipArrow = document.createElement('div');
|
107 | tooltipArrow.className = 'p-tooltip-arrow';
|
108 | this.container.appendChild(tooltipArrow);
|
109 | this.tooltipText = document.createElement('div');
|
110 | this.tooltipText.className = 'p-tooltip-text';
|
111 | this.updateText();
|
112 | if (this.positionStyle) {
|
113 | this.container.style.position = this.positionStyle;
|
114 | }
|
115 | this.container.appendChild(this.tooltipText);
|
116 | if (this.appendTo === 'body')
|
117 | document.body.appendChild(this.container);
|
118 | else if (this.appendTo === 'target')
|
119 | DomHandler.appendChild(this.container, this.el.nativeElement);
|
120 | else
|
121 | DomHandler.appendChild(this.container, this.appendTo);
|
122 | this.container.style.display = 'inline-block';
|
123 | }
|
124 | show() {
|
125 | if (!this.text || this.disabled) {
|
126 | return;
|
127 | }
|
128 | this.create();
|
129 | this.align();
|
130 | DomHandler.fadeIn(this.container, 250);
|
131 | if (this.tooltipZIndex === 'auto')
|
132 | this.container.style.zIndex = ++DomHandler.zindex;
|
133 | else
|
134 | this.container.style.zIndex = this.tooltipZIndex;
|
135 | this.bindDocumentResizeListener();
|
136 | }
|
137 | hide() {
|
138 | this.remove();
|
139 | }
|
140 | updateText() {
|
141 | if (this.escape) {
|
142 | this.tooltipText.innerHTML = '';
|
143 | this.tooltipText.appendChild(document.createTextNode(this._text));
|
144 | }
|
145 | else {
|
146 | this.tooltipText.innerHTML = this._text;
|
147 | }
|
148 | }
|
149 | align() {
|
150 | let position = this.tooltipPosition;
|
151 | switch (position) {
|
152 | case 'top':
|
153 | this.alignTop();
|
154 | if (this.isOutOfBounds()) {
|
155 | this.alignBottom();
|
156 | if (this.isOutOfBounds()) {
|
157 | this.alignRight();
|
158 | if (this.isOutOfBounds()) {
|
159 | this.alignLeft();
|
160 | }
|
161 | }
|
162 | }
|
163 | break;
|
164 | case 'bottom':
|
165 | this.alignBottom();
|
166 | if (this.isOutOfBounds()) {
|
167 | this.alignTop();
|
168 | if (this.isOutOfBounds()) {
|
169 | this.alignRight();
|
170 | if (this.isOutOfBounds()) {
|
171 | this.alignLeft();
|
172 | }
|
173 | }
|
174 | }
|
175 | break;
|
176 | case 'left':
|
177 | this.alignLeft();
|
178 | if (this.isOutOfBounds()) {
|
179 | this.alignRight();
|
180 | if (this.isOutOfBounds()) {
|
181 | this.alignTop();
|
182 | if (this.isOutOfBounds()) {
|
183 | this.alignBottom();
|
184 | }
|
185 | }
|
186 | }
|
187 | break;
|
188 | case 'right':
|
189 | this.alignRight();
|
190 | if (this.isOutOfBounds()) {
|
191 | this.alignLeft();
|
192 | if (this.isOutOfBounds()) {
|
193 | this.alignTop();
|
194 | if (this.isOutOfBounds()) {
|
195 | this.alignBottom();
|
196 | }
|
197 | }
|
198 | }
|
199 | break;
|
200 | }
|
201 | }
|
202 | getHostOffset() {
|
203 | if (this.appendTo === 'body' || this.appendTo === 'target') {
|
204 | let offset = this.el.nativeElement.getBoundingClientRect();
|
205 | let targetLeft = offset.left + DomHandler.getWindowScrollLeft();
|
206 | let targetTop = offset.top + DomHandler.getWindowScrollTop();
|
207 | return { left: targetLeft, top: targetTop };
|
208 | }
|
209 | else {
|
210 | return { left: 0, top: 0 };
|
211 | }
|
212 | }
|
213 | alignRight() {
|
214 | this.preAlign('right');
|
215 | let hostOffset = this.getHostOffset();
|
216 | let left = hostOffset.left + DomHandler.getOuterWidth(this.el.nativeElement);
|
217 | let top = hostOffset.top + (DomHandler.getOuterHeight(this.el.nativeElement) - DomHandler.getOuterHeight(this.container)) / 2;
|
218 | this.container.style.left = left + 'px';
|
219 | this.container.style.top = top + 'px';
|
220 | }
|
221 | alignLeft() {
|
222 | this.preAlign('left');
|
223 | let hostOffset = this.getHostOffset();
|
224 | let left = hostOffset.left - DomHandler.getOuterWidth(this.container);
|
225 | let top = hostOffset.top + (DomHandler.getOuterHeight(this.el.nativeElement) - DomHandler.getOuterHeight(this.container)) / 2;
|
226 | this.container.style.left = left + 'px';
|
227 | this.container.style.top = top + 'px';
|
228 | }
|
229 | alignTop() {
|
230 | this.preAlign('top');
|
231 | let hostOffset = this.getHostOffset();
|
232 | let left = hostOffset.left + (DomHandler.getOuterWidth(this.el.nativeElement) - DomHandler.getOuterWidth(this.container)) / 2;
|
233 | let top = hostOffset.top - DomHandler.getOuterHeight(this.container);
|
234 | this.container.style.left = left + 'px';
|
235 | this.container.style.top = top + 'px';
|
236 | }
|
237 | alignBottom() {
|
238 | this.preAlign('bottom');
|
239 | let hostOffset = this.getHostOffset();
|
240 | let left = hostOffset.left + (DomHandler.getOuterWidth(this.el.nativeElement) - DomHandler.getOuterWidth(this.container)) / 2;
|
241 | let top = hostOffset.top + DomHandler.getOuterHeight(this.el.nativeElement);
|
242 | this.container.style.left = left + 'px';
|
243 | this.container.style.top = top + 'px';
|
244 | }
|
245 | preAlign(position) {
|
246 | this.container.style.left = -999 + 'px';
|
247 | this.container.style.top = -999 + 'px';
|
248 | let defaultClassName = 'p-tooltip p-component p-tooltip-' + position;
|
249 | this.container.className = this.tooltipStyleClass ? defaultClassName + ' ' + this.tooltipStyleClass : defaultClassName;
|
250 | }
|
251 | isOutOfBounds() {
|
252 | let offset = this.container.getBoundingClientRect();
|
253 | let targetTop = offset.top;
|
254 | let targetLeft = offset.left;
|
255 | let width = DomHandler.getOuterWidth(this.container);
|
256 | let height = DomHandler.getOuterHeight(this.container);
|
257 | let viewport = DomHandler.getViewport();
|
258 | return (targetLeft + width > viewport.width) || (targetLeft < 0) || (targetTop < 0) || (targetTop + height > viewport.height);
|
259 | }
|
260 | onWindowResize(e) {
|
261 | this.hide();
|
262 | }
|
263 | bindDocumentResizeListener() {
|
264 | this.zone.runOutsideAngular(() => {
|
265 | this.resizeListener = this.onWindowResize.bind(this);
|
266 | window.addEventListener('resize', this.resizeListener);
|
267 | });
|
268 | }
|
269 | unbindDocumentResizeListener() {
|
270 | if (this.resizeListener) {
|
271 | window.removeEventListener('resize', this.resizeListener);
|
272 | this.resizeListener = null;
|
273 | }
|
274 | }
|
275 | unbindEvents() {
|
276 | if (this.tooltipEvent === 'hover') {
|
277 | this.el.nativeElement.removeEventListener('mouseenter', this.mouseEnterListener);
|
278 | this.el.nativeElement.removeEventListener('mouseleave', this.mouseLeaveListener);
|
279 | this.el.nativeElement.removeEventListener('click', this.clickListener);
|
280 | }
|
281 | else if (this.tooltipEvent === 'focus') {
|
282 | this.el.nativeElement.removeEventListener('focus', this.focusListener);
|
283 | this.el.nativeElement.removeEventListener('blur', this.blurListener);
|
284 | }
|
285 | this.unbindDocumentResizeListener();
|
286 | }
|
287 | remove() {
|
288 | if (this.container && this.container.parentElement) {
|
289 | if (this.appendTo === 'body')
|
290 | document.body.removeChild(this.container);
|
291 | else if (this.appendTo === 'target')
|
292 | this.el.nativeElement.removeChild(this.container);
|
293 | else
|
294 | DomHandler.removeChild(this.container, this.appendTo);
|
295 | }
|
296 | this.unbindDocumentResizeListener();
|
297 | this.clearTimeouts();
|
298 | this.container = null;
|
299 | }
|
300 | clearShowTimeout() {
|
301 | if (this.showTimeout) {
|
302 | clearTimeout(this.showTimeout);
|
303 | this.showTimeout = null;
|
304 | }
|
305 | }
|
306 | clearHideTimeout() {
|
307 | if (this.hideTimeout) {
|
308 | clearTimeout(this.hideTimeout);
|
309 | this.hideTimeout = null;
|
310 | }
|
311 | }
|
312 | clearTimeouts() {
|
313 | this.clearShowTimeout();
|
314 | this.clearHideTimeout();
|
315 | }
|
316 | ngOnDestroy() {
|
317 | this.unbindEvents();
|
318 | this.remove();
|
319 | }
|
320 | }
|
321 | Tooltip.decorators = [
|
322 | { type: Directive, args: [{
|
323 | selector: '[pTooltip]'
|
324 | },] }
|
325 | ];
|
326 | Tooltip.ctorParameters = () => [
|
327 | { type: ElementRef },
|
328 | { type: NgZone }
|
329 | ];
|
330 | Tooltip.propDecorators = {
|
331 | tooltipPosition: [{ type: Input }],
|
332 | tooltipEvent: [{ type: Input }],
|
333 | appendTo: [{ type: Input }],
|
334 | positionStyle: [{ type: Input }],
|
335 | tooltipStyleClass: [{ type: Input }],
|
336 | tooltipZIndex: [{ type: Input }],
|
337 | escape: [{ type: Input }],
|
338 | showDelay: [{ type: Input }],
|
339 | hideDelay: [{ type: Input }],
|
340 | life: [{ type: Input }],
|
341 | disabled: [{ type: Input, args: ["tooltipDisabled",] }],
|
342 | text: [{ type: Input, args: ['pTooltip',] }]
|
343 | };
|
344 | class TooltipModule {
|
345 | }
|
346 | TooltipModule.decorators = [
|
347 | { type: NgModule, args: [{
|
348 | imports: [CommonModule],
|
349 | exports: [Tooltip],
|
350 | declarations: [Tooltip]
|
351 | },] }
|
352 | ];
|
353 |
|
354 |
|
355 |
|
356 |
|
357 |
|
358 | export { Tooltip, TooltipModule };
|
359 |
|