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

atinc / ngx-tethys / c9d10b12-973e-4ba4-b197-e38769ff9e9c

11 Dec 2023 07:01AM UTC coverage: 90.189% (-0.2%) from 90.364%
c9d10b12-973e-4ba4-b197-e38769ff9e9c

Pull #2967

circleci

mengshuicmq
fix(datePicker): remove note
Pull Request #2967: feat(datePicker): date-picker support quarter(#INFR-10719)

5362 of 6614 branches covered (0.0%)

Branch coverage included in aggregate %.

60 of 83 new or added lines in 7 files covered. (72.29%)

18 existing lines in 4 files now uncovered.

13382 of 14169 relevant lines covered (94.45%)

968.07 hits per line

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

89.93
/src/date-picker/base-picker.component.ts
1
import { InputBoolean, ThyPlacement } from 'ngx-tethys/core';
2
import { coerceBooleanProperty, elementMatchClosest, FunctionProp, P, TinyDate } from 'ngx-tethys/util';
3

4
import {
5
    ChangeDetectorRef,
6
    Component,
7
    ElementRef,
8
    EventEmitter,
9
    Input,
10
    OnChanges,
11
    OnInit,
1✔
12
    Output,
13
    TemplateRef,
148✔
14
    ViewChild
148✔
15
} from '@angular/core';
5✔
16

17
import { AbstractPickerComponent } from './abstract-picker.component';
18
import { CompatibleValue, RangeAdvancedValue } from './inner-types';
19
import { CompatibleDate, ThyPanelMode } from './standard-types';
777✔
20
import { ThyPickerComponent } from './picker.component';
21
import { hasTimeInStringDate, isValidStringDate, parseStringDate, transformDateValue } from './picker.util';
22

496✔
23
/**
24
 * @private
25
 */
