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

atinc / ngx-tethys / e62d3b10-1466-49c3-aabd-707148681fc8

14 Jun 2024 08:24AM UTC coverage: 90.422%. Remained the same
e62d3b10-1466-49c3-aabd-707148681fc8

push

circleci

minlovehua
feat: use the ngx-tethys/util's coerceBooleanProperty instead of booleanAttribute #INFR-12648

5467 of 6692 branches covered (81.69%)

Branch coverage included in aggregate %.

117 of 120 new or added lines in 66 files covered. (97.5%)

183 existing lines in 46 files now uncovered.

13216 of 13970 relevant lines covered (94.6%)

985.91 hits per line

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

86.0
/src/date-picker/abstract-picker.directive.ts
1
import { ThyPlacement } from 'ngx-tethys/core';
2
import { ThyPopover, ThyPopoverConfig } from 'ngx-tethys/popover';
3
import { FunctionProp, warnDeprecation } from 'ngx-tethys/util';
4
import { fromEvent, Observable, Subject } from 'rxjs';
5
import { debounceTime, mapTo, takeUntil, tap } from 'rxjs/operators';
6

7
import { coerceArray, coerceBooleanProperty } from '@angular/cdk/coercion';
8
import {
9
    AfterViewInit,
10
    ChangeDetectorRef,
11
    Directive,
12
    ElementRef,
13
    EventEmitter,
14
    Input,
1✔
15
    OnChanges,
16
    OnDestroy,
27✔
17
    OnInit,
18
    Output,
19
    SimpleChange,
15!
20
    TemplateRef,
21
    numberAttribute
22
} from '@angular/core';
15!
23

15✔
24
import { AbstractPickerComponent } from './abstract-picker.component';
25
import { DatePopup } from './lib/popups/date-popup.component';
15✔
26
import { ThyDateChangeEvent, ThyPanelMode } from './standard-types';
27
import { CompatibleValue } from './inner-types';
28
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
15!
29

15✔
30
/**
31
 * @private
15✔
32
 */
