|
@@ -1,133 +1,86 @@
|
1
|
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';
|
|
4
|
+import { Overlay, OverlayConfig, ScrollDispatcher, OverlayRef } from '@angular/cdk/overlay';
|
5
|
5
|
import { Platform } from '@angular/cdk/platform';
|
6
|
6
|
import { TemplatePortal } from '@angular/cdk/portal';
|
7
|
7
|
|
8
|
8
|
export const MAT_AUTOCOMPLETE_VALUE_ACCESSOR: any = {
|
9
|
|
- provide: NG_VALUE_ACCESSOR,
|
10
|
|
- useExisting: forwardRef(() => C3TooltipTrigger),
|
11
|
|
- multi: true
|
|
9
|
+ provide: NG_VALUE_ACCESSOR,
|
|
10
|
+ useExisting: forwardRef(() => C3TooltipTrigger),
|
|
11
|
+ multi: true
|
12
|
12
|
};
|
13
|
13
|
|
14
|
14
|
@Directive({
|
15
|
|
- selector: '[c3Tooltip]',
|
16
|
|
- exportAs: 'c3TooltipTrigger',
|
17
|
|
- providers: [MAT_AUTOCOMPLETE_VALUE_ACCESSOR]
|
|
15
|
+ selector: '[c3Tooltip]',
|
|
16
|
+ exportAs: 'c3TooltipTrigger',
|
|
17
|
+ providers: [MAT_AUTOCOMPLETE_VALUE_ACCESSOR]
|
18
|
18
|
})
|
19
|
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;
|
|
20
|
+ overlayRef: OverlayRef | null;
|
24
|
21
|
|
25
|
|
- @Input('c3Tooltip') tooltip: C3Tooltip;
|
|
22
|
+ @Input('c3Tooltip') tooltip: C3Tooltip;
|
26
|
23
|
|
27
|
|
- @Input('c3TooltipDisabled') disabled: Boolean = false;
|
|
24
|
+ @Input('c3TooltipDisabled') disabled: Boolean = false;
|
28
|
25
|
|
29
|
|
- /** The default delay in ms before showing the tooltip after show is called */
|
30
|
|
- @Input('c3TooltipShowDelay') showDelay = 0;
|
|
26
|
+ /** The default delay in ms before showing the tooltip after show is called */
|
|
27
|
+ @Input('c3TooltipShowDelay') showDelay = 0;
|
31
|
28
|
|
32
|
|
- /** The default delay in ms before hiding the tooltip after hide is called */
|
33
|
|
- @Input('c3TooltipHideDelay') hideDelay = 0;
|
|
29
|
+ /** The default delay in ms before hiding the tooltip after hide is called */
|
|
30
|
+ @Input('c3TooltipHideDelay') hideDelay = 0;
|
34
|
31
|
|
35
|
|
- private _manualListeners = new Map<string, EventListenerOrEventListenerObject>();
|
|
32
|
+ private _manualListeners = new Map<string, EventListenerOrEventListenerObject>();
|
36
|
33
|
|
37
|
|
- constructor(
|
38
|
|
- private _element: ElementRef<HTMLElement>,
|
39
|
|
- private _overlay: Overlay,
|
40
|
|
- platform: Platform,
|
41
|
|
- private _ngZone: NgZone,
|
42
|
|
- private _viewContainerRef: ViewContainerRef) {
|
43
|
|
- if (!platform.IOS && !platform.ANDROID) {
|
44
|
|
- this._manualListeners
|
45
|
|
- .set('mouseenter', () => this.show())
|
46
|
|
- .set('mouseleave', () => this.hide());
|
47
|
|
- }
|
48
|
|
- }
|
49
|
|
-
|
50
|
|
- ngAfterViewInit() {
|
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;
|
|
34
|
+ constructor(
|
|
35
|
+ private _element: ElementRef<HTMLElement>,
|
|
36
|
+ private _overlay: Overlay,
|
|
37
|
+ platform: Platform,
|
|
38
|
+ private _ngZone: NgZone,
|
|
39
|
+ private _scrollDispatcher: ScrollDispatcher,
|
|
40
|
+ private _viewContainerRef: ViewContainerRef) {
|
|
41
|
+ if (!platform.IOS && !platform.ANDROID) {
|
|
42
|
+ this._manualListeners
|
|
43
|
+ .set('mouseenter', () => this.show())
|
|
44
|
+ .set('mouseleave', () => this.hide());
|
74
|
45
|
}
|
75
|
|
- }
|
76
|
|
-
|
77
|
|
- get panelOpen(): boolean {
|
78
|
|
- return this._overlayAttached;
|
79
|
46
|
}
|
80
|
47
|
|
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);
|
|
48
|
+ ngAfterViewInit() {
|
|
49
|
+ this._manualListeners.forEach((listener, event) => this._element.nativeElement.addEventListener(event, listener));
|
|
50
|
+ }
|
104
|
51
|
|
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',
|
|
52
|
+ ngOnDestroy() {
|
|
53
|
+ this._manualListeners.forEach((listener, event) => {
|
|
54
|
+ this._element.nativeElement.removeEventListener(event, listener);
|
|
55
|
+ });
|
|
56
|
+ this._manualListeners.clear();
|
|
57
|
+ }
|
121
|
58
|
|
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
|
|
- };
|
|
59
|
+ show() {
|
|
60
|
+ const overlayRef = this._overlay.create(this.getOverlayConfig());
|
|
61
|
+ const portal = new TemplatePortal(this.tooltip.template, this._viewContainerRef);
|
|
62
|
+ overlayRef.attach(portal);
|
126
|
63
|
|
127
|
|
- let positions: ConnectedPosition[];
|
|
64
|
+ this.overlayRef = overlayRef;
|
|
65
|
+ }
|
128
|
66
|
|
129
|
|
- positions = [belowPosition, abovePosition];
|
|
67
|
+ hide() {
|
|
68
|
+ this.overlayRef.detach();
|
|
69
|
+ }
|
130
|
70
|
|
131
|
|
- positionStrategy.withPositions(positions);
|
132
|
|
- }
|
|
71
|
+ private getOverlayConfig(): OverlayConfig {
|
|
72
|
+ const positionStrategy = this._overlay.position()
|
|
73
|
+ .flexibleConnectedTo(this._element)
|
|
74
|
+ .withPositions([{
|
|
75
|
+ originX: 'start',
|
|
76
|
+ originY: 'top',
|
|
77
|
+ overlayX: 'center',
|
|
78
|
+ overlayY: 'bottom',
|
|
79
|
+ }])
|
|
80
|
+ .withViewportMargin(8);
|
|
81
|
+
|
|
82
|
+ return new OverlayConfig({
|
|
83
|
+ positionStrategy
|
|
84
|
+ })
|
|
85
|
+ }
|
133
|
86
|
}
|