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

atinc / ngx-tethys / 68ef226c-f83e-44c1-b8ed-e420a83c5d84

28 May 2025 10:31AM UTC coverage: 10.352% (-80.0%) from 90.316%
68ef226c-f83e-44c1-b8ed-e420a83c5d84

Pull #3460

circleci

pubuzhixing8
chore: xxx
Pull Request #3460: refactor(icon): migrate signal input #TINFR-1476

132 of 6823 branches covered (1.93%)

Branch coverage included in aggregate %.

10 of 14 new or added lines in 1 file covered. (71.43%)

11648 existing lines in 344 files now uncovered.

2078 of 14525 relevant lines covered (14.31%)

6.69 hits per line

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

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

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

18
import { getControlsValue } from '../time-picker-controls.util';
1✔
19
import { TimePickerConfig } from './inner-time-picker.config';
UNCOV
20

×
21
import { TimeChangeSource, TimePickerComponentState, TimePickerControls } from './inner-time-picker.class';
22

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

×
UNCOV
34
import { Subscription } from 'rxjs';
×
UNCOV
35

×
UNCOV
36
import { ThyTimePickerStore } from './inner-time-picker.store';
×
UNCOV
37

×
UNCOV
38
export const TIMEPICKER_CONTROL_VALUE_ACCESSOR: StaticProvider = {
×
UNCOV
39
    provide: NG_VALUE_ACCESSOR,
×
40
    useExisting: forwardRef(() => ThyInnerTimePicker),
41
    multi: true
UNCOV
42
};
×
UNCOV
43

×
UNCOV
44
/**
×
45
 * @internal
UNCOV
46
 */
×
UNCOV
47
@Component({
×
48
    selector: 'thy-inner-time-picker',
UNCOV
49
    changeDetection: ChangeDetectionStrategy.OnPush,
×
UNCOV
50
    providers: [TIMEPICKER_CONTROL_VALUE_ACCESSOR, ThyTimePickerStore],
×
UNCOV
51
    templateUrl: './inner-time-picker.component.html',
×
52
    imports: []
53
})
54
export class ThyInnerTimePicker implements ControlValueAccessor, TimePickerComponentState, TimePickerControls, OnChanges, OnDestroy {
UNCOV
55
    private _cd = inject(ChangeDetectorRef);
×
UNCOV
56
    private _store = inject(ThyTimePickerStore);
×
UNCOV
57

×
58
    /** hours change step */
59
    @Input() hourStep: number;
UNCOV
60
    /** hours change step */
×
61
    @Input() minuteStep: number;
62
    /** seconds change step */
63
    @Input() secondsStep: number;
×
64
    /** if true hours and minutes fields will be readonly */
65
    @Input() readonlyInput: boolean;
66
    /** if true hours and minutes fields will be disabled */
×
67
    @Input() disabled: boolean;
68
    /** if true scroll inside hours and minutes inputs will change time */
UNCOV
69
    @Input() mousewheel: boolean;
×
70
    /** if true the values of hours and minutes can be changed using the up/down arrow keys on the keyboard */
71
    @Input() arrowKeys: boolean;
×
UNCOV
72
    /** if true spinner arrows above and below the inputs will be shown */
×
UNCOV
73
    @Input() showSpinners: boolean;
×
74
    /** if true meridian button will be shown */
75
    @Input() showMeridian: boolean;
×
UNCOV
76
    /** show minutes in timePicker */
×
UNCOV
77
    @Input() showMinutes: boolean;
×
78
    /** show seconds in timePicker */
79
    @Input() showSeconds: boolean;
×
UNCOV
80
    /** meridian labels based on locale */
×
UNCOV
81
    @Input() meridians: string[];
×
82
    /** minimum time user can select */
83
    @Input() min: Date;
UNCOV
84
    /** maximum time user can select */
×
UNCOV
85
    @Input() max: Date;
×
UNCOV
86
    /** placeholder for hours field in timePicker */
×
UNCOV
87
    @Input() hoursPlaceholder: string;
×
UNCOV
88
    /** placeholder for minutes field in timePicker */
×
UNCOV
89
    @Input() minutesPlaceholder: string;
×
UNCOV
90
    /** placeholder for seconds field in timePicker */
×
UNCOV
91
    @Input() secondsPlaceholder: string;
×
92
    /** timezone */
UNCOV
93
    @Input() timeZone: string;
×
94

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

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

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

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

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

×
118
    canDecrementHours: boolean;
119
    canDecrementMinutes: boolean;
UNCOV
120
    canDecrementSeconds: boolean;
×
121

122
    canToggleMeridian: boolean;
123

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

UNCOV
128
    private timerPickerSubscription = new Subscription();
×
UNCOV
129

×
UNCOV
130
    constructor() {
×
UNCOV
131
        const _config = inject(TimePickerConfig);
×
UNCOV
132
        const _cd = this._cd;
×
UNCOV
133
        const _store = this._store;
×
134

UNCOV
135
        Object.assign(this, _config);
×
136

137
        this.timerPickerSubscription.add(
138
            _store
139
                .select(state => state.value)
140
                .subscribe((value: Date) => {
141
                    // update UI values if date changed
142
                    this._renderTime(value);
UNCOV
143
                    this.onChange(value);
×
144
                    this._store.updateControls(getControlsValue(this), this.timeZone);
×
145
                })
UNCOV
146
        );
×
UNCOV
147

×
148
        this.timerPickerSubscription.add(
149
            _store
150
                .select(state => state.controls)
151
                .subscribe((controlsState: TimePickerControls) => {
152
                    this.isValid.emit(isInputValid(this.hours, this.minutes, this.seconds, this.isPM()));
UNCOV
153
                    Object.assign(this, controlsState);
×
UNCOV
154
                    _cd.markForCheck();
×
155
                })
UNCOV
156
        );
×
UNCOV
157
    }
×
158

159
    resetValidation(): void {
160
        this.invalidHours = false;
UNCOV
161
        this.invalidMinutes = false;
×
162
        this.invalidSeconds = false;
163
    }
UNCOV
164

×
165
    isPM(): boolean {
166
        return this.showMeridian && this.meridian === this.meridians[1];
UNCOV
167
    }
×
UNCOV
168

×
169
    prevDef($event: Event) {
170
        $event.preventDefault();
UNCOV
171
    }
×
172

173
    wheelSign($event: WheelEventInit): number {
UNCOV
174
        return Math.sign($event.deltaY) * -1;
×
UNCOV
175
    }
×
UNCOV
176

×
UNCOV
177
    ngOnChanges(changes: SimpleChanges): void {
×
UNCOV
178
        this._store.updateControls(getControlsValue(this), this.timeZone);
×
UNCOV
179
    }
×
180

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

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

191
    changeSeconds(step: number, source: TimeChangeSource = ''): void {
UNCOV
192
        this.resetValidation();
×
UNCOV
193
        this._store.changeSeconds({ step, source }, this.timeZone);
×
UNCOV
194
    }
×
195

196
    updateHours(hours: string): void {
1✔
197
        this.resetValidation();
1✔
198
        this.hours = hours;
199

200
        const isValid = isHourInputValid(this.hours, this.isPM()) && this.isValidLimit();
201

202
        if (!isValid) {
203
            this.invalidHours = true;
204
            this.isValid.emit(false);
205
            this.onChange(null);
206

207
            return;
208
        }
209

210
        this._updateTime();
211
    }
212

213
    updateMinutes(minutes: string) {
214
        this.resetValidation();
215
        this.minutes = minutes;
216

217
        const isValid = isMinuteInputValid(this.minutes) && this.isValidLimit();
218

219
        if (!isValid) {
1✔
220
            this.invalidMinutes = true;
221
            this.isValid.emit(false);
222
            this.onChange(null);
223

224
            return;
225
        }
226

227
        this._updateTime();
228
    }
229

230
    updateSeconds(seconds: string) {
231
        this.resetValidation();
232
        this.seconds = seconds;
233

234
        const isValid = isSecondInputValid(this.seconds) && this.isValidLimit();
235

236
        if (!isValid) {
237
            this.invalidSeconds = true;
238
            this.isValid.emit(false);
239
            this.onChange(null);
240

241
            return;
242
        }
243

244
        this._updateTime();
245
    }
246

247
    isValidLimit(): boolean {
248
        return isInputLimitValid(
249
            {
250
                hour: this.hours,
251
                minute: this.minutes,
252
                seconds: this.seconds,
253
                isPM: this.isPM()
254
            },
255
            this.max,
256
            this.min,
257
            this.timeZone
258
        );
259
    }
260

261
    _updateTime() {
262
        const _seconds = this.showSeconds ? this.seconds : void 0;
263
        const _minutes = this.showMinutes ? this.minutes : void 0;
264
        if (!isInputValid(this.hours, _minutes, _seconds, this.isPM())) {
265
            this.isValid.emit(false);
266
            this.onChange(null);
267

268
            return;
269
        }
270

271
        this._store.setTime(
272
            {
273
                hour: this.hours,
274
                minute: this.minutes,
275
                seconds: this.seconds,
276
                isPM: this.isPM()
277
            },
278
            this.timeZone
279
        );
280
    }
281

282
    toggleMeridian(): void {
283
        if (!this.showMeridian || !this.isEditable) {
284
            return;
285
        }
286

287
        const _hoursPerDayHalf = 12;
288
        this._store.changeHours({
289
            step: _hoursPerDayHalf,
290
            source: ''
291
        });
292
    }
293

294
    writeValue(obj: string | null | undefined | Date): void {
295
        if (isValidDate(obj)) {
296
            this._store.writeValue(parseTime(obj, this.timeZone));
297
        } else if (obj == null) {
298
            this._store.writeValue(null);
299
        }
300
    }
301

302
    registerOnChange(fn: (_: any) => {}): void {
303
        this.onChange = fn;
304
    }
305

306
    registerOnTouched(fn: () => {}): void {
307
        this.onTouched = fn;
308
    }
309

310
    setDisabledState(isDisabled: boolean): void {
311
        this.disabled = isDisabled;
312
        this._cd.markForCheck();
313
    }
314

315
    ngOnDestroy(): void {
316
        this.timerPickerSubscription.unsubscribe();
317
    }
318

319
    private _renderTime(value: string | Date): void {
320
        if (!isValidDate(value)) {
321
            this.hours = '';
322
            this.minutes = '';
323
            this.seconds = '';
324
            this.meridian = this.meridians[0];
325

326
            return;
327
        }
328

329
        const _value = parseTime(value, this.timeZone);
330
        const _hoursPerDayHalf = 12;
331
        let _hours = _value.getHours();
332

333
        if (this.showMeridian) {
334
            this.meridian = this.meridians[_hours >= _hoursPerDayHalf ? 1 : 0];
335
            _hours = _hours % _hoursPerDayHalf;
336
            // should be 12 PM, not 00 PM
337
            if (_hours === 0) {
338
                _hours = _hoursPerDayHalf;
339
            }
340
        }
341

342
        this.hours = padNumber(_hours);
343
        this.minutes = padNumber(_value.getMinutes());
344
        this.seconds = padNumber(_value.getUTCSeconds());
345
    }
346
}
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