33
@Directive()
34
export abstract class PickerDirective extends AbstractPickerComponent implements OnInit, AfterViewInit, OnDestroy, OnChanges {
33✔
35
    showWeek = false;
36

37
    @Input() thyDateRender: FunctionProp<TemplateRef<Date> | string>;
60!
38

60✔
39
    panelMode: ThyPanelMode | ThyPanelMode[];
60✔
40

29!
41
    /**
42
     * @type EventEmitter<ThyPanelMode | ThyPanelMode[]>
43
     */
31✔
44
    @Output() readonly thyOnPanelChange = new EventEmitter<ThyPanelMode | ThyPanelMode[]>();
45

60✔
46
    /**
47
     * @type EventEmitter<Date[]>
48
     */
27✔
49
    @Output() readonly thyOnCalendarChange = new EventEmitter<Date[]>();
27✔
50

51
    private _showTime: object | boolean;
52
    @Input() get thyShowTime(): object | boolean {
53
        return this._showTime;
54
    }
55
    set thyShowTime(value: object | boolean) {
56
        this._showTime = typeof value === 'object' ? value : coerceBooleanProperty(value);
57
    }
58

59
    /**
60
     * 是否展示时间(时、分)
61
     * @default false
62
     */
63
    @Input({ transform: coerceBooleanProperty }) thyMustShowTime = false;
64

65
    /**
66
     * 弹出位置
67
     * @type top | topLeft | topRight | bottom | bottomLeft | bottomRight | left | leftTop | leftBottom | right | rightTop | rightBottom
68
     */
69
    @Input() thyPlacement: ThyPlacement = 'bottom';
70

71
    private offset = 4;
72

73
    /**
74
     * 弹出 DatePicker 的偏移量
75
     * @default 4
76
     */
77
    @Input({ transform: numberAttribute })
78
    set thyOffset(value: number) {
79
        if (typeof ngDevMode === 'undefined' || ngDevMode) {
27!
80
            warnDeprecation(`thyOffset parameter will be deprecated, please use thyPopoverOptions instead.`);
27✔
81
        }
27✔
82
        this.offset = value;
27✔
83
    }
15✔
84

10✔
85
    private hasBackdrop = true;
86

27✔
87
    /**
UNCOV
88
     * 是否有幕布
×
89
     * @default true
90
     */
27✔
91
    @Input({ transform: coerceBooleanProperty })
27✔
92
    set thyHasBackdrop(value: boolean) {
9✔
93
        if (typeof ngDevMode === 'undefined' || ngDevMode) {
94
            warnDeprecation(`thyHasBackdrop parameter will be deprecated, please use thyPopoverOptions instead.`);
27✔
95
        }
96
        this.hasBackdrop = value;
97
    }
15✔
98

27✔
99
    /**
100
     * popover 的其它参数
101
     */
7✔
102
    @Input() thyPopoverOptions: ThyPopoverConfig;
103

104
    /**
105
     * 是否阻止冒泡
9✔
106
     */
107
    @Input({ transform: coerceBooleanProperty }) thyStopPropagation = true;
108

33✔
109
    private destroy$ = new Subject<void>();
27!
110
    private el: HTMLElement = this.elementRef.nativeElement;
27✔
111
    readonly $click: Observable<boolean> = fromEvent(this.el, 'click').pipe(
112
        tap(e => {
113
            if (this.thyStopPropagation) {
114
                e.stopPropagation();
115
            }
34✔
116
        }),
34✔
117
        mapTo(true)
34✔
118
    );
34✔
119

34✔
120
    takeUntilDestroyed = takeUntilDestroyed();
34✔
121

34✔
122
    ngOnInit() {
34✔
123
        this.getInitialState();
34✔
124
    }
34✔
125

34✔
126
    private getInitialState() {
34✔
127
        this.thyMode = this.thyMode || 'date';
34✔
128
        this.flexible = this.thyMode === 'flexible';
34✔
129

34✔
130
        if (this.isRange) {
29✔
131
            this.panelMode = this.flexible ? ['date', 'date'] : [this.thyMode, this.thyMode];
28✔
132
        } else {
133
            this.panelMode = this.thyMode;
134
        }
34✔
135
        this.showWeek = this.thyMode === 'week';
136
    }
137

33✔
138
    private openOverlay(): void {
33✔
139
        this.getInitialState();
140
        const popoverRef = this.thyPopover.open(
141
            DatePopup,
34✔
142
            Object.assign(
34✔
143
                {
144
                    origin: this.el,
145
                    hasBackdrop: this.hasBackdrop,
9✔
146
                    backdropClass: 'thy-overlay-transparent-backdrop',
9✔
147
                    offset: this.offset,
9!
148
                    outsideClosable: true,
9✔
149
                    initialState: {
150
                        isRange: this.isRange,
151
                        panelMode: this.panelMode,
152
                        showWeek: this.showWeek,
153
                        value: this.thyValue,
33✔
154
                        showTime: this.thyShowTime,
155
                        mustShowTime: this.withTime,
156
                        format: this.thyFormat,
157
                        dateRender: this.thyDateRender,
9!
UNCOV
158
                        disabledDate: this.thyDisabledDate,
×
159
                        placeholder: this.thyPlaceHolder,
160
                        className: this.thyPanelClassName,
161
                        defaultPickerValue: this.thyDefaultPickerValue,
UNCOV
162
                        minDate: this.thyMinDate,
×
163
                        maxDate: this.thyMaxDate,
164
                        showShortcut: this.thyShowShortcut,
1✔
165
                        shortcutPresets: this.shortcutPresets,
166
                        shortcutPosition: this.shortcutPosition,
167
                        flexible: this.flexible,
168
                        flexibleDateGranularity: this.flexibleDateGranularity,
169
                        timestampPrecision: this.thyTimestampPrecision
1✔
170
                    },
171
                    placement: this.thyPlacement
172
                },
173
                this.thyPopoverOptions
174
            )
175
        );
176
        if (popoverRef) {
177
            const componentInstance = popoverRef.componentInstance;
178
            componentInstance.valueChange.pipe(takeUntil(this.destroy$)).subscribe((event: CompatibleValue) => this.onValueChange(event));
179
            componentInstance.calendarChange.pipe(takeUntil(this.destroy$)).subscribe((event: CompatibleValue) => {
180
                const rangeValue = coerceArray(event).map(x => x.nativeDate);
181
                this.thyOnCalendarChange.emit(rangeValue);
182
            });
1✔
183
            componentInstance.showTimePickerChange
184
                .pipe(takeUntil(this.destroy$))
185
                .subscribe((event: boolean) => this.onShowTimePickerChange(event));
186
            // eslint-disable-next-line max-len
187
            componentInstance.ngOnChanges({ value: {} as SimpleChange }); // dynamically created components don't call ngOnChanges, manual call
188
            componentInstance.dateValueChange?.pipe(this.takeUntilDestroyed).subscribe((event: ThyDateChangeEvent) => {
189
                this.thyDateChange.emit(event);
190
            });
191
            popoverRef
192
                .afterOpened()
193
                .pipe(takeUntil(this.destroy$))
194
                .subscribe(() => this.thyOpenChange.emit(true));
195
            popoverRef
196
                .afterClosed()
197
                .pipe(takeUntil(this.destroy$))
198
                .subscribe(() => this.thyOpenChange.emit(false));
199
        }
200
    }
201

202
    closeOverlay(): void {
203
        this.thyPopover.close();
204
    }
205

206
    initActionSubscribe(): void {
207
        this.$click.pipe(debounceTime(50), takeUntil(this.destroy$)).subscribe(() => {
208
            if (!this.thyDisabled && !this.thyReadonly) {
209
                this.openOverlay();
210
            }
211
        });
212
    }
213

214
    constructor(public elementRef: ElementRef, public cdr: ChangeDetectorRef, private thyPopover: ThyPopover) {
215
        super(cdr);
216
    }
217

218
    ngAfterViewInit(): void {
219
        this.setDefaultTimePickerState();
220
        this.initActionSubscribe();
221
    }
222

223
    ngOnDestroy(): void {
224
        this.destroy$.next();
225
        this.destroy$.complete();
226
    }
227

228
    onValueChange(value: CompatibleValue): void {
229
        this.restoreTimePickerState(value);
230
        super.onValueChange(value);
231
        if (!this.flexible) {
232
            this.closeOverlay();
233
        }
234
    }
235

236
    // Displays the time directly when the time must be displayed by default
237
    setDefaultTimePickerState() {
238
        this.withTime = this.thyMustShowTime;
239
    }
240

241
    // Restore after clearing time to select whether the original picker time is displayed or not
242
    restoreTimePickerState(value: CompatibleValue | null) {
243
        if (!value) {
244
            this.withTime = this.thyMustShowTime || this.originWithTime;
245
        }
246
    }
247
    onShowTimePickerChange(show: boolean): void {
248
        this.withTime = show;
249
    }
250
}
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