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

atinc / ngx-tethys / 10698a89-6a67-4df9-92de-a09375e9923d

12 Dec 2023 02:44AM UTC coverage: 90.216% (-0.2%) from 90.396%
10698a89-6a67-4df9-92de-a09375e9923d

Pull #2967

circleci

mengshuicmq
Merge branch 'cmq/feat-#INFR-10719' of https://github.com/atinc/ngx-tethys into cmq/feat-#INFR-10719
Pull Request #2967: feat(datePicker): date-picker support quarter(#INFR-10719)

5366 of 6616 branches covered (0.0%)

Branch coverage included in aggregate %.

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

19 existing lines in 5 files now uncovered.

13390 of 14174 relevant lines covered (94.47%)

968.26 hits per line

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

92.47
/src/date-picker/lib/popups/date-popup.component.ts
1
import { endOfDay, startOfDay } 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
} from '@angular/core';
16

17
import { NgFor, NgIf, NgTemplateOutlet } from '@angular/common';
18
import { FormsModule } from '@angular/forms';
1✔
19
import { ThyButtonIconComponent } from 'ngx-tethys/button';
20
import { ThyNavComponent, ThyNavItemDirective } from 'ngx-tethys/nav';
1✔
21
import { ThyDatePickerConfigService } from '../../date-picker.service';
22
import { CompatibleValue, DatePickerFlexibleTab, RangeAdvancedValue, RangePartType } from '../../inner-types';
23
import { dateAddAmount, getShortcutValue, hasValue, makeValue, transformDateValue } from '../../picker.util';
145✔
24
import {
145✔
25
    CompatibleDate,
145✔
26
    CompatiblePresets,
145✔
27
    DisabledDateFn,
145✔
28
    SupportTimeOptions,
145✔
29
    ThyDateChangeEvent,
145✔
30
    ThyDateGranularity,
145✔
31
    ThyPanelMode,
145✔
32
    ThyShortcutPosition,
145✔
33
    ThyShortcutPreset,
145✔
34
    ThyShortcutValue,
145✔
35
    ThyShortcutValueChange
145✔
36
} from '../../standard-types';
145✔
37
import { CalendarFooterComponent } from '../calendar/calendar-footer.component';
145✔
38
import { DateCarouselComponent } from '../date-carousel/date-carousel.component';
145✔
39
import { InnerPopupComponent } from './inner-popup.component';
40

41
/**
1✔
42
 * @private
1✔
43
 */
44
@Component({
45
    changeDetection: ChangeDetectionStrategy.OnPush,
144✔
46
    // eslint-disable-next-line @angular-eslint/component-selector
144✔
47
    selector: 'date-popup',
144!
48
    exportAs: 'datePopup',
×
49
    templateUrl: './date-popup.component.html',
50
    standalone: true,
144✔
51
    imports: [
1✔
52
        NgIf,
1✔
53
        NgFor,
54
        ThyNavComponent,
144✔
55
        ThyNavItemDirective,
144✔
56
        ThyButtonIconComponent,
144✔
57
        DateCarouselComponent,
8✔
58
        FormsModule,
59
        NgTemplateOutlet,
60
        InnerPopupComponent,
61
        CalendarFooterComponent
62
    ]
63
})
64
export class DatePopupComponent implements OnChanges, OnInit {
65
    @Input() isRange: boolean;
245✔
66
    @Input() showWeek: boolean;
123✔
67

48✔
68
    @Input() format: string;
69
    @Input() disabledDate: DisabledDateFn;
70
    @Input() minDate: Date | number;
75✔
71
    @Input() maxDate: Date | number;
72
    @Input() showToday: boolean;
73

245✔
74
    /**
123✔
75
     * 是否支持设置时间(时、分)
76
     */
245✔
77
    @Input() showTime: SupportTimeOptions | boolean;
152✔
78

79
    /**
80
     * 是否展示时间(时、分)
81
     */
144✔
82
    @Input() mustShowTime: boolean;
144✔
83

402✔
84
    @Input() dateRender: FunctionProp<TemplateRef<Date> | string>;
85
    @Input() className: string;
86
    @Input() panelMode: ThyPanelMode | ThyPanelMode[];
144✔
87
    @Input() value: CompatibleValue;
92✔
88
    @Input() defaultPickerValue: CompatibleDate | number;
87✔
89

90
    @Input() showShortcut: boolean;
92✔
91

92!
92
    @Input() shortcutPresets: CompatiblePresets;
92✔
93

92✔
94
    @Input() shortcutPosition: ThyShortcutPosition;
92✔
95

92✔
96
    @Input() flexible: boolean;
92✔
97

34✔
98
    @Input() flexibleDateGranularity: ThyDateGranularity;
124✔
99

124✔
100
    @Output() readonly panelModeChange = new EventEmitter<ThyPanelMode | ThyPanelMode[]>();
124✔
101
    @Output() readonly calendarChange = new EventEmitter<CompatibleValue>();
124✔
102
    @Output() readonly valueChange = new EventEmitter<CompatibleValue | RangeAdvancedValue>();
124✔
103
    @Output() readonly resultOk = new EventEmitter<void>(); // Emitted when done with date selecting
10✔
104
    @Output() readonly showTimePickerChange = new EventEmitter<boolean>();
105
    /**
106
     * @deprecated
114✔
107
     */
108
    @Output() readonly shortcutValueChange = new EventEmitter<ThyShortcutValueChange>();
109
    @Output() readonly dateValueChange = new EventEmitter<ThyDateChangeEvent>();
110

111
    prefixCls = 'thy-calendar';
58✔
112
    showTimePicker = false;
119✔
113
    timeOptions: SupportTimeOptions | SupportTimeOptions[] | null;
119✔
114
    activeDate: TinyDate | TinyDate[];
119✔
115
    selectedValue: TinyDate[] = []; // Range ONLY
11✔
116
    hoverValue: TinyDate[] = []; // Range ONLY
117

118
    advancedSelectedValue: RangeAdvancedValue; // advanced ONLY
108✔
119

120
    flexibleActiveTab: DatePickerFlexibleTab = 'advanced';
121

122
    get hasTimePicker(): boolean {
123
        return !!this.showTime;
124
    }
125
    private partTypeMap: { [key: string]: number } = { left: 0, right: 1 };
126

419✔
127
    [property: string]: any;
419✔
128

124✔
129
    endPanelMode: ThyPanelMode | ThyPanelMode[];
124✔
130

131
    innerShortcutPresets: ThyShortcutPreset[];
419✔
132

204✔
133
    disableTimeConfirm = false;
166✔
134

135
    constructor(private cdr: ChangeDetectorRef, private datePickerConfigService: ThyDatePickerConfigService) {}
204✔
136

137
    setProperty<T extends keyof DatePopupComponent>(key: T, value: this[T]): void {
138
        this[key] = value;
215✔
139
        this.cdr.markForCheck();
140
    }
419✔
141

142
    ngOnInit(): void {
143
        this.initShortcutPresets();
144✔
144
        this.initPanelMode();
21✔
145
        if (this.flexible && this.flexibleDateGranularity === 'day') {
13✔
146
            this.flexibleActiveTab = 'custom';
147
        }
148
        if (this.defaultPickerValue && !hasValue(this.value)) {
8✔
149
            const { value } = transformDateValue(this.defaultPickerValue);
150
            this.value = makeValue(value, this.isRange);
151
        }
152
        this.updateActiveDate();
123✔
153
        this.initDisabledDate();
48✔
154
        if (this.isRange && this.flexible && this.value) {
155
            this.advancedSelectedValue = {
156
                begin: this.value[0],
75✔
157
                end: this.value[1],
158
                dateGranularity: this.flexibleDateGranularity
159
            };
160
        }
161
    }
162

163
    ngOnChanges(changes: SimpleChanges): void {
164
        if (changes.panelMode) {
144✔
165
            if (helpers.isArray(this.panelMode)) {
15✔
166
                this.endPanelMode = [...this.panelMode];
15✔
167
            } else {
168
                this.endPanelMode = this.panelMode;
144✔
169
            }
13✔
170
        }
13✔
171
        if (changes.defaultPickerValue) {
172
            this.updateActiveDate();
144✔
173
        }
6✔
174
        if (changes.value && changes.value.currentValue) {
175
            this.updateActiveDate();
144✔
176
        }
19,736✔
177
    }
19,736✔
178

1,932✔
179
    initShortcutPresets(): void {
180
        const { shortcutRangesPresets, shortcutDatePresets, showShortcut } = this.datePickerConfigService;
19,736✔
181

1,581✔
182
        this.showShortcut =
183
            ['date', 'date,date'].includes(this.panelMode.toString()) && isUndefinedOrNull(this.showShortcut)
19,736✔
184
                ? showShortcut
630✔
185
                : this.showShortcut;
186

19,736✔
187
        if (this.showShortcut) {
188
            if (!this.shortcutPresets) {
189
                this.shortcutPresets = this.isRange ? shortcutRangesPresets : shortcutDatePresets;
190
            }
62✔
191

62✔
192
            this.innerShortcutPresets = isFunction(this.shortcutPresets) ? this.shortcutPresets() : this.shortcutPresets;
193
            if (this.innerShortcutPresets.length) {
194
                const minDate: TinyDate = this.getMinTinyDate();
5✔
195
                const maxDate: TinyDate = this.getMaxTinyDate();
5✔
196

5✔
197
                const minTime = minDate ? minDate.getTime() : null;
198
                const maxTime = maxDate ? maxDate.getTime() : null;
199

2!
200
                if (this.isRange) {
2✔
201
                    this.innerShortcutPresets.forEach((preset: ThyShortcutPreset) => {
202
                        const begin: number | Date = getShortcutValue(preset.value[0]);
203
                        const beginTime: number = new TinyDate(startOfDay(begin)).getTime();
1!
204

205
                        const end: number | Date = getShortcutValue(preset.value[1]);
×
206
                        const endTime: number = new TinyDate(endOfDay(end)).getTime();
×
207

×
208
                        if ((minDate && endTime < minTime) || (maxDate && beginTime > maxTime)) {
209
                            preset.disabled = true;
210
                        } else {
×
211
                            preset.disabled = false;
212
                        }
213
                    });
214
                } else {
215
                    this.innerShortcutPresets.forEach((preset: ThyShortcutPreset) => {
14✔
216
                        const singleValue: number | Date = getShortcutValue(preset.value as ThyShortcutValue);
1✔
217
                        const singleTime: number = new TinyDate(singleValue).getTime();
218

219
                        if ((minDate && singleTime < minTime) || (maxDate && singleTime > maxTime)) {
13✔
220
                            preset.disabled = true;
221
                        } else {
14✔
222
                            preset.disabled = false;
223
                        }
224
                    });
40✔
225
                }
10✔
226
            }
10✔
227
        }
228
    }
229

30✔
230
    updateActiveDate() {
231
        this.clearHoverValue();
232
        if (!this.value) {
233
            const { value } = transformDateValue(this.defaultPickerValue);
24!
234
            this.value = makeValue(value, this.isRange);
235
        }
236
        if (this.isRange) {
237
            if (!this.flexible || this.flexibleDateGranularity === 'day') {
24✔
238
                this.selectedValue = this.value as TinyDate[];
239
            }
240
            this.activeDate = this.normalizeRangeValue(this.value as TinyDate[], this.getPanelMode(this.endPanelMode) as ThyPanelMode);
241
        } else {
2✔
242
            this.activeDate = this.value as TinyDate;
243
        }
244
        this.isDisableTimeConfirm();
3✔
245
    }
3!
246

3✔
247
    initPanelMode() {
248
        if (!this.endPanelMode) {
249
            if (helpers.isArray(this.panelMode)) {
×
250
                this.endPanelMode = [...this.panelMode];
251
            } else {
3✔
252
                this.endPanelMode = this.panelMode;
253
            }
254
        } else {
255
            if (helpers.isArray(this.endPanelMode)) {
256
                this.panelMode = [...this.endPanelMode];
257
            } else {
258
                this.panelMode = this.endPanelMode;
5✔
259
            }
260
        }
5✔
261
    }
5✔
262

263
    initDisabledDate(): void {
264
        let minDate: TinyDate;
265
        let maxDate: TinyDate;
266
        let disabledDateFn: DisabledDateFn;
34✔
267
        if (this.minDate) {
268
            const { value } = transformDateValue(this.minDate);
20✔
269
            minDate = new TinyDate(value as Date);
20✔
270
        }
20✔
271
        if (this.maxDate) {
272
            const { value } = transformDateValue(this.maxDate);
10✔
273
            maxDate = new TinyDate(value as Date);
10✔
274
        }
10✔
275
        if (this.disabledDate) {
276
            disabledDateFn = this.disabledDate;
10!
277
        }
278
        this.disabledDate = d => {
10✔
279
            let expression = false;
10✔
280
            if (minDate) {
10✔
281
                expression = d < minDate.startOfDay().nativeDate;
10✔
282
            }
283
            if (maxDate && !expression) {
284
                expression = d > maxDate.endOfDay().nativeDate;
285
            }
10✔
286
            if (disabledDateFn && typeof disabledDateFn === 'function' && !expression) {
10✔
287
                expression = disabledDateFn(d);
10✔
288
            }
10✔
289
            return expression;
290
        };
291
    }
292

293
    onShowTimePickerChange(show: boolean): void {
294
        this.showTimePicker = show;
14✔
295
        this.showTimePickerChange.emit(show);
14✔
296
    }
14✔
297

298
    onClickOk(): void {
299
        this.setValue(this.value);
300
        this.valueChange.emit(this.value);
301
        this.resultOk.emit();
302
    }
21✔
303

9✔
304
    onClickRemove(): void {
305
        this.value = this.isRange ? [] : null;
12✔
306
        this.valueChange.emit(this.value);
12✔
307
    }
12✔
308

12✔
309
    onDayHover(value: TinyDate): void {
12✔
310
        if (this.isRange && this.selectedValue[0] && !this.selectedValue[1]) {
9✔
311
            // When right value is selected, don't do hover
312
            const base = this.selectedValue[0]; // Use the left of selected value as the base to decide later hoverValue
313
            if (base.isBeforeDay(value)) {
3✔
314
                this.hoverValue = [base, value];
315
            } else {
316
                this.hoverValue = [value, base];
317
            }
886!
318
        }
×
319
    }
×
320

×
321
    onPanelModeChange(mode: ThyPanelMode, partType?: RangePartType): void {
×
322
        if (this.isRange) {
323
            (this.panelMode as ThyPanelMode[])[this.getPartTypeIndex(partType)] = mode;
×
324
        } else {
325
            this.panelMode = mode;
326
        }
886✔
327
        this.panelModeChange.emit(this.panelMode);
328
    }
329

330
    onHeaderChange(value: TinyDate, partType?: RangePartType): void {
1,108✔
331
        if (this.isRange) {
724✔
332
            this.activeDate[this.getPartTypeIndex(partType)] = value;
333
            this.activeDate = this.normalizeRangeValue(
334
                this.activeDate as TinyDate[],
384✔
335
                this.getPanelMode(this.endPanelMode, partType) as ThyPanelMode
336
            );
337
        } else {
338
            this.activeDate = value;
442✔
339
        }
250✔
340
    }
250✔
341

342
    onSelectTime(value: TinyDate, partType?: RangePartType): void {
343
        if (this.isRange) {
192✔
344
            // TODO:range picker set time
345
        } else {
346
            this.setValue(new TinyDate(value.nativeDate));
347
        }
442✔
348
    }
250✔
349

350
    selectTab(active: DatePickerFlexibleTab) {
351
        this.flexibleActiveTab = active;
192✔
352
    }
353

354
    clearFlexibleValue() {
325✔
355
        this.flexibleDateGranularity = null;
1,245✔
356
        if (this.flexibleActiveTab === 'advanced') {
357
            this.advancedSelectedValue = {};
358
        } else {
199✔
359
            this.selectedValue = [];
360
        }
361
        this.valueChange.emit({
199✔
362
            begin: null,
363
            end: null,
364
            dateGranularity: this.flexibleDateGranularity
429✔
365
        });
366
    }
367

73✔
368
    changeValueFromAdvancedSelect(value: RangeAdvancedValue) {
73✔
369
        this.valueChange.emit(value);
1✔
370
        // clear custom date when select a advanced date
1✔
371
        this.selectedValue = [];
372
        this.dateValueChange.emit({
373
            value: [value.begin, value.end]
374
        });
375
    }
376

377
    changeValueFromSelect(value: TinyDate, partType?: RangePartType): void {
72✔
378
        if (this.isRange) {
41✔
379
            // clear advanced date when select a custom date
380
            this.advancedSelectedValue = {};
381

73✔
382
            const [left, right] = this.selectedValue as TinyDate[];
383

×
384
            if ((!left && !right) || (left && right)) {
224✔
385
                // If totally full or empty, clean up && re-assign left first
386
                this.hoverValue = this.selectedValue = [value];
387
                this.selectedValue = [new TinyDate(startOfDay(this.selectedValue[0].nativeDate))];
388
                this.calendarChange.emit([this.selectedValue[0].clone()]);
389
            } else if (left && !right) {
390
                // If one of them is empty, assign the other one and sort, then set the final values
391
                this.clearHoverValue(); // Clean up
224✔
392
                this.setRangeValue('right', value);
224✔
393
                this.selectedValue = sortRangeValue(this.selectedValue); // Sort
224✔
394
                this.selectedValue = [
224✔
395
                    new TinyDate(startOfDay(this.selectedValue[0].nativeDate)),
224✔
396
                    new TinyDate(endOfDay(this.selectedValue[1].nativeDate))
186✔
397
                ];
398
                this.activeDate = this.normalizeRangeValue(
224✔
399
                    this.selectedValue,
400
                    this.getPanelMode(this.endPanelMode, partType) as ThyPanelMode
401
                );
10✔
402
                this.setValue(this.cloneRangeDate(this.selectedValue));
10✔
403
                this.calendarChange.emit(this.cloneRangeDate(this.selectedValue));
404
                this.dateValueChange.emit({
405
                    value: this.cloneRangeDate(this.selectedValue)
53✔
406
                });
407
            }
408
        } else {
492✔
409
            const updatedValue = this.updateHourMinute(value);
405✔
410
            this.setValue(updatedValue);
411
            this.dateValueChange.emit({
87✔
412
                value: updatedValue
87✔
413
            });
87✔
414
        }
87✔
415
    }
16✔
416

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

20✔
425
        const isEqualTime = dateTime.toString() === originDateTime.toString();
20✔
426
        if (isEqualTime) {
20✔
427
            return value;
13✔
428
        } else {
13✔
429
            return value.setHms(originDateTime[0], originDateTime[1], originDateTime[2]);
13✔
430
        }
13✔
431
    }
13!
UNCOV
432

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

446
    getPanelMode(panelMode: ThyPanelMode | ThyPanelMode[], partType?: RangePartType): ThyPanelMode {
7✔
447
        if (this.isRange) {
7!
UNCOV
448
            return panelMode[this.getPartTypeIndex(partType)] as ThyPanelMode;
×
449
        } else {
450
            return panelMode as ThyPanelMode;
7✔
451
        }
452
    }
453

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

20✔
463
    getActiveDate(partType?: RangePartType): TinyDate {
13✔
464
        if (this.isRange) {
13✔
465
            return this.activeDate[this.getPartTypeIndex(partType)];
13!
466
        } else {
13✔
467
            return this.activeDate as TinyDate;
468
        }
469
    }
470

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

585
            return date;
586
        }
587
    }
588

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

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

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

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

610
                selectedPresetValue = this.cloneRangeDate(this.selectedValue);
611
            }
612
        } else {
613
            const singleDate: number | Date = getShortcutValue(value);
614
            const singleTinyDate: TinyDate = this.updateHourMinute(new TinyDate(singleDate));
615
            selectedPresetValue = this.getSelectedShortcutPreset(singleTinyDate) as TinyDate;
616
        }
617
        this.shortcutValueChange.emit({
618
            value: selectedPresetValue,
619
            triggerPresets: shortcutPresets
620
        });
621
        this.setValue(selectedPresetValue);
622
        this.dateValueChange.emit({
623
            value: helpers.isArray(value) ? this.selectedValue : selectedPresetValue,
624
            triggerPreset: shortcutPresets
625
        });
626
    }
627

628
    public trackByFn(index: number) {
629
        return index;
630
    }
631
}
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