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

atinc / ngx-tethys / 42cede8a-a636-4b81-b6eb-23535d958128

30 May 2024 08:41AM UTC coverage: 90.416% (-0.004%) from 90.42%
42cede8a-a636-4b81-b6eb-23535d958128

Pull #3099

circleci

xinglu01
fix(date-picker): add test
Pull Request #3099: fix(date-picker): handle range directive add timestampPrecision (#INFR-11707)

5467 of 6692 branches covered (81.69%)

Branch coverage included in aggregate %.

2 of 2 new or added lines in 2 files covered. (100.0%)

4 existing lines in 2 files now uncovered.

13212 of 13967 relevant lines covered (94.59%)

983.39 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,
26✔
17
    OnInit,
18
    Output,
19
    SimpleChange,
14!
20
    TemplateRef,
21
    booleanAttribute,
22
    numberAttribute
14!
23
} from '@angular/core';
14✔
24

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

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

58!
38
    @Input() thyDateRender: FunctionProp<TemplateRef<Date> | string>;
58✔
39

58✔
40
    panelMode: ThyPanelMode | ThyPanelMode[];
29!
41

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

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

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

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

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

72
    private offset = 4;
73

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

86
    private hasBackdrop = true;
26✔
87

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

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

105
    /**
8✔
106
     * 是否阻止冒泡
107
     */
108
    @Input({ transform: booleanAttribute }) thyStopPropagation = true;
32✔
109

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

33✔
121
    takeUntilDestroyed = takeUntilDestroyed();
33✔
122

33✔
123
    ngOnInit() {
33✔
124
        this.getInitialState();
33✔
125
    }
33✔
126

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

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

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

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

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

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

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

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

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

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

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