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

atinc / ngx-tethys / 129e0fd3-b436-4e51-a99e-27a86ab79bed

14 Dec 2023 05:55AM UTC coverage: 90.399% (-0.009%) from 90.408%
129e0fd3-b436-4e51-a99e-27a86ab79bed

Pull #2969

circleci

luxiaobei
feat(property): property-item add thyEditingChange #INFR-10910
Pull Request #2969: feat(property): property-item add thyEditingChange #INFR-10910

5353 of 6582 branches covered (0.0%)

Branch coverage included in aggregate %.

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

20 existing lines in 5 files now uncovered.

13336 of 14092 relevant lines covered (94.64%)

972.82 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,
139✔
14
    ViewChild
139✔
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';
726✔
20
import { ThyPickerComponent } from './picker.component';
21
import { hasTimeInStringDate, isValidStringDate, parseStringDate, transformDateValue } from './picker.util';
22

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

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

140✔
40
    initialized: boolean;
140✔
41

42
    private innerPreviousDate: string;
43

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

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

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

5✔
55
    get thyMode() {
5✔
56
        return this._panelMode;
5✔
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
145✔
74
     */
145✔
75
    @Input() get thyShowTime(): object | boolean {
58✔
76
        return this._showTime;
77
    }
78
    set thyShowTime(value: object | boolean) {
87✔
79
        this._showTime = typeof value === 'object' ? value : coerceBooleanProperty(value);
80
    }
145✔
81

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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