• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

atinc / ngx-tethys / d9ae709b-3c27-4b69-b125-b8b80b54f90b

pending completion
d9ae709b-3c27-4b69-b125-b8b80b54f90b

Pull #2757

circleci

mengshuicmq
fix: fix code review
Pull Request #2757: feat(color-picker): color-picker support disabled (#INFR-8645)

98 of 6315 branches covered (1.55%)

Branch coverage included in aggregate %.

1 of 1 new or added line in 1 file covered. (100.0%)

2392 of 13661 relevant lines covered (17.51%)

83.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

49.49
/src/core/overlay/overlay.directive.ts
1
import { ChangeDetectorRef, ElementRef, NgZone } from '@angular/core';
2
import { OverlayRef } from '@angular/cdk/overlay';
3
import { Subject, fromEvent } from 'rxjs';
4
import { normalizePassiveListenerOptions, Platform } from '@angular/cdk/platform';
1✔
5
import { FocusMonitor } from '@angular/cdk/a11y';
6
import { takeUntil, take } from 'rxjs/operators';
7

4✔
8
export type ThyOverlayTrigger = 'hover' | 'focus' | 'click';
9

10
const passiveEventListenerOptions = normalizePassiveListenerOptions({ passive: true });
1✔
11

12
export abstract class ThyOverlayDirectiveBase {
1!
13
    protected elementRef: ElementRef;
×
14
    private initialized = false;
×
15
    /** Trigger Overlay */
16
    protected _trigger: ThyOverlayTrigger = 'click';
17
    public get trigger() {
18
        return this._trigger;
1✔
19
    }
1✔
20
    public set trigger(value: ThyOverlayTrigger) {
21
        this._trigger = value;
1✔
22
        // Trigger reinitialize when trigger changed which can't contain first
1✔
23
        if (this.initialized) {
24
            this.clearEventListeners();
25
            this.initialize();
1!
26
        }
×
27
    }
28

1!
29
    protected overlayRef: OverlayRef;
1✔
30
    protected manualListeners = new Map<string, EventListenerOrEventListenerObject>();
31
    protected ngUnsubscribe$ = new Subject<void>();
32
    protected focusMonitor: FocusMonitor;
33
    protected platform: Platform;
1✔
34
    protected ngZone: NgZone;
35
    protected showDelay? = 100;
1✔
36
    protected hideDelay? = 100;
1✔
37
    protected touchendHideDelay? = 0;
1✔
38
    protected disabled = false;
1✔
39
    protected showTimeoutId: number | null | any;
1✔
40
    protected hideTimeoutId: number | null | any;
1✔
41
    protected changeDetectorRef: ChangeDetectorRef;
1✔
42

1✔
43
    /**
1✔
44
     * The overlay keep opened when the mouse moves to the overlay container
1✔
45
     */
1✔
46
    protected overlayPin: boolean;
1✔
47

1✔
48
    /** create overlay, you can use popover service or overlay*/
49
    // abstract createOverlay(): OverlayRef;
50

1✔
51
    abstract show(delay?: number): void;
1✔
52
    abstract hide(delay?: number): void;
1!
53

1!
54
    private clearEventListeners() {
×
55
        this.manualListeners.forEach((listener, event) => {
56
            this.elementRef.nativeElement.removeEventListener(event, listener);
×
57
        });
58
        this.manualListeners.clear();
59
        this.focusMonitor.stopMonitoring(this.elementRef);
60
    }
×
61

×
62
    private clearTimer() {
×
63
        if (this.showTimeoutId) {
×
64
            clearTimeout(this.showTimeoutId);
65
        }
66
        if (this.hideTimeoutId) {
×
67
            clearTimeout(this.hideTimeoutId);
×
68
        }
69
    }
70

×
71
    constructor(
72
        elementRef: ElementRef,
73
        platform: Platform,
74
        focusMonitor: FocusMonitor,
75
        ngZone: NgZone,
×
76
        overlayPin?: boolean,
×
77
        changeDetectorRef?: ChangeDetectorRef
78
    ) {
79
        this.elementRef = elementRef;
80
        this.platform = platform;
1!
81
        this.focusMonitor = focusMonitor;
×
82
        this.ngZone = ngZone;
83
        this.overlayPin = overlayPin;
84
        this.changeDetectorRef = changeDetectorRef;
85
    }
86

×
87
    initialize() {
×
88
        this.initialized = true;
89
        const element: HTMLElement = this.elementRef.nativeElement;
90
        if (!this.platform.IOS && !this.platform.ANDROID) {
×
91
            if (this.trigger === 'hover') {
92
                this.manualListeners
93
                    .set('mouseenter', () => {
94
                        this.show();
95
                    })
96
                    .set('mouseleave', (event: MouseEvent) => {
1!
97
                        // Delay 100ms to avoid the overlay being closed immediately when the cursor is moved to the overlay container
1✔
98
                        this.hide();
×
99
                        const overlayElement: HTMLElement = this.overlayRef && this.overlayRef.overlayElement;
100
                        if (overlayElement && this.overlayPin) {
101
                            fromEvent(overlayElement, 'mouseenter')
×
102
                                .pipe(take(1))
×
103
                                .subscribe(() => {
104
                                    this.clearTimer();
105
                                    fromEvent(overlayElement, 'mouseleave')
106
                                        .pipe(take(1))
×
107
                                        .subscribe(() => {
108
                                            this.hide();
×
109
                                        });
×
110
                                });
111
                        }
112
                        // if showDelay is too long and mouseleave immediately, overlayRef is not exist, we should clearTimeout
113
                        if (!this.overlayRef) {
×
114
                            this.clearTimer();
115
                        }
116
                    });
117
            } else if (this.trigger === 'focus') {
×
118
                this.focusMonitor
119
                    .monitor(this.elementRef)
120
                    .pipe(takeUntil(this.ngUnsubscribe$))
1✔
121
                    .subscribe(origin => {
122
                        // Note that the focus monitor runs outside the Angular zone.
123
                        if (!origin) {
124
                            this.ngZone.run(() => this.hide(0));
1✔
125
                        } else {
126
                            this.ngZone.run(() => this.show());
127
                        }
128
                    });
129
                // this.manualListeners.set('focus', () => this.show());
130
                // this.manualListeners.set('blur', () => this.hide());
131
            } else if (this.trigger === 'click') {
132
                this.manualListeners.set('click', () => {
×
133
                    this.show();
134
                });
135
            } else if (typeof ngDevMode === 'undefined' || ngDevMode) {
1✔
136
                throw new Error(`${this.trigger} is not supporteed, possible values are: hover | focus | click.`);
1✔
137
            }
1!
138
        } else {
×
139
            const touchendListener = () => {
140
                // this.hide(this.touchendHideDelay);
1✔
141
                setTimeout(() => {
1✔
142
                    this.hide(0);
143
                }, this.touchendHideDelay);
144
            };
145
            // Reserve extensions for mobile in the future
146
            this.manualListeners
147
                .set('touchend', touchendListener)
148
                .set('touchcancel', touchendListener)
149
                .set('touchstart', () => {
150
                    this.show();
151
                });
152
        }
153

154
        this.manualListeners.forEach((listener, event) =>
155
            // Note: since Chrome 56 defaults document level `touchstart` listener to passive.
156
            // Element touch listeners are not passive by default.
157
            // We never call `preventDefault()` on events, so we're safe making them passive.
158
            element.addEventListener(event, listener, passiveEventListenerOptions)
159
        );
160
    }
161

162
    /**
163
     * Marks that the overlay needs to be checked in the next change detection run.
164
     * Mainly used for rendering before positioning a overlay, which
165
     * can be problematic in components with OnPush change detection.
166
     */
167
    markForCheck() {
168
        this.changeDetectorRef?.markForCheck();
169
    }
170

171
    dispose(): void {
172
        this.ngUnsubscribe$.next();
173
        this.ngUnsubscribe$.complete();
174
        if (this.overlayRef) {
175
            this.overlayRef.dispose();
176
        }
177
        this.clearEventListeners();
178
        this.clearTimer();
179
    }
180
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc