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

atinc / ngx-tethys / 5ba5b9d7-3ca9-4ff2-bbba-bde58c0f849f

22 Feb 2024 09:41AM UTC coverage: 90.604%. Remained the same
5ba5b9d7-3ca9-4ff2-bbba-bde58c0f849f

Pull #3027

circleci

minlovehua
feat(schematics): provide schematics for removing the suffix of standalone components #INFR-11662
Pull Request #3027: refactor: remove the component suffix for standalone components and provide schematics #INFR-10654

5425 of 6642 branches covered (81.68%)

Branch coverage included in aggregate %.

323 of 333 new or added lines in 193 files covered. (97.0%)

36 existing lines in 8 files now uncovered.

13504 of 14250 relevant lines covered (94.76%)

981.28 hits per line

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

83.23
/src/date-picker/abstract-picker.component.ts
1
import { InputBoolean, TabIndexDisabledControlValueAccessorMixin } from 'ngx-tethys/core';
2
import { coerceBooleanProperty, TinyDate, warnDeprecation } from 'ngx-tethys/util';
3
import { Subject } from 'rxjs';
4

5
import {
6
    ChangeDetectorRef,
7
    Directive,
8
    EventEmitter,
9
    Input,
10
    OnChanges,
11
    OnDestroy,
1✔
12
    OnInit,
13
    Output,
68✔
14
    SimpleChanges,
15
    ViewChild
16
} from '@angular/core';
263✔
17
import { ControlValueAccessor } from '@angular/forms';
18

19
import { CompatibleValue, RangeAdvancedValue } from './inner-types';
68!
20
import { ThyPicker } from './picker.component';
68✔
21
import { makeValue, transformDateValue } from './picker.util';
22
import {
23
    CompatibleDate,
24
    DateEntry,
68✔
25
    DisabledDateFn,
26
    ThyDateRangeEntry,
27
    ThyPanelMode,
3,017✔
28
    ThyShortcutPosition,
29
    CompatiblePresets,
30
    ThyShortcutValueChange,
341✔
31
    ThyDateGranularity,
32
    ThyDateChangeEvent
33
} from './standard-types';
13✔
34

35
/**
36
 * @private
695✔
37
 */
38
@Directive()
39
export abstract class AbstractPickerComponent
154✔
40
    extends TabIndexDisabledControlValueAccessorMixin
41
    implements OnInit, OnChanges, OnDestroy, ControlValueAccessor