63!
26
@Component({
27
    template: ``,
28
    standalone: true,
149✔
29
    host: {
149✔
30
        '[attr.tabindex]': `tabIndex`,
149✔
31
        '(focus)': 'onFocus($event)',
149✔
32
        '(blur)': 'onBlur($event)'
149✔
33
    }
149✔
34
})
149✔
35
export class BasePickerComponent extends AbstractPickerComponent implements OnInit, OnChanges {
149✔
36
    showWeek = false;
37

38
    panelMode: ThyPanelMode | ThyPanelMode[];
149✔
39

149✔
40
    initialized: boolean;
149✔
41

42
    private innerPreviousDate: string;
43

49✔
44
    @ViewChild('thyPicker', { static: true }) thyPicker: ThyPickerComponent;
49✔
45

49✔
46
    @Input() thyDateRender: FunctionProp<TemplateRef<Date> | string>;
49✔
47

41✔
48
    @Input() set thyMode(value: ThyPanelMode) {
49
        this._panelMode = value ?? 'date';
49✔
50
        if (this.initialized) {
51
            this.setDefaultTimePickerState(this._panelMode);
52
        }
14✔
53
    }
6✔
54

6✔
55
    get thyMode() {
6✔
56
        return this._panelMode;
6✔
57
    }
58

8✔
59
    /**
8✔
60
     * @type EventEmitter<ThyPanelMode | ThyPanelMode[]>
8!
61
     */
8✔
62
    @Output() readonly thyOnPanelChange = new EventEmitter<ThyPanelMode | ThyPanelMode[]>();
5✔
63

64
    /**
65
     * @type EventEmitter<Date[]>
3✔
66
     */
67
    @Output() readonly thyOnCalendarChange = new EventEmitter<Date[]>();
8✔
68

8✔
69
    private _showTime: object | boolean;
8✔
70

71
    /**
72
     * 增加时间选择功能
73
     * @default false
154✔
74
     */
154✔
75
    @Input() get thyShowTime(): object | boolean {
58✔
76
        return this._showTime;
77
    }
78
    set thyShowTime(value: object | boolean) {
96✔
79
        this._showTime = typeof value === 'object' ? value : coerceBooleanProperty(value);
80
    }
154✔
81

154✔
82
    /**
118✔
83
     * 是否展示时间(时、分)
84
     * @default false
85
     */
86
    @Input() @InputBoolean() thyMustShowTime = false;
87

118✔
88
    /**
89
     * 弹出位置
118✔
90
     * @type top | topLeft | topRight | bottom | bottomLeft | bottomRight | left | leftTop | leftBottom | right | rightTop | rightBottom
91
     */
92
    @Input() thyPlacement: ThyPlacement = 'bottomLeft';
93

94
    /**
63✔
95
     * @type EventEmitter<CompatibleDate | null>
10✔
96
     */
97
    @Output() readonly thyOnOk = new EventEmitter<CompatibleDate | null>();
98

99
    constructor(cdr: ChangeDetectorRef, protected element: ElementRef) {
100
        super(cdr);
10!
101
    }
15✔
102

10✔
103
    ngOnInit(): void {
104
        super.ngOnInit();
105
        this.setDefaultTimePickerState(this._panelMode);
106
        this.initialized = true;
62✔
107
    }
108

109
    onValueChange(value: CompatibleValue | RangeAdvancedValue): void {
5!
110
        this.thyPicker.entering = false;
×
111
        this.restoreTimePickerState(value as CompatibleValue);
×
UNCOV
112
        super.onValueChange(value);
×
113
        if (!this.flexible) {
114
            this.closeOverlay();
UNCOV
115
        }
×
116
        this.innerPreviousDate = this.thyPicker.getReadableValue(this.thyValue);
117
    }
118

119
    onInputValueChange(formatDate: string | null | Array<null>) {
5!
120
        if (!formatDate || !formatDate.length) {
5✔
121
            const compatibleValue = formatDate ? (formatDate as CompatibleValue) : null;
122
            this.restoreTimePickerState(compatibleValue);
UNCOV
123
            super.onValueChange(compatibleValue);
×
124
            return;
125
        }
126
        let value = formatDate as string;
5✔
127
        const valueValid = isValidStringDate(value);
128
        const valueLimitValid = valueValid ? this.isValidDateLimit(parseStringDate(value)) : false;
129
        if (valueValid && valueLimitValid) {
173✔
130
            this.innerPreviousDate = value;
173✔
131
        } else {
55✔
132
            value = this.innerPreviousDate;
133
        }
134
        const tinyDate = value ? (this.thyShowTime ? parseStringDate(value) : parseStringDate(value).startOfDay()) : null;
135
        this.restoreTimePickerState(tinyDate);
1✔
136
        super.onValueChange(tinyDate);
137
    }
138

139
    // Displays the time directly when the time must be displayed by default
5✔
140
    setDefaultTimePickerState(value: ThyPanelMode) {
1✔
141
        this.withTime = this.thyMustShowTime;
142
        if (this.isRange) {
4✔
143
            this.panelMode = this.flexible ? ['date', 'date'] : [value, value];
144
        } else {
145
            this.panelMode = value;
13!
146
        }
13✔
147
        this.showWeek = value === 'week';
4✔
148
        if (!this.thyFormat) {
149
            const inputFormats: { [key in ThyPanelMode]?: string } = {
13✔
150
                year: 'yyyy',
151
                quarter: 'yyyy年qqq',
152
                month: 'yyyy-MM',
153
                week: 'yyyy-ww周',
8✔
154
                date: this.thyShowTime ? 'yyyy-MM-dd HH:mm' : 'yyyy-MM-dd'
8!
155
            };
×
156
            this.thyFormat = this.flexible ? inputFormats['date'] : inputFormats[value];
157
        }
8✔
158
    }
8✔
159

8✔
160
    // Restore after clearing time to select whether the original picker time is displayed or not
161
    restoreTimePickerState(value: CompatibleValue | null) {
162
        if (!value) {
163
            this.withTime = this.thyMustShowTime || this.originWithTime;
1✔
164
        }
165
    }
166

167
    // Emit thyOnCalendarChange when select date by thy-range-picker
1✔
168
    onCalendarChange(value: TinyDate[]): void {
169
        if (this.isRange) {
170
            const rangeValue = value.map(x => x.nativeDate);
171
            this.thyOnCalendarChange.emit(rangeValue);
172
        }
173
    }
174

175
    onShowTimePickerChange(show: boolean): void {
176
        this.withTime = show;
177
    }
178

179
    onResultOk(): void {
1✔
180
        if (this.isRange) {
181
            const value = this.thyValue as TinyDate[];
182
            if (value.length) {
183
                this.thyOnOk.emit([value[0].nativeDate, value[1].nativeDate]);
1✔
184
            } else {
185
                this.thyOnOk.emit([]);
186
            }
187
        } else {
188
            if (this.thyValue) {
189
                this.thyOnOk.emit((this.thyValue as TinyDate).nativeDate);
190
            } else {
191
                this.thyOnOk.emit(null);
192
            }
193
        }
194
        this.closeOverlay();
195
    }
196

197
    onOpenChange(open: boolean): void {
198
        this.thyOpenChange.emit(open);
199
        if (!open) {
200
            this.onTouchedFn();
201
        }
202
    }
203

204
    onFocus(event: Event) {
205
        this.picker.focus();
206
    }
207

208
    onBlur(event?: FocusEvent) {
209
        // Tab 聚焦后自动聚焦到 input 输入框,此分支下直接返回,无需触发 onTouchedFn
210
        if (elementMatchClosest(event?.relatedTarget as HTMLElement, ['date-popup', 'thy-picker'])) {
211
            return;
212
        }
213
        this.onTouchedFn();
214
    }
215

216
    onInputDate(value: string) {
217
        if (value && isValidStringDate(value)) {
218
            if (this.thyShowTime) {
219
                this.withTime = hasTimeInStringDate(value);
220
            }
221
            this.thyValue = parseStringDate(value);
222
        }
223
    }
224

225
    private isValidDateLimit(date: TinyDate): boolean {
226
        let disable = false;
227
        if (this.thyDisabledDate !== undefined) {
228
            disable = this.thyDisabledDate(date.nativeDate);
229
        }
230
        const minDate = this.thyMinDate ? new TinyDate(transformDateValue(this.thyMinDate).value as Date) : null;
231
        const maxDate = this.thyMaxDate ? new TinyDate(transformDateValue(this.thyMaxDate).value as Date) : null;
232
        return (
233
            (!minDate || date.startOfDay().nativeDate >= minDate.startOfDay().nativeDate) &&
234
            (!maxDate || date.startOfDay().nativeDate <= maxDate.startOfDay().nativeDate) &&
235
            !disable
236
        );
237
    }
238
}
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