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

atinc / ngx-tethys / d9ae709b-3c27-4b69-b125-b8b80b54f90b

pending completion
d9ae709b-3c27-4b69-b125-b8b80b54f90b

Pull #2757

circleci

mengshuicmq
fix: fix code review
Pull Request #2757: feat(color-picker): color-picker support disabled (#INFR-8645)

98 of 6315 branches covered (1.55%)

Branch coverage included in aggregate %.

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

2392 of 13661 relevant lines covered (17.51%)

83.12 hits per line

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

1.51
/src/date-picker/lib/date-carousel/date-carousel.component.ts
1
import { NgClass, NgFor, NgIf, NgTemplateOutlet } from '@angular/common';
2
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, HostBinding, Input, OnDestroy, OnInit } from '@angular/core';
3
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
4
import { ThyButtonComponent } from 'ngx-tethys/button';
5
import { ThyIconComponent } from 'ngx-tethys/icon';
6
import { TinyDate } from 'ngx-tethys/util';
7
import { Subject } from 'rxjs';
8
import { AdvancedSelectableCell, RangeAdvancedValue } from '../../inner-types';
9
import { DatePickerAdvancedShowYearTipPipe } from '../../picker.pipes';
10
import { ThyDateGranularity } from '../../standard-types';
11

12
/**
13
 * @private
14
 */
15
@Component({
1✔
16
    // eslint-disable-next-line @angular-eslint/component-selector
17
    selector: 'date-carousel',
×
18
    templateUrl: './date-carousel.component.html',
×
19
    changeDetection: ChangeDetectionStrategy.OnPush,
×
20
    providers: [
×
21
        {
×
22
            provide: NG_VALUE_ACCESSOR,
23
            multi: true,
24
            useExisting: forwardRef(() => DateCarouselComponent)
×
25
        }
26
    ],
×
27
    standalone: true,
28
    imports: [NgTemplateOutlet, ThyButtonComponent, ThyIconComponent, NgFor, NgClass, NgIf, DatePickerAdvancedShowYearTipPipe]
29
})
×
30
export class DateCarouselComponent implements OnInit, ControlValueAccessor, OnDestroy {
×
31
    @HostBinding('class') className = 'thy-date-picker-advanced-carousel';
×
32

×
33
    @Input() activeDate: TinyDate;
×
34

×
35
    set defaultValue(value: RangeAdvancedValue) {
36
        this.dateGranularity = value.dateGranularity;
37
        this.buildSelectableData(value.begin);
×
38

×
39
        if (value.begin && value.end) {
×
40
            const shouldBeSelectValue = this.getShouldBeToggleValue(value.begin, value.end);
41
            this.select(...shouldBeSelectValue);
×
42
        } else {
×
43
            this.clearSelect(true);
×
44
        }
×
45
        this.initialized = true;
×
46
    }
×
47

48
    selectableData: { year?: AdvancedSelectableCell[]; quarter?: AdvancedSelectableCell[]; month?: AdvancedSelectableCell[] } = {};
49

50
    dateGranularity: ThyDateGranularity;
51

52
    selectedValue: AdvancedSelectableCell[] = [];
53

×
54
    private initialized = false;
×
55

56
    private selectedValueChange$ = new Subject<RangeAdvancedValue>();
57

58
    private _onChange: (value: RangeAdvancedValue) => void;
59

60
    private _onTouched: (value: RangeAdvancedValue) => void;
61

62
    constructor(private cdr: ChangeDetectorRef) {}
63

64
    ngOnInit(): void {
×
65
        this.selectedValueChange$.subscribe(() => {
×
66
            if (this.selectedValue.length) {
67
                this.buildSelectableData(this.selectedValue[0]?.startValue, this.dateGranularity);
68
            }
69
            this.selectableData.year.forEach(item => (item.classMap = this.getClassMap(item)));
×
70
            this.selectableData.quarter.forEach(item => (item.classMap = this.getClassMap(item)));
71
            this.selectableData.month.forEach(item => (item.classMap = this.getClassMap(item)));
72
            if (this.initialized) {
×
73
                if (this.isSelectEmpty()) {
74
                    this._onChange({
75
                        dateGranularity: null,
×
76
                        begin: null,
77
                        end: null
78
                    });
79
                } else {
80
                    const selctedValue = this.selectedValue;
81
                    this._onChange({
82
                        dateGranularity: this.dateGranularity,
83
                        begin: selctedValue[0]?.startValue,
84
                        end: selctedValue[selctedValue.length - 1]?.endValue
×
85
                    });
86
                }
87
            }
×
88
        });
×
89
    }
90

91
    writeValue(value: RangeAdvancedValue): void {
×
92
        if (value) {
×
93
            this.defaultValue = value;
94
        }
95
    }
×
96

×
97
    registerOnChange(fn: any): void {
×
98
        this._onChange = fn;
99
    }
100

101
    registerOnTouched(fn: any): void {
102
        this._onTouched = fn;
×
103
    }
104

105
    getClassMap(cell: AdvancedSelectableCell) {
×
106
        return {
107
            [`active`]: this.isSelected(cell),
108
            [`indeterminate`]: this.isCellIndeterminate(this.selectedValue, cell),
×
109
            [`type-active`]: this.isTypeActive(this.selectedValue, cell),
110
            ['in-hover-range']: cell.isInRange,
111
            ['out-range']: cell.isOutRange
×
112
        };
×
113
    }
×
114

115
    isTypeActive(originalValue: AdvancedSelectableCell[], value: AdvancedSelectableCell) {
116
        return originalValue?.length && originalValue[0].type === value.type;
×
117
    }
×
118

119
    isCellIndeterminate(originalValue: AdvancedSelectableCell[], value: AdvancedSelectableCell) {
120
        if (originalValue[0]?.type === value.type) {
×
121
            return false;
×
122
        } else {
123
            if (originalValue[0]?.type === 'year') {
×
124
                return !!originalValue.find(item => item.startValue.isSameYear(value.startValue));
×
125
            } else {
126
                return value.type === 'year'
127
                    ? !!originalValue.find(item => item.startValue.isSameYear(value.startValue))
×
128
                    : !!originalValue.find(item => item.startValue.isSameQuarter(value.startValue));
×
129
            }
×
130
        }
131
    }
132

133
    isSelected(value: AdvancedSelectableCell) {
×
134
        return this.selectedValue.find(item => item.startValue.isSameDay(value.startValue)) && this.dateGranularity === value.type;
×
135
    }
136

×
137
    isSelectEmpty() {
×
138
        return this.selectedValue.length == 0;
×
139
    }
140

141
    selectSort() {
×
142
        this.selectedValue.sort((a, b) => a.startValue.getTime() - b.startValue.getTime());
×
143
    }
×
144

×
145
    select(...value: AdvancedSelectableCell[]) {
146
        value.forEach(item => {
147
            if (!this.isSelected(item)) {
×
148
                this.selectedValue.push(...value);
149
            }
×
150
        });
×
151
        this.selectSort();
×
152
        this.selectedValueChange$.next(undefined);
153
    }
154

×
155
    deselect(...value: AdvancedSelectableCell[]) {
×
156
        value.forEach(item => {
×
157
            this.selectedValue = this.selectedValue.filter(selected => !selected.startValue.isSameDay(item.startValue));
×
158
        });
159
        this.selectSort();
160
        this.selectedValueChange$.next(undefined);
×
161
    }
162

×
163
    clearSelect(hidden?: boolean) {
×
164
        this.selectedValue = [];
×
165
        if (!hidden) {
166
            this.selectedValueChange$.next(undefined);
167
        }
×
168
    }
×
169

×
170
    getShouldBeToggleValue(begin: TinyDate, end: TinyDate) {
×
171
        let selectedValue: AdvancedSelectableCell[] = [];
172
        switch (this.dateGranularity) {
173
            case 'year':
174
                this.dateGranularity = 'year';
×
175
                if (begin.isSameYear(end)) {
176
                    selectedValue.push(this.getSelectableYear(begin));
177
                } else {
×
178
                    selectedValue.push(this.getSelectableYear(begin));
×
179
                    while (!begin.isSameYear(end)) {
×
180
                        begin = begin.addYears(1);
181
                        selectedValue.push(this.getSelectableYear(begin));
×
182
                    }
×
183
                }
184
                break;
×
185
            case 'month':
186
                this.dateGranularity = 'month';
×
187
                if (begin.isSameMonth(end)) {
×
188
                    selectedValue.push(this.getSelectableMonth(begin));
189
                } else {
×
190
                    selectedValue.push(this.getSelectableMonth(begin));
191
                    while (!begin.isSameMonth(end)) {
×
192
                        begin = begin.addMonths(1);
×
193
                        selectedValue.push(this.getSelectableMonth(begin));
194
                    }
×
195
                }
196
                break;
197
            case 'quarter':
×
198
                this.dateGranularity = 'quarter';
199
                if (begin.isSameQuarter(end)) {
×
200
                    selectedValue.push(this.getSelectableQuarter(begin));
×
201
                } else {
×
202
                    selectedValue.push(this.getSelectableQuarter(begin));
203
                    while (!begin.isSameQuarter(end)) {
204
                        begin = begin.addQuarters(1);
205
                        selectedValue.push(this.getSelectableQuarter(begin));
206
                    }
207
                }
208
        }
209
        return selectedValue;
×
210
    }
×
211

×
212
    buildSelectableData(startDate: TinyDate, excludeGranularity?: ThyDateGranularity) {
213
        const buildGranularity = ['year', 'month', 'quarter'].filter(item => item !== excludeGranularity);
214
        buildGranularity.forEach(granularity => {
215
            switch (granularity) {
216
                case 'year':
217
                    this.selectableData.year = [...Array(3).keys()].map((item, index) => {
218
                        return this.getSelectableYear(startDate, index);
219
                    });
×
220
                    break;
×
221
                case 'quarter':
×
222
                    this.selectableData.quarter = [...Array(4).keys()].map((item, index) => {
223
                        return this.getSelectableQuarter(startDate, index);
224
                    });
225
                    break;
226
                case 'month':
227
                    this.selectableData.month = [...Array(4).keys()].map((item, index) => {
228
                        return this.getSelectableMonth(startDate, index);
×
229
                    });
230
                    break;
231
            }
×
232
        });
233
        this.cdr.markForCheck();
×
234
    }
×
235

236
    getSelectableYear(currentDate: TinyDate, preOrNextcount: number = 0): AdvancedSelectableCell {
×
237
        currentDate = currentDate || this.activeDate || new TinyDate().startOfYear();
×
238
        return {
239
            type: 'year',
×
240
            content: `${currentDate.addYears(preOrNextcount).getYear()}`,
241
            startValue: currentDate.startOfYear().addYears(preOrNextcount),
×
242
            endValue: currentDate.endOfYear().addYears(preOrNextcount),
243
            classMap: {}
244
        };
×
245
    }
246

×
247
    getSelectableQuarter(currentDate: TinyDate, preOrNextcount: number = 0): AdvancedSelectableCell {
×
248
        currentDate = currentDate || this.activeDate || new TinyDate().startOfQuarter();
249
        return {
×
250
            type: 'quarter',
×
251
            content: `Q${currentDate.addQuarters(preOrNextcount).getQuarter()}`,
252
            startValue: currentDate.startOfQuarter().addQuarters(preOrNextcount),
×
253
            endValue: currentDate.endOfQuarter().addQuarters(preOrNextcount),
254
            classMap: {}
×
255
        };
256
    }
257

×
258
    getSelectableMonth(currentDate: TinyDate, preOrNextcount: number = 0): AdvancedSelectableCell {
×
259
        currentDate = currentDate || this.activeDate || new TinyDate().startOfMonth();
×
260
        const cell: AdvancedSelectableCell = {
261
            type: 'month',
×
262
            content: `${currentDate.addMonths(preOrNextcount).getMonth() + 1}月`,
×
263
            startValue: currentDate.startOfMonth().addMonths(preOrNextcount),
×
264
            endValue: currentDate.endOfMonth().addMonths(preOrNextcount),
265
            classMap: {}
×
266
        };
267
        return cell;
×
268
    }
×
269

×
270
    prevClick(type: ThyDateGranularity) {
×
271
        switch (type) {
272
            case 'year':
×
273
                this.selectableData.year = this.selectableData.year.map(item => this.getSelectableYear(item.startValue, -1));
274
                break;
×
275
            case 'quarter':
×
276
                this.selectableData.quarter = this.selectableData.quarter.map(item => this.getSelectableQuarter(item.startValue, -2));
×
277
                break;
×
278
            case 'month':
279
                this.selectableData.month = this.selectableData.month.map(item => this.getSelectableMonth(item.startValue, -2));
280
        }
281
        this.selectableData[type].forEach(item => (item.classMap = this.getClassMap(item)));
×
282
    }
×
283

×
284
    nextClick(type: ThyDateGranularity) {
285
        switch (type) {
286
            case 'year':
287
                this.selectableData.year = this.selectableData.year.map(item => this.getSelectableYear(item.startValue, 1));
288
                break;
×
289
            case 'quarter':
290
                this.selectableData.quarter = this.selectableData.quarter.map(item => this.getSelectableQuarter(item.startValue, 2));
×
291
                break;
292
            case 'month':
293
                this.selectableData.month = this.selectableData.month.map(item => this.getSelectableMonth(item.startValue, 2));
294
        }
×
295
        this.selectableData[type].forEach(item => (item.classMap = this.getClassMap(item)));
×
296
    }
×
297

×
298
    selectDate(type: ThyDateGranularity, value: AdvancedSelectableCell) {
299
        this.selectableData[type].forEach(item => {
300
            item.isInRange = false;
301
            item.isOutRange = false;
×
302
        });
×
303

304
        if (this.isSelectEmpty()) {
×
305
            this.dateGranularity = type;
×
306
            this.select(value);
×
307
            // this.selectedValueChange$.next();
×
308
            return;
309
        }
310
        if (this.isSelected(value)) {
×
311
            this.toggleSelect(value);
×
312
            if (this.isSelectEmpty()) {
×
313
                this.dateGranularity = null;
×
314
            }
×
315
            return;
316
        }
317

×
318
        if (this.dateGranularity === value.type) {
319
            const { rangeStart, rangeEnd } = this.getActualStartAndEnd(value);
320
            const shouldBeSelectValue = this.getShouldBeToggleValue(rangeStart, rangeEnd);
321
            this.select(...shouldBeSelectValue);
322
            // this.selectedValueChange$.next();
323
        } else {
×
324
            this.dateGranularity = type;
×
325
            this.clearSelect(true);
×
326
            this.select(value);
×
327
            // this.selectedValueChange$.next();
328
        }
329
    }
×
330
    toggleSelect(value: AdvancedSelectableCell) {
331
        if (value.startValue.isSameDay(this.selectedValue[0].startValue)) {
332
            // only deselect first one
333
            this.deselect(value);
×
334
        } else {
335
            // deselect current and all after current
336
            const rangeStart = value.startValue;
×
337
            const rangeEnd = this.selectedValue[this.selectedValue.length - 1].endValue;
×
338
            const shouldBeDeselectValue = this.getShouldBeToggleValue(rangeStart, rangeEnd);
339
            this.deselect(...shouldBeDeselectValue);
×
340
        }
×
341
    }
342

×
343
    onMouseenter(event: Event, type: ThyDateGranularity, value: AdvancedSelectableCell) {
344
        if (this.isSelectEmpty() || this.dateGranularity !== type) {
345
            return;
×
346
        }
×
347
        if (this.isSelected(value)) {
348
            value.isInRange = true;
×
349
            if (value.startValue.isSameDay(this.selectedValue[0].startValue)) {
×
350
                value.isOutRange = true;
×
351
            } else {
352
                const rangeStart = value.startValue;
×
353
                const rangeEnd = this.selectedValue[this.selectedValue.length - 1].endValue;
×
354
                this.selectableData[type].forEach((item: AdvancedSelectableCell) => {
×
355
                    if (item.startValue.getTime() >= rangeStart.getTime() && item.startValue.getTime() < rangeEnd.getTime()) {
356
                        item.isOutRange = true;
×
357
                    } else {
358
                        item.isOutRange = false;
359
                    }
×
360
                });
361
            }
1✔
362
        } else {
363
            const { rangeStart, rangeEnd } = this.getActualStartAndEnd(value);
364
            this.selectableData[type].forEach((item: AdvancedSelectableCell) => {
1✔
365
                if (item.startValue.getTime() >= rangeStart.getTime() && item.startValue.getTime() < rangeEnd.getTime()) {
366
                    item.isInRange = true;
367
                } else {
368
                    item.isInRange = false;
369
                }
1✔
370
            });
371
        }
372
        this.selectableData[type].forEach(item => (item.classMap = this.getClassMap(item)));
373
    }
374

375
    onMouseleave(event: Event, type: ThyDateGranularity, value: AdvancedSelectableCell) {
376
        if (value.isInRange) {
377
            this.selectableData[type].forEach(item => (item.isInRange = false));
378
        }
379
        if (value.isOutRange) {
×
380
            this.selectableData[type].forEach(item => (item.isOutRange = false));
381
        }
382
        this.selectableData[type].forEach(item => (item.classMap = this.getClassMap(item)));
383
    }
384

385
    getActualStartAndEnd(value: AdvancedSelectableCell) {
386
        const selectedStart = this.selectedValue[0].startValue;
387
        const selectedEnd = this.selectedValue[this.selectedValue.length - 1].endValue;
388
        let rangeStart: TinyDate, rangeEnd: TinyDate;
389
        if (value.startValue.isBeforeDay(selectedStart)) {
390
            rangeStart = value.startValue;
391
            rangeEnd = selectedStart;
392
        }
393
        if (value.startValue.isAfterDay(selectedEnd)) {
394
            rangeStart = selectedEnd;
395
            rangeEnd = value.endValue;
396
        }
397
        return { rangeStart, rangeEnd };
398
    }
399

400
    ngOnDestroy(): void {
401
        this.selectedValueChange$.complete();
402
    }
403
}
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