42
{
187✔
43
    thyValue: CompatibleValue | null;
187✔
44

187✔
45
    _panelMode: ThyPanelMode = 'date';
187✔
46

187✔
47
    /**
187✔
48
     * 模式
187✔
49
     * @type decade | year | month | date | week | flexible
187✔
50
     */
187✔
51
    @Input() set thyMode(value: ThyPanelMode) {
187✔
52
        this._panelMode = value ?? 'date';
187✔
53
    }
187✔
54

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

187✔
59
    /**
187✔
60
     * 是否显示清除按钮
61
     */
62
    @Input() @InputBoolean() thyAllowClear = true;
154✔
63

154✔
64
    /**
154✔
65
     * 是否自动获取焦点
66
     * @default false
67
     */
154✔
68
    @Input() @InputBoolean() thyAutoFocus = false;
69

70
    @Input() @InputBoolean() thyOpen: boolean;
18✔
71

72
    @Input() thyDisabledDate: DisabledDateFn;
73

42✔
74
    /**
75
     * 最小值
76
     * @type Date | number
230✔
77
     */
37✔
78
    @Input() thyMinDate: Date | number;
79

80
    /**
81
     * 最大值
154✔
82
     * @type Date | number
154✔
83
     */
84
    @Input() thyMaxDate: Date | number;
85

47✔
86
    /**
87
     * 输入框提示文字
88
     * @type string | string[]
89
     */
×
90
    @Input() thyPlaceHolder: string | string[];
91

×
92
    /**
93
     * 是否只读
94
     * @default false
95
     */
×
96
    @Input() @InputBoolean() thyReadonly: boolean;
97

×
98
    /**
99
     * 选择器 className
100
     */
101
    @Input() thyOriginClassName: string;
×
102

103
    /**
×
104
     * 弹出层 className
105
     */
106
    @Input() thyPanelClassName: string;
107

×
108
    /**
109
     * 输入框的大小
×
110
     * @type xs | sm | md | lg | default
111
     */
112
    @Input() thySize: 'lg' | 'md' | 'sm' | 'xs' | 'default' = 'default';
113

×
114
    /**
115
     * 展示的日期格式
×
116
     * @default yyyy-MM-dd
117
     */
118
    @Input() thyFormat: string;
119

×
120
    /**
121
     * @description.en-us only for range picker, Whether to automatically take the beginning and ending unixTime of the day
×
122
     * @description.zh-cn 是否取值开始日期的00:00以及截止日期的24:00
123
     * @default false
124
     */
70✔
125
    @Input() @InputBoolean() thyAutoStartAndEnd = false;
70✔
126

70✔
127
    /**
70✔
128
     * 面板默认日期
70✔
129
     * @type CompatibleDate | number | null
31✔
130
     */
31✔
131
    @Input() thyDefaultPickerValue: CompatibleDate | number | null = null;
31✔
132

28✔
133
    /**
28!
134
     * 自定义的后缀图标
×
135
     */
136
    @Input() thySuffixIcon = 'calendar';
137

28✔
138
    /**
139
     * 是否展示快捷选项面板
140
     * @default false
141
     */
142
    @Input() @InputBoolean() thyShowShortcut: boolean;
143

31✔
144
    /**
8✔
145
     * 快捷选项面板的显示位置
146
     * @type left | bottom
31✔
147
     */
148
    @Input() set thyShortcutPosition(position: ThyShortcutPosition) {
149
        if (!!position) {
39✔
150
            this.shortcutPosition = position;
39✔
151
        }
29✔
152
    }
153

39✔
154
    /**
36✔
155
     * 自定义快捷选项
156
     * @type ThyShortcutPreset[]
157
     */
3✔
158
    @Input() set thyShortcutPresets(presets: CompatiblePresets) {
159
        this.shortcutPresets = presets;
160
    }
161

162
    /**
450✔
163
     * 已废弃,请使用 thyDateChange
70!
164
     * @deprecated please use thyDateChange
×
165
     */
166
    @Output() readonly thyShortcutValueChange = new EventEmitter<ThyShortcutValueChange>();
167

70!
168
    /**
×
169
     * 日期变化的回调
170
     */
171
    @Output() readonly thyDateChange = new EventEmitter<ThyDateChangeEvent>();
172

173
    @Output() readonly thyOpenChange = new EventEmitter<boolean>();
174

×
NEW
175
    @ViewChild(ThyPicker, { static: true }) public picker: ThyPicker;
×
176

177
    /**
178
     * 是否禁用
380✔
179
     * @default false
380✔
180
     */
380✔
181
    @Input()
3✔
182
    @InputBoolean()
2✔
183
    get thyDisabled(): boolean {
184
        return this.disabled;
185
    }
380✔
186
    set thyDisabled(value: boolean) {
380✔
187
        this.disabled = coerceBooleanProperty(value);
380✔
188
    }
380✔
189

380✔
190
    disabled = false;
380✔
191

192
    shortcutPosition: ThyShortcutPosition = 'left';
193

381✔
194
    shortcutPresets: CompatiblePresets;
195

196
    isRange: boolean;
182✔
197

182✔
198
    withTime: boolean;
199

200
    flexible: boolean;
154✔
201

117✔
202
    flexibleDateGranularity: ThyDateGranularity;
203

154✔
204
    protected destroyed$: Subject<void> = new Subject();
205
    protected isCustomPlaceHolder = false;
206
    private onlyEmitDate = false;
450✔
207
    protected originWithTime: boolean;
208

1✔
209
    get realOpenState(): boolean {
210
        return this.picker.realOpenState;
211
    }
1✔
212

213
    get isShowDatePopup(): boolean {
214
        return this.picker.isShowDatePopup;
215
    }
216

217
    initValue(): void {
218
        this.thyValue = this.isRange ? [] : null;
219
    }
220

221
    constructor(public cdr: ChangeDetectorRef) {
222
        super();
223
    }
224

225
    ngOnInit(): void {
226
        this.setDefaultPlaceHolder();
227
        this.initValue();
228
        this.isFlexible();
229
    }
230

231
    isFlexible() {
232
        this.flexible = this.thyMode === 'flexible';
233
    }
234

235
    onShortcutValueChange(event: ThyShortcutValueChange) {
236
        this.thyShortcutValueChange.emit(event);
237
    }
238

1✔
239
    onDateValueChange(event: ThyDateChangeEvent) {
240
        this.thyDateChange.emit(event);
241
    }
242

1✔
243
    ngOnChanges(changes: SimpleChanges): void {
244
        if (changes.thyPlaceHolder && changes.thyPlaceHolder.firstChange && typeof this.thyPlaceHolder !== 'undefined') {
245
            this.isCustomPlaceHolder = true;
246
        }
1✔
247
    }
248

249
    ngOnDestroy(): void {
250
        this.destroyed$.next();
1✔
251
        this.destroyed$.complete();
252
    }
253

254
    closeOverlay(): void {
1✔
255
        this.picker.hideOverlay();
256
    }
257

258
    getAutoStartAndEndValue(begin: TinyDate, end: TinyDate) {
1✔
259
        let value: { begin: number; end: number };
260
        switch (this.thyMode) {
261
            case 'date':
262
                value = {
1✔
263
                    begin: begin.startOfDay().getUnixTime(),
264
                    end: end.endOfDay().getUnixTime()
265
                };
266
                break;
267
            case 'week':
1✔
268
                value = {
269
                    begin: begin.startOfWeek().getUnixTime(),
270
                    end: end.endOfWeek().getUnixTime()
271
                };
272
                break;
273
            case 'month':
274
                value = {
275
                    begin: begin.startOfMonth().getUnixTime(),
276
                    end: end.endOfMonth().getUnixTime()
277
                };
278
                break;
279
            case 'year':
280
                value = {
281
                    begin: begin.startOfYear().getUnixTime(),
282
                    end: end.endOfYear().getUnixTime()
283
                };
284
                break;
285
            default:
286
                value = {
287
                    begin: begin.startOfDay().getUnixTime(),
288
                    end: end.endOfDay().getUnixTime()
289
                };
290
                break;
291
        }
292
        return value;
293
    }
294

295
    onValueChange(originalValue: CompatibleValue | RangeAdvancedValue): void {
296
        this.setFormatRule();
297
        const { value, withTime, flexibleDateGranularity } = transformDateValue(originalValue);
298
        this.flexibleDateGranularity = flexibleDateGranularity;
299
        this.setValue(value);
300
        if (this.isRange) {
301
            const vAsRange: any = this.thyValue;
302
            let value = { begin: null, end: null } as ThyDateRangeEntry;
303
            if (vAsRange.length) {
304
                const [begin, end] = vAsRange as TinyDate[];
305
                if (this.thyAutoStartAndEnd) {
306
                    value = this.getAutoStartAndEndValue(begin, end);
307
                } else {
308
                    value = {
309
                        begin: begin.getUnixTime(),
310
                        end: end.getUnixTime()
311
                    };
312
                }
313
            }
314
            if (this.flexible) {
315
                value.granularity = flexibleDateGranularity;
316
            }
317
            this.onChangeFn(value);
318
        } else {
319
            const value = { date: null, with_time: this.withTime ? 1 : 0 } as DateEntry;
320
            if (this.thyValue) {
321
                value.date = (this.thyValue as TinyDate).getUnixTime();
322
            }
323
            if (this.onlyEmitDate) {
324
                this.onChangeFn(value.date);
325
            } else {
326
                this.onChangeFn(value);
327
            }
328
        }
329
    }
330

331
    setFormatRule() {
332
        if (!this.thyFormat) {
333
            if (this.withTime) {
334
                this.thyFormat = 'yyyy-MM-dd HH:mm';
335
            } else {
336
                if (!this.onlyEmitDate) {
337
                    this.thyFormat = 'yyyy-MM-dd';
338
                }
339
            }
340
        }
341
    }
342

343
    onOpenChange(open: boolean): void {
344
        this.thyOpen = open;
345
        this.thyOpenChange.emit(open);
346
    }
347

348
    onChangeFn: (val: CompatibleDate | DateEntry | ThyDateRangeEntry | number | null) => void = () => void 0;
349

350
    writeValue(originalValue: CompatibleDate | ThyDateRangeEntry): void {
351
        const { value, withTime, flexibleDateGranularity } = transformDateValue(originalValue);
352
        this.flexibleDateGranularity = flexibleDateGranularity;
353
        if (this.flexible && value && (value as Date[]).length) {
354
            if (!this.flexibleDateGranularity) {
355
                this.flexibleDateGranularity = 'day';
356
            }
357
        }
358

359
        this.setValue(value);
360
        this.setTimePickerState(withTime);
361
        this.onlyEmitDate = typeof withTime === 'undefined';
362
        this.originWithTime = withTime;
363
        this.setFormatRule();
364
        this.cdr.markForCheck();
365
    }
366

367
    setTimePickerState(withTime: boolean): void {
368
        this.withTime = withTime;
369
    }
370

371
    setDisabledState(disabled: boolean): void {
372
        this.thyDisabled = disabled;
373
        this.cdr.markForCheck();
374
    }
375

376
    private setDefaultPlaceHolder(): void {
377
        if (!this.isCustomPlaceHolder) {
378
            this.thyPlaceHolder = this.isRange ? ['开始日期', '结束日期'] : '请选择日期';
379
        }
380
        this.cdr.markForCheck();
381
    }
382

383
    public setValue(value: CompatibleDate): void {
384
        this.thyValue = makeValue(value, this.isRange);
385
    }
386
}
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