|
@@ -1,6 +1,9 @@
|
1
|
|
-import { Directive, forwardRef, Input, AfterViewInit, ElementRef, ViewContainerRef } from '@angular/core';
|
|
1
|
+import { Directive, forwardRef, Input, AfterViewInit, ElementRef, ViewContainerRef, OnDestroy, NgZone } from '@angular/core';
|
2
|
2
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
3
|
3
|
import { C3Tooltip } from './c3-tooltip.component';
|
|
4
|
+import { Overlay, OverlayRef, OverlayConfig, PositionStrategy, FlexibleConnectedPositionStrategy, ConnectedPosition } from '@angular/cdk/overlay';
|
|
5
|
+import { Platform } from '@angular/cdk/platform';
|
|
6
|
+import { TemplatePortal } from '@angular/cdk/portal';
|
4
|
7
|
|
5
|
8
|
export const MAT_AUTOCOMPLETE_VALUE_ACCESSOR: any = {
|
6
|
9
|
provide: NG_VALUE_ACCESSOR,
|
|
@@ -9,20 +12,122 @@ export const MAT_AUTOCOMPLETE_VALUE_ACCESSOR: any = {
|
9
|
12
|
};
|
10
|
13
|
|
11
|
14
|
@Directive({
|
12
|
|
- selector: 'button[c3Tooltip]',
|
|
15
|
+ selector: '[c3Tooltip]',
|
13
|
16
|
exportAs: 'c3TooltipTrigger',
|
14
|
17
|
providers: [MAT_AUTOCOMPLETE_VALUE_ACCESSOR]
|
15
|
18
|
})
|
16
|
|
-export class C3TooltipTrigger implements AfterViewInit {
|
|
19
|
+export class C3TooltipTrigger implements AfterViewInit, OnDestroy {
|
|
20
|
+ private _overlayRef: OverlayRef | null;
|
|
21
|
+ private _portal: TemplatePortal;
|
|
22
|
+ private _positionStrategy: FlexibleConnectedPositionStrategy;
|
|
23
|
+ private _overlayAttached: boolean = false;
|
|
24
|
+
|
17
|
25
|
@Input('c3Tooltip') tooltip: C3Tooltip;
|
18
|
26
|
|
|
27
|
+ @Input('c3TooltipDisabled') disabled: Boolean = false;
|
|
28
|
+
|
|
29
|
+ /** The default delay in ms before showing the tooltip after show is called */
|
|
30
|
+ @Input('c3TooltipShowDelay') showDelay = 0;
|
|
31
|
+
|
|
32
|
+ /** The default delay in ms before hiding the tooltip after hide is called */
|
|
33
|
+ @Input('c3TooltipHideDelay') hideDelay = 0;
|
|
34
|
+
|
|
35
|
+ private _manualListeners = new Map<string, EventListenerOrEventListenerObject>();
|
|
36
|
+
|
19
|
37
|
constructor(
|
20
|
|
- private _element: ElementRef<HTMLInputElement>,
|
21
|
|
- // private _overlay: Overlay,
|
|
38
|
+ private _element: ElementRef<HTMLElement>,
|
|
39
|
+ private _overlay: Overlay,
|
|
40
|
+ platform: Platform,
|
|
41
|
+ private _ngZone: NgZone,
|
22
|
42
|
private _viewContainerRef: ViewContainerRef) {
|
|
43
|
+ if (!platform.IOS && !platform.ANDROID) {
|
|
44
|
+ this._manualListeners
|
|
45
|
+ .set('mouseenter', () => this.show())
|
|
46
|
+ .set('mouseleave', () => this.hide());
|
|
47
|
+ }
|
23
|
48
|
}
|
24
|
49
|
|
25
|
50
|
ngAfterViewInit() {
|
26
|
|
- console.log(this.tooltip.template)
|
|
51
|
+ this._manualListeners.forEach((listener, event) => this._element.nativeElement.addEventListener(event, listener));
|
|
52
|
+ }
|
|
53
|
+
|
|
54
|
+ ngOnDestroy() {
|
|
55
|
+ this._manualListeners.forEach((listener, event) => {
|
|
56
|
+ this._element.nativeElement.removeEventListener(event, listener);
|
|
57
|
+ });
|
|
58
|
+ this._manualListeners.clear();
|
|
59
|
+ }
|
|
60
|
+
|
|
61
|
+ show(delay: number = this.showDelay) {
|
|
62
|
+ console.log('show')
|
|
63
|
+ let overlayRef = this._overlayRef;
|
|
64
|
+
|
|
65
|
+ if (!overlayRef) {
|
|
66
|
+ this._portal = new TemplatePortal(this.tooltip.template, this._viewContainerRef);
|
|
67
|
+ overlayRef = this._overlay.create(this._getOverlayConfig());
|
|
68
|
+ this._overlayRef = overlayRef;
|
|
69
|
+ }
|
|
70
|
+
|
|
71
|
+ if (overlayRef && !overlayRef.hasAttached()) {
|
|
72
|
+ overlayRef.attach(this._portal);
|
|
73
|
+ this._overlayAttached = true;
|
|
74
|
+ }
|
|
75
|
+ }
|
|
76
|
+
|
|
77
|
+ get panelOpen(): boolean {
|
|
78
|
+ return this._overlayAttached;
|
|
79
|
+ }
|
|
80
|
+
|
|
81
|
+ hide() {
|
|
82
|
+ if (!this._overlayAttached) {
|
|
83
|
+ return;
|
|
84
|
+ }
|
|
85
|
+
|
|
86
|
+ if (this._overlayRef && this._overlayRef.hasAttached()) {
|
|
87
|
+ this._overlayRef.detach();
|
|
88
|
+ }
|
|
89
|
+ }
|
|
90
|
+
|
|
91
|
+ private _getOverlayConfig(): OverlayConfig {
|
|
92
|
+ return new OverlayConfig({
|
|
93
|
+ positionStrategy: this._getOverlayPosition(),
|
|
94
|
+ width: this._element.nativeElement.getBoundingClientRect().width
|
|
95
|
+ });
|
|
96
|
+ }
|
|
97
|
+
|
|
98
|
+ private _getOverlayPosition(): PositionStrategy {
|
|
99
|
+ const strategy = this._overlay.position()
|
|
100
|
+ .flexibleConnectedTo(this.tooltip.template.elementRef)
|
|
101
|
+ .withFlexibleDimensions(true)
|
|
102
|
+ .withPush(false)
|
|
103
|
+ .withViewportMargin(8);
|
|
104
|
+
|
|
105
|
+ this._setStrategyPositions(strategy);
|
|
106
|
+ this._positionStrategy = strategy;
|
|
107
|
+ return strategy;
|
|
108
|
+ }
|
|
109
|
+ private _setStrategyPositions(positionStrategy: FlexibleConnectedPositionStrategy) {
|
|
110
|
+ const belowPosition: ConnectedPosition = {
|
|
111
|
+ originX: 'start',
|
|
112
|
+ originY: 'bottom',
|
|
113
|
+ overlayX: 'start',
|
|
114
|
+ overlayY: 'top'
|
|
115
|
+ };
|
|
116
|
+ const abovePosition: ConnectedPosition = {
|
|
117
|
+ originX: 'start',
|
|
118
|
+ originY: 'top',
|
|
119
|
+ overlayX: 'start',
|
|
120
|
+ overlayY: 'bottom',
|
|
121
|
+
|
|
122
|
+ // The overlay edge connected to the trigger should have squared corners, while
|
|
123
|
+ // the opposite end has rounded corners. We apply a CSS class to swap the
|
|
124
|
+ // border-radius based on the overlay position.
|
|
125
|
+ };
|
|
126
|
+
|
|
127
|
+ let positions: ConnectedPosition[];
|
|
128
|
+
|
|
129
|
+ positions = [belowPosition, abovePosition];
|
|
130
|
+
|
|
131
|
+ positionStrategy.withPositions(positions);
|
27
|
132
|
}
|
28
|
133
|
}
|