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

atinc / ngx-tethys / 09355d18-269d-4a6e-b476-9706aecd80e7

24 Dec 2024 02:27AM UTC coverage: 90.329% (-0.03%) from 90.356%
09355d18-269d-4a6e-b476-9706aecd80e7

Pull #3284

circleci

mengshuicmq
test(datePicker): add test
Pull Request #3284: fix(datePicker): #TINFR-1217 fix start time and end time when select…

5554 of 6800 branches covered (81.68%)

Branch coverage included in aggregate %.

8 of 8 new or added lines in 1 file covered. (100.0%)

11 existing lines in 2 files now uncovered.

13267 of 14036 relevant lines covered (94.52%)

992.14 hits per line

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

89.67
/src/date-picker/lib/popups/date-popup.component.ts
1
import { endOfDay, endOfISOWeek, endOfQuarter, endOfYear, startOfDay, startOfISOWeek, startOfQuarter, startOfYear } from 'date-fns';
2
import { FunctionProp, TinyDate, TinyDateCompareGrain, helpers, isFunction, isUndefinedOrNull, sortRangeValue } from 'ngx-tethys/util';
3

4
import {
5
    ChangeDetectionStrategy,
6
    ChangeDetectorRef,
7
    Component,
8
    EventEmitter,
9
    Input,
10
    OnChanges,
11
    OnInit,
12
    Output,
13
    SimpleChanges,
14
    TemplateRef,
15
    inject,
16
    Signal
17
} from '@angular/core';
18

19
import { NgTemplateOutlet } from '@angular/common';
1✔
20
import { FormsModule } from '@angular/forms';
21
import { ThyButtonIcon } from 'ngx-tethys/button';
150✔
22
import { ThyNav, ThyNavItemDirective } from 'ngx-tethys/nav';
150✔
23
import { ThyDatePickerConfigService } from '../../date-picker.service';
150✔
24
import { CompatibleValue, DatePickerFlexibleTab, RangeAdvancedValue, RangePartType } from '../../inner-types';
150✔
25
import { dateAddAmount, getShortcutValue, hasValue, makeValue, setValueByTimestampPrecision, transformDateValue } from '../../picker.util';
150✔
26
import {
150✔
27
    CompatibleDate,
150✔
28
    CompatiblePresets,
150✔
29
    DisabledDateFn,
150✔
30
    SupportTimeOptions,
150✔
31
    ThyDateChangeEvent,
150✔
32
    ThyDateGranularity,
150✔
33
    ThyPanelMode,
150✔
34
    ThyShortcutPosition,
150✔
35
    ThyShortcutPreset,
150✔
36
    ThyShortcutValue
150✔
37
} from '../../standard-types';
38
import { CalendarFooter } from '../calendar/calendar-footer.component';
39
import { DateCarousel } from '../date-carousel/date-carousel.component';
1✔
40
import { InnerPopup } from './inner-popup.component';
41
import { injectLocale, ThyDatePickerLocale } from 'ngx-tethys/i18n';
42

1✔
43
/**
1✔
44
 * @private
45
 */
46
@Component({
149✔
47
    changeDetection: ChangeDetectionStrategy.OnPush,
149✔
48
    // eslint-disable-next-line @angular-eslint/component-selector
149!
49
    selector: 'date-popup',
×
50
    exportAs: 'datePopup',
51
    templateUrl: './date-popup.component.html',
149!
52
    standalone: true,
×
53
    imports: [ThyNav, ThyNavItemDirective, ThyButtonIcon, DateCarousel, FormsModule, NgTemplateOutlet, InnerPopup, CalendarFooter]
×
54
})
55
export class DatePopup implements OnChanges, OnInit {
149✔
56
    private cdr = inject(ChangeDetectorRef);
149✔
57
    private datePickerConfigService = inject(ThyDatePickerConfigService);
149✔
58
    locale: Signal<ThyDatePickerLocale> = injectLocale('datePicker');
8✔
59

60
    @Input() isRange: boolean;
61
    @Input() showWeek: boolean;
62

63
    @Input() format: string;
64
    @Input() disabledDate: DisabledDateFn;
65
    @Input() minDate: Date | number;
66
    @Input() maxDate: Date | number;
307✔
67
    @Input() showToday: boolean;
149✔
68

59✔
69
    /**
70
     * 是否支持设置时间(时、分)
71
     */
90✔
72
    @Input() showTime: SupportTimeOptions | boolean;
73

74
    /**
307✔
75
     * 是否展示时间(时、分)
149✔
76
     */
77
    @Input() mustShowTime: boolean;
307✔
78

198✔
79
    @Input() dateRender: FunctionProp<TemplateRef<Date> | string>;
80
    @Input() className: string;
81
    @Input() panelMode: ThyPanelMode | ThyPanelMode[];
82
    @Input() value: CompatibleValue;
149✔
83
    @Input() defaultPickerValue: CompatibleDate | number;
149✔
84

414✔
85
    @Input() showShortcut: boolean;
86

87
    @Input() shortcutPresets: CompatiblePresets;
149✔
88

94✔
89
    @Input() shortcutPosition: ThyShortcutPosition;
91✔
90

91
    @Input() flexible: boolean;
94✔
92

94!
93
    @Input() flexibleDateGranularity: ThyDateGranularity;
94✔
94

94✔
95
    @Input() timestampPrecision: 'seconds' | 'milliseconds';
94✔
96

94✔
97
    @Output() readonly panelModeChange = new EventEmitter<ThyPanelMode | ThyPanelMode[]>();
94✔
98
    @Output() readonly calendarChange = new EventEmitter<CompatibleValue>();
30✔
99
    @Output() readonly valueChange = new EventEmitter<CompatibleValue | RangeAdvancedValue>();
114✔
100
    @Output() readonly resultOk = new EventEmitter<void>(); // Emitted when done with date selecting
114✔
101
    @Output() readonly showTimePickerChange = new EventEmitter<boolean>();
114✔
102
    @Output() readonly dateValueChange = new EventEmitter<ThyDateChangeEvent>();
114✔
103

114✔
104
    prefixCls = 'thy-calendar';
12✔
105
    showTimePicker = false;
106
    timeOptions: SupportTimeOptions | SupportTimeOptions[] | null;
107
    activeDate: TinyDate | TinyDate[];
102✔
108
    selectedValue: TinyDate[] = []; // Range ONLY
109
    hoverValue: TinyDate[] = []; // Range ONLY
110

111
    advancedSelectedValue: RangeAdvancedValue; // advanced ONLY
112

64✔
113
    flexibleActiveTab: DatePickerFlexibleTab = 'advanced';
133✔
114

133✔
115
    get hasTimePicker(): boolean {
133✔
116
        return !!this.showTime;
11✔
117
    }
118
    private partTypeMap: { [key: string]: number } = { left: 0, right: 1 };
119

122✔
120
    [property: string]: any;
121

122
    endPanelMode: ThyPanelMode | ThyPanelMode[];
123

124
    innerShortcutPresets: ThyShortcutPreset[];
125

126
    disableTimeConfirm = false;
127

497✔
128
    setProperty<T extends keyof DatePopup>(key: T, value: this[T]): void {
497✔
129
        this[key] = value;
142✔
130
        this.cdr.markForCheck();
142✔
131
    }
132

497✔
133
    ngOnInit(): void {
234✔
134
        this.initShortcutPresets();
196✔
135
        this.initPanelMode();
136
        if (this.flexible && this.flexibleDateGranularity === 'day') {
234✔
137
            this.flexibleActiveTab = 'custom';
138
        }
139
        if (this.defaultPickerValue && !hasValue(this.value)) {
263✔
140
            const { value } = transformDateValue(this.defaultPickerValue);
141
            this.value = makeValue(value, this.isRange);
497✔
142
        }
143
        this.updateActiveDate();
144
        this.initDisabledDate();
149!
145
        if (this.isRange && this.flexible && this.value) {
×
146
            this.advancedSelectedValue = {
×
147
                begin: this.value[0],
148
                end: this.value[1],
149
                dateGranularity: this.flexibleDateGranularity
×
150
            };
151
        }
152
    }
153

149✔
154
    ngOnChanges(changes: SimpleChanges): void {
59✔
155
        if (changes.panelMode) {
156
            if (helpers.isArray(this.panelMode)) {
157
                this.endPanelMode = [...this.panelMode];
90✔
158
            } else {
159
                this.endPanelMode = this.panelMode;
160
            }
161
        }
162
        if (changes.defaultPickerValue) {
163
            this.updateActiveDate();
164
        }
165
        if (changes.value && changes.value.currentValue) {
149✔
166
            this.updateActiveDate();
15✔
167
        }
15✔
168
    }
169

149✔
170
    initShortcutPresets(): void {
13✔
171
        const { shortcutRangesPresets, shortcutDatePresets, showShortcut } = this.datePickerConfigService;
13✔
172

173
        this.showShortcut =
149✔
174
            ['date', 'date,date'].includes(this.panelMode.toString()) && isUndefinedOrNull(this.showShortcut)
6✔
175
                ? showShortcut
176
                : this.showShortcut;
149✔
177

21,394✔
178
        if (this.showShortcut) {
21,394✔
179
            if (!this.shortcutPresets) {
2,310✔
180
                this.shortcutPresets = this.isRange ? shortcutRangesPresets : shortcutDatePresets;
181
            }
21,394✔
182

1,753✔
183
            this.innerShortcutPresets = isFunction(this.shortcutPresets) ? this.shortcutPresets() : this.shortcutPresets;
184
            if (this.innerShortcutPresets.length) {
21,394✔
185
                const minDate: TinyDate = this.getMinTinyDate();
630✔
186
                const maxDate: TinyDate = this.getMaxTinyDate();
187

21,394✔
188
                const minTime = minDate ? minDate.getTime() : null;
189
                const maxTime = maxDate ? maxDate.getTime() : null;
190

191
                if (this.isRange) {
66✔
192
                    this.innerShortcutPresets.forEach((preset: ThyShortcutPreset) => {
66✔
193
                        const begin: number | Date = getShortcutValue(preset.value[0]);
194
                        const beginTime: number = new TinyDate(startOfDay(begin)).getTime();
195

5✔
196
                        const end: number | Date = getShortcutValue(preset.value[1]);
5✔
197
                        const endTime: number = new TinyDate(endOfDay(end)).getTime();
5✔
198

199
                        if ((minDate && endTime < minTime) || (maxDate && beginTime > maxTime)) {
200
                            preset.disabled = true;
2!
201
                        } else {
2✔
202
                            preset.disabled = false;
203
                        }
204
                    });
1!
205
                } else {
206
                    this.innerShortcutPresets.forEach((preset: ThyShortcutPreset) => {
×
207
                        const singleValue: number | Date = getShortcutValue(preset.value as ThyShortcutValue);
×
208
                        const singleTime: number = new TinyDate(singleValue).getTime();
×
209

210
                        if ((minDate && singleTime < minTime) || (maxDate && singleTime > maxTime)) {
211
                            preset.disabled = true;
×
212
                        } else {
213
                            preset.disabled = false;
214
                        }
215
                    });
216
                }
14✔
217
            }
1✔
218
        }
219
    }
220

13✔
221
    updateActiveDate() {
222
        this.clearHoverValue();
14✔
223
        if (!this.value) {
224
            const { value } = transformDateValue(this.defaultPickerValue);
225
            this.value = makeValue(value, this.isRange);
42✔
226
        }
10✔
227
        if (this.isRange) {
10✔
228
            if (!this.flexible || this.flexibleDateGranularity === 'day') {
229
                this.selectedValue = this.value as TinyDate[];
230
            }
32✔
231
            this.activeDate = this.normalizeRangeValue(this.value as TinyDate[], this.getPanelMode(this.endPanelMode) as ThyPanelMode);
232
        } else {
233
            this.activeDate = this.value as TinyDate;
234
        }
28!
235
        this.isDisableTimeConfirm();
236
    }
237

238
    initPanelMode() {
28✔
239
        if (!this.endPanelMode) {
240
            if (helpers.isArray(this.panelMode)) {
241
                this.endPanelMode = [...this.panelMode];
242
            } else {
2✔
243
                this.endPanelMode = this.panelMode;
244
            }
245
        } else {
3✔
246
            if (helpers.isArray(this.endPanelMode)) {
3!
247
                this.panelMode = [...this.endPanelMode];
3✔
248
            } else {
249
                this.panelMode = this.endPanelMode;
250
            }
×
251
        }
252
    }
3✔
253

254
    initDisabledDate(): void {
255
        let minDate: TinyDate;
256
        let maxDate: TinyDate;
257
        let disabledDateFn: DisabledDateFn;
258
        if (this.minDate) {
259
            const { value } = transformDateValue(this.minDate);
5✔
260
            minDate = new TinyDate(value as Date);
261
        }
5✔
262
        if (this.maxDate) {
5✔
263
            const { value } = transformDateValue(this.maxDate);
264
            maxDate = new TinyDate(value as Date);
265
        }
266
        if (this.disabledDate) {
267
            disabledDateFn = this.disabledDate;
34✔
268
        }
269
        this.disabledDate = d => {
20✔
270
            let expression = false;
20✔
271
            if (minDate) {
20✔
272
                expression = d < minDate.startOfDay().nativeDate;
273
            }
10✔
274
            if (maxDate && !expression) {
10✔
275
                expression = d > maxDate.endOfDay().nativeDate;
10✔
276
            }
277
            if (disabledDateFn && typeof disabledDateFn === 'function' && !expression) {
10!
278
                expression = disabledDateFn(d);
279
            }
10✔
280
            return expression;
10✔
281
        };
10✔
282
    }
10✔
283

10✔
284
    onShowTimePickerChange(show: boolean): void {
10✔
285
        this.showTimePicker = show;
10✔
286
        this.showTimePickerChange.emit(show);
10✔
287
    }
288

289
    onClickOk(): void {
290
        this.setValue(this.value);
291
        this.valueChange.emit(this.value);
292
        this.resultOk.emit();
14✔
293
    }
14✔
294

14✔
295
    onClickRemove(): void {
296
        this.value = this.isRange ? [] : null;
297
        this.valueChange.emit(this.value);
298
    }
299

300
    onDayHover(value: TinyDate): void {
10✔
301
        if (this.isRange && this.selectedValue[0] && !this.selectedValue[1]) {
10!
UNCOV
302
            // When right value is selected, don't do hover
×
303
            const base = this.selectedValue[0]; // Use the left of selected value as the base to decide later hoverValue
304
            if (base.isBeforeDay(value)) {
10!
UNCOV
305
                this.hoverValue = [base, value];
×
306
            } else {
307
                this.hoverValue = [value, base];
10!
UNCOV
308
            }
×
309
        }
310
    }
311

10✔
312
    onPanelModeChange(mode: ThyPanelMode, partType?: RangePartType): void {
313
        if (this.isRange) {
314
            (this.panelMode as ThyPanelMode[])[this.getPartTypeIndex(partType)] = mode;
315
        } else {
25✔
316
            this.panelMode = mode;
12✔
317
        }
318
        this.panelModeChange.emit(this.panelMode);
13✔
319
    }
13✔
320

13✔
321
    onHeaderChange(value: TinyDate, partType?: RangePartType): void {
13✔
322
        if (this.isRange) {
13✔
323
            this.activeDate[this.getPartTypeIndex(partType)] = value;
10✔
324
            this.activeDate = this.normalizeRangeValue(
325
                this.activeDate as TinyDate[],
326
                this.getPanelMode(this.endPanelMode, partType) as ThyPanelMode
3✔
327
            );
328
        } else {
329
            this.activeDate = value;
330
        }
988!
UNCOV
331
    }
×
UNCOV
332

×
UNCOV
333
    onSelectTime(value: TinyDate, partType?: RangePartType): void {
×
UNCOV
334
        if (this.isRange) {
×
335
            // TODO:range picker set time
UNCOV
336
        } else {
×
337
            this.setValue(new TinyDate(value.nativeDate));
338
        }
339
    }
988✔
340

341
    selectTab(active: DatePickerFlexibleTab) {
342
        this.flexibleActiveTab = active;
343
    }
1,250✔
344

796✔
345
    clearFlexibleValue() {
346
        this.flexibleDateGranularity = null;
347
        if (this.flexibleActiveTab === 'advanced') {
454✔
348
            this.advancedSelectedValue = {};
349
        } else {
350
            this.selectedValue = [];
351
        }
493✔
352
        this.valueChange.emit({
266✔
353
            begin: null,
266✔
354
            end: null,
355
            dateGranularity: this.flexibleDateGranularity
356
        });
227✔
357
    }
358

359
    changeValueFromAdvancedSelect(value: RangeAdvancedValue) {
360
        this.valueChange.emit(value);
493✔
361
        // clear custom date when select a advanced date
266✔
362
        this.selectedValue = [];
363
        this.dateValueChange.emit({
364
            value: [value.begin, value.end]
227✔
365
        });
366
    }
367

365✔
368
    changeValueFromSelect(value: TinyDate, partType?: RangePartType): void {
1,349✔
369
        if (this.isRange) {
370
            // clear advanced date when select a custom date
371
            this.advancedSelectedValue = {};
215✔
372

373
            const [left, right] = this.selectedValue as TinyDate[];
374

215✔
375
            if ((!left && !right) || (left && right)) {
376
                // If totally full or empty, clean up && re-assign left first
377
                this.hoverValue = this.selectedValue = [value];
507✔
378
                this.selectedValue = [new TinyDate(startOfDay(this.selectedValue[0].nativeDate))];
379
                this.calendarChange.emit([this.selectedValue[0].clone()]);
380
            } else if (left && !right) {
78✔
381
                // If one of them is empty, assign the other one and sort, then set the final values
78✔
382
                this.clearHoverValue(); // Clean up
1✔
383
                this.setRangeValue('right', value);
1✔
384
                this.selectedValue = sortRangeValue(this.selectedValue); // Sort
385
                this.selectedValue = this.getSelectedRangeValueByMode(this.selectedValue);
386
                this.activeDate = this.normalizeRangeValue(
387
                    this.selectedValue,
388
                    this.getPanelMode(this.endPanelMode, partType) as ThyPanelMode
389
                );
390
                this.setValue(this.cloneRangeDate(this.selectedValue));
77✔
391
                this.calendarChange.emit(this.cloneRangeDate(this.selectedValue));
41✔
392
                this.dateValueChange.emit({
393
                    value: this.cloneRangeDate(this.selectedValue)
394
                });
78✔
395
            }
396
        } else {
×
397
            const updatedValue = this.updateHourMinute(value);
254✔
398
            this.setValue(updatedValue);
399
            this.dateValueChange.emit({
400
                value: updatedValue
401
            });
402
        }
403
    }
404

254✔
405
    private getSelectedRangeValueByMode(value: TinyDate[]): TinyDate[] {
254✔
406
        const panelMode = this.getPanelMode(this.endPanelMode);
254✔
407
        if (panelMode === 'year') {
254✔
408
            return [new TinyDate(startOfYear(value[0].nativeDate)), new TinyDate(endOfYear(value[1].nativeDate))];
254✔
409
        } else if (panelMode === 'quarter') {
202✔
410
            return [new TinyDate(startOfQuarter(value[0].nativeDate)), new TinyDate(endOfQuarter(value[1].nativeDate))];
411
        } else if (panelMode === 'week') {
254✔
412
            return [new TinyDate(startOfISOWeek(value[0].nativeDate)), new TinyDate(endOfISOWeek(value[1].nativeDate))];
413
        } else {
414
            return [new TinyDate(startOfDay(value[0].nativeDate)), new TinyDate(endOfDay(value[1].nativeDate))];
10✔
415
        }
10✔
416
    }
417

418
    private updateHourMinute(value: TinyDate): TinyDate {
50✔
419
        if (!this.value) {
420
            return value;
421
        }
575✔
422
        const originDate = this.value as TinyDate;
475✔
423
        const dateTime = [value.getHours(), value.getMinutes(), value.getSeconds()];
424
        const originDateTime = [originDate.getHours(), originDate.getMinutes(), originDate.getSeconds()];
100✔
425

100✔
426
        const isEqualTime = dateTime.toString() === originDateTime.toString();
100✔
427
        if (isEqualTime) {
100✔
428
            return value;
16✔
429
        } else {
430
            return value.setHms(originDateTime[0], originDateTime[1], originDateTime[2]);
431
        }
84✔
432
    }
433

434
    enablePrevNext(direction: 'prev' | 'next', partType?: RangePartType): boolean {
435
        if (this.isRange && this.panelMode === this.endPanelMode) {
21✔
436
            const [start, end] = this.activeDate as TinyDate[];
21✔
437
            const showMiddle = !start.addMonths(1).isSame(end, 'month'); // One month diff then don't show middle prev/next
21✔
438
            if ((partType === 'left' && direction === 'next') || (partType === 'right' && direction === 'prev')) {
21✔
439
                return showMiddle;
21✔
440
            }
10✔
441
            return true;
10✔
442
        } else {
10✔
443
            return true;
10✔
444
        }
10!
UNCOV
445
    }
×
446

447
    getPanelMode(panelMode: ThyPanelMode | ThyPanelMode[], partType?: RangePartType): ThyPanelMode {
10✔
448
        if (this.isRange) {
1✔
449
            return panelMode[this.getPartTypeIndex(partType)] as ThyPanelMode;
450
        } else {
9✔
451
            return panelMode as ThyPanelMode;
1✔
452
        }
453
    }
8✔
454

1✔
455
    getValueBySelector(partType?: RangePartType): TinyDate {
456
        if (this.isRange) {
7✔
457
            const valueShow = this.selectedValue; // Use the real time value that without decorations when timepicker is shown up
458
            return (valueShow as TinyDate[])[this.getPartTypeIndex(partType)];
459
        } else {
11✔
460
            return this.value as TinyDate;
11!
UNCOV
461
        }
×
462
    }
463

11✔
464
    getActiveDate(partType?: RangePartType): TinyDate {
465
        if (this.isRange) {
466
            return this.activeDate[this.getPartTypeIndex(partType)];
467
        } else {
24✔
468
            return this.activeDate as TinyDate;
2✔
469
        }
470
    }
22✔
471

22✔
472
    getPartTypeIndex(partType: RangePartType = 'left'): number {
1✔
473
        return this.partTypeMap[partType];
474
    }
475

21✔
476
    private getMinTinyDate() {
10✔
477
        return this.minDate ? new TinyDate(transformDateValue(this.minDate).value as Date) : null;
10✔
478
    }
10!
479

10✔
480
    private getMaxTinyDate() {
481
        return this.maxDate ? new TinyDate(transformDateValue(this.maxDate).value as Date) : null;
482
    }
483

10✔
484
    private clearHoverValue(): void {
485
        this.hoverValue = [];
486
    }
487

11✔
488
    private setValue(value: CompatibleValue): void {
11✔
489
        this.value = value;
11✔
490
        if (this.isRange && this.flexible) {
491
            this.flexibleDateGranularity = 'day';
21✔
492
            this.valueChange.emit({
21✔
493
                begin: value[0],
21✔
494
                end: value[1],
21✔
495
                dateGranularity: this.flexibleDateGranularity
496
            });
497
        } else {
21✔
498
            if (!this.showTime || !this.showTimePicker) {
1✔
499
                this.valueChange.emit(this.value);
500
            }
501
        }
1✔
502
        this.isDisableTimeConfirm();
503
    }
504

505
    private normalizeRangeValue(value: TinyDate[], mode: ThyPanelMode = 'month'): TinyDate[] {
506
        const headerModes: { [key in ThyPanelMode]?: ThyPanelMode } = {
507
            week: 'month',
508
            date: 'month',
509
            month: 'year',
510
            quarter: 'year',
511
            year: 'decade'
512
        };
513
        const headerMode = headerModes[mode];
514
        const [start, end] = value;
515
        const newStart = start || new TinyDate();
516
        let newEnd = end;
517
        if (!newEnd || newStart.isSame(end, headerMode as TinyDateCompareGrain)) {
518
            newEnd = dateAddAmount(newStart, 1, headerMode);
519
        }
520
        return [newStart, newEnd];
521
    }
522

523
    private setRangeValue(partType: RangePartType, value: TinyDate): void {
524
        const ref = (this.selectedValue = this.cloneRangeDate(this.selectedValue as TinyDate[]));
525
        ref[this.getPartTypeIndex(partType)] = value;
526
    }
527

528
    private cloneRangeDate(value: TinyDate[]): TinyDate[] {
529
        return [value[0] && value[0].clone(), value[1] && value[1].clone()] as TinyDate[];
530
    }
1✔
531

532
    private isDisableTimeConfirm() {
533
        if (this.isRange || !this.showTime) {
534
            return;
535
        }
536

537
        const date: TinyDate = this.value ? (this.value as TinyDate) : new TinyDate();
538
        const minDate: TinyDate = this.getMinTinyDate();
539
        const maxDate: TinyDate = this.getMaxTinyDate();
540

541
        if ((minDate && date.getTime() < minDate.getTime()) || (maxDate && date.getTime() > maxDate.getTime())) {
542
            this.disableTimeConfirm = true;
543
        } else {
544
            this.disableTimeConfirm = false;
545
        }
546
    }
547

548
    private getSelectedShortcutPreset(date: CompatibleValue): CompatibleValue {
549
        const minDate: TinyDate = this.getMinTinyDate();
550
        const maxDate: TinyDate = this.getMaxTinyDate();
551

552
        const minTime: number = (minDate && minDate.getTime()) || null;
553
        const maxTime: number = (maxDate && maxDate.getTime()) || null;
554

555
        if (helpers.isArray(date)) {
556
            const startDate: TinyDate = date[0];
557
            const endDate: TinyDate = date[1];
558

559
            const startTime: number = startDate.getTime();
560
            const endTime: number = endDate.getTime();
561

562
            if ((maxDate && startTime > maxTime) || (minDate && endTime < minTime)) {
563
                return [];
564
            }
565

566
            if (minDate && startTime < minTime && maxDate && endTime > maxTime) {
567
                return [minDate, maxDate];
568
            }
569

570
            if (minDate && startTime < minTime) {
571
                return [minDate, endDate];
572
            }
573

574
            if (maxDate && endTime > maxTime) {
575
                return [startDate, maxDate];
576
            }
577

578
            return date;
579
        } else {
580
            const singleTime: number = date.getTime();
581

582
            if ((minDate && singleTime < minTime) || (maxDate && singleTime > maxTime)) {
583
                return null;
584
            }
585

586
            return date;
587
        }
588
    }
589

590
    shortcutSetValue(shortcutPresets: ThyShortcutPreset) {
591
        if (shortcutPresets.disabled) {
592
            return;
593
        }
594

595
        const { value } = shortcutPresets;
596
        if (!value) {
597
            return;
598
        }
599

600
        let selectedPresetValue: CompatibleValue;
601
        if (helpers.isArray(value)) {
602
            const begin: number | Date = getShortcutValue(value[0]);
603
            const end: number | Date = getShortcutValue(value[1]);
604

605
            if (begin && end) {
606
                this.selectedValue = this.getSelectedShortcutPreset([
607
                    new TinyDate(startOfDay(begin)),
608
                    new TinyDate(endOfDay(end))
609
                ]) as TinyDate[];
610

611
                selectedPresetValue = this.cloneRangeDate(this.selectedValue);
612
            }
613
        } else {
614
            const singleDate: number | Date = getShortcutValue(value);
615
            const singleTinyDate: TinyDate = this.updateHourMinute(new TinyDate(singleDate));
616
            selectedPresetValue = this.getSelectedShortcutPreset(singleTinyDate) as TinyDate;
617
        }
618
        this.setValue(selectedPresetValue);
619
        const shortcutPresetsValue = setValueByTimestampPrecision(shortcutPresets?.value, this.isRange, this.timestampPrecision) as number;
620
        this.dateValueChange.emit({
621
            value: helpers.isArray(value) ? this.selectedValue : selectedPresetValue,
622
            triggerPreset: Object.assign({}, shortcutPresets, { value: shortcutPresetsValue })
623
        });
624
        if (!helpers.isArray(value) && this.showTime && this.showTimePicker) {
625
            this.updateActiveDate();
626
        }
627
    }
628
}
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