• 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

3.42
/src/time-picker/inner/inner-time-picker.component.ts
1
import {
2
    ChangeDetectionStrategy,
3
    ChangeDetectorRef,
4
    Component,
5
    EventEmitter,
6
    forwardRef,
7
    Input,
8
    OnChanges,
9
    OnDestroy,
10
    Output,
11
    SimpleChanges,
1✔
12
    StaticProvider
13
} from '@angular/core';
14

×
15
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
16

17
import { getControlsValue } from '../time-picker-controls.util';
18
import { TimePickerConfig } from './inner-time-picker.config';
19

20
import { TimeChangeSource, TimePickerComponentState, TimePickerControls } from './inner-time-picker.class';
1✔
21

22
import {
×
23
    isValidDate,
24
    padNumber,
25
    parseTime,
×
26
    isInputValid,
×
27
    isHourInputValid,
×
28
    isMinuteInputValid,
29
    isSecondInputValid,
×
30
    isInputLimitValid
×
31
} from '../time-picker.utils';
×
32

33
import { Subscription } from 'rxjs';
×
34

×
35
import { ThyTimePickerStore } from './inner-time-picker.store';
×
36
import { NgIf } from '@angular/common';
×
37

×
38
export const TIMEPICKER_CONTROL_VALUE_ACCESSOR: StaticProvider = {
×
39
    provide: NG_VALUE_ACCESSOR,
40
    /* eslint-disable-next-line @typescript-eslint/no-use-before-define */
41
    useExisting: forwardRef(() => ThyInnerTimePickerComponent),
×
42
    multi: true
×
43
};
×
44

45
/**
×
46
 * @internal
×
47
 */
48
@Component({
×
49
    selector: 'thy-inner-time-picker',
×
50
    changeDetection: ChangeDetectionStrategy.OnPush,
×
51
    providers: [TIMEPICKER_CONTROL_VALUE_ACCESSOR, ThyTimePickerStore],
52
    templateUrl: './inner-time-picker.component.html',
53
    standalone: true,
54
    imports: [NgIf]
×
55
})
×
56
export class ThyInnerTimePickerComponent
×
57
    implements ControlValueAccessor, TimePickerComponentState, TimePickerControls, OnChanges, OnDestroy
58
{
59
    /** hours change step */
×
60
    @Input() hourStep: number;
61
    /** hours change step */
62
    @Input() minuteStep: number;
×
63
    /** seconds change step */
64
    @Input() secondsStep: number;
65
    /** if true hours and minutes fields will be readonly */
×
66
    @Input() readonlyInput: boolean;
67
    /** if true hours and minutes fields will be disabled */
68
    @Input() disabled: boolean;
×
69
    /** if true scroll inside hours and minutes inputs will change time */
70
    @Input() mousewheel: boolean;
×
71
    /** if true the values of hours and minutes can be changed using the up/down arrow keys on the keyboard */
×
72
    @Input() arrowKeys: boolean;
×
73
    /** if true spinner arrows above and below the inputs will be shown */
74
    @Input() showSpinners: boolean;
×
75
    /** if true meridian button will be shown */
×
76
    @Input() showMeridian: boolean;
×
77
    /** show minutes in timePicker */
78
    @Input() showMinutes: boolean;
×
79
    /** show seconds in timePicker */
×
80
    @Input() showSeconds: boolean;
×
81
    /** meridian labels based on locale */
82
    @Input() meridians: string[];
83
    /** minimum time user can select */
×
84
    @Input() min: Date;
×
85
    /** maximum time user can select */
×
86
    @Input() max: Date;
×
87
    /** placeholder for hours field in timePicker */
×
88
    @Input() hoursPlaceholder: string;
×
89
    /** placeholder for minutes field in timePicker */
×
90
    @Input() minutesPlaceholder: string;
×
91
    /** placeholder for seconds field in timePicker */
92
    @Input() secondsPlaceholder: string;
×
93

94
    /** emits true if value is a valid date */
95
    @Output() isValid = new EventEmitter<boolean>();
×
96

×
97
    // ui variables
×
98
    hours: string;
×
99
    minutes: string;
×
100
    seconds: string;
×
101
    meridian: string;
×
102

×
103
    get isEditable(): boolean {
104
        return !(this.readonlyInput || this.disabled);
×
105
    }
106

107
    // min/max validation for input fields
×
108
    invalidHours = false;
×
109
    invalidMinutes = false;
×
110
    invalidSeconds = false;
×
111

×
112
    // time picker controls state
×
113
    canIncrementHours: boolean;
×
114
    canIncrementMinutes: boolean;
×
115
    canIncrementSeconds: boolean;
116

×
117
    canDecrementHours: boolean;
118
    canDecrementMinutes: boolean;
119
    canDecrementSeconds: boolean;
×
120

121
    canToggleMeridian: boolean;
122

123
    // control value accessor methods
124
    onChange = Function.prototype;
125
    onTouched = Function.prototype;
126

127
    private timerPickerSubscription = new Subscription();
×
128

×
129
    constructor(_config: TimePickerConfig, private _cd: ChangeDetectorRef, private _store: ThyTimePickerStore) {
×
130
        Object.assign(this, _config);
×
131

×
132
        this.timerPickerSubscription.add(
×
133
            _store
134
                .select(state => state.value)
×
135
                .subscribe((value: Date) => {
136
                    // update UI values if date changed
137
                    this._renderTime(value);
138
                    this.onChange(value);
139
                    this._store.updateControls(getControlsValue(this));
140
                })
141
        );
142

×
143
        this.timerPickerSubscription.add(
×
144
            _store
145
                .select(state => state.controls)
×
146
                .subscribe((controlsState: TimePickerControls) => {
×
147
                    this.isValid.emit(isInputValid(this.hours, this.minutes, this.seconds, this.isPM()));
148
                    Object.assign(this, controlsState);
149
                    _cd.markForCheck();
150
                })
151
        );
152
    }
×
153

×
154
    resetValidation(): void {
155
        this.invalidHours = false;
×
156
        this.invalidMinutes = false;
×
157
        this.invalidSeconds = false;
158
    }
159

160
    isPM(): boolean {
×
161
        return this.showMeridian && this.meridian === this.meridians[1];
162
    }
163

×
164
    prevDef($event: Event) {
165
        $event.preventDefault();
166
    }
×
167

×
168
    wheelSign($event: WheelEventInit): number {
169
        return Math.sign($event.deltaY) * -1;
170
    }
×
171

172
    ngOnChanges(changes: SimpleChanges): void {
173
        this._store.updateControls(getControlsValue(this));
×
174
    }
×
175

×
176
    changeHours(step: number, source: TimeChangeSource = ''): void {
×
177
        this.resetValidation();
×
178
        this._store.changeHours({ step, source });
×
179
    }
180

×
181
    changeMinutes(step: number, source: TimeChangeSource = ''): void {
×
182
        this.resetValidation();
×
183
        this._store.changeMinutes({ step, source });
×
184
    }
×
185

×
186
    changeSeconds(step: number, source: TimeChangeSource = ''): void {
187
        this.resetValidation();
×
188
        this._store.changeSeconds({ step, source });
×
189
    }
190

191
    updateHours(hours: string): void {
×
192
        this.resetValidation();
×
193
        this.hours = hours;
×
194

195
        const isValid = isHourInputValid(this.hours, this.isPM()) && this.isValidLimit();
1✔
196

197
        if (!isValid) {
198
            this.invalidHours = true;
199
            this.isValid.emit(false);
200
            this.onChange(null);
1✔
201

202
            return;
203
        }
204

205
        this._updateTime();
206
    }
207

208
    updateMinutes(minutes: string) {
209
        this.resetValidation();
210
        this.minutes = minutes;
211

212
        const isValid = isMinuteInputValid(this.minutes) && this.isValidLimit();
213

214
        if (!isValid) {
215
            this.invalidMinutes = true;
216
            this.isValid.emit(false);
217
            this.onChange(null);
218

219
            return;
220
        }
221

1✔
222
        this._updateTime();
223
    }
224

225
    updateSeconds(seconds: string) {
226
        this.resetValidation();
227
        this.seconds = seconds;
228

229
        const isValid = isSecondInputValid(this.seconds) && this.isValidLimit();
230

231
        if (!isValid) {
232
            this.invalidSeconds = true;
233
            this.isValid.emit(false);
234
            this.onChange(null);
235

236
            return;
237
        }
238

239
        this._updateTime();
240
    }
241

242
    isValidLimit(): boolean {
243
        return isInputLimitValid(
244
            {
245
                hour: this.hours,
246
                minute: this.minutes,
247
                seconds: this.seconds,
248
                isPM: this.isPM()
249
            },
250
            this.max,
251
            this.min
252
        );
253
    }
254

255
    _updateTime() {
256
        const _seconds = this.showSeconds ? this.seconds : void 0;
257
        const _minutes = this.showMinutes ? this.minutes : void 0;
258
        if (!isInputValid(this.hours, _minutes, _seconds, this.isPM())) {
259
            this.isValid.emit(false);
260
            this.onChange(null);
261

262
            return;
263
        }
264

265
        this._store.setTime({
266
            hour: this.hours,
267
            minute: this.minutes,
268
            seconds: this.seconds,
269
            isPM: this.isPM()
270
        });
271
    }
272

273
    toggleMeridian(): void {
274
        if (!this.showMeridian || !this.isEditable) {
275
            return;
276
        }
277

278
        const _hoursPerDayHalf = 12;
279
        this._store.changeHours({
280
            step: _hoursPerDayHalf,
281
            source: ''
282
        });
283
    }
284

285
    writeValue(obj: string | null | undefined | Date): void {
286
        if (isValidDate(obj)) {
287
            this._store.writeValue(parseTime(obj));
288
        } else if (obj == null) {
289
            this._store.writeValue(null);
290
        }
291
    }
292

293
    registerOnChange(fn: (_: any) => {}): void {
294
        this.onChange = fn;
295
    }
296

297
    registerOnTouched(fn: () => {}): void {
298
        this.onTouched = fn;
299
    }
300

301
    setDisabledState(isDisabled: boolean): void {
302
        this.disabled = isDisabled;
303
        this._cd.markForCheck();
304
    }
305

306
    ngOnDestroy(): void {
307
        this.timerPickerSubscription.unsubscribe();
308
    }
309

310
    private _renderTime(value: string | Date): void {
311
        if (!isValidDate(value)) {
312
            this.hours = '';
313
            this.minutes = '';
314
            this.seconds = '';
315
            this.meridian = this.meridians[0];
316

317
            return;
318
        }
319

320
        const _value = parseTime(value);
321
        const _hoursPerDayHalf = 12;
322
        let _hours = _value.getHours();
323

324
        if (this.showMeridian) {
325
            this.meridian = this.meridians[_hours >= _hoursPerDayHalf ? 1 : 0];
326
            _hours = _hours % _hoursPerDayHalf;
327
            // should be 12 PM, not 00 PM
328
            if (_hours === 0) {
329
                _hours = _hoursPerDayHalf;
330
            }
331
        }
332

333
        this.hours = padNumber(_hours);
334
        this.minutes = padNumber(_value.getMinutes());
335
        this.seconds = padNumber(_value.getUTCSeconds());
336
    }
337
}
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