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

atinc / ngx-tethys / 5ba5b9d7-3ca9-4ff2-bbba-bde58c0f849f

22 Feb 2024 09:41AM UTC coverage: 90.604%. Remained the same
5ba5b9d7-3ca9-4ff2-bbba-bde58c0f849f

Pull #3027

circleci

minlovehua
feat(schematics): provide schematics for removing the suffix of standalone components #INFR-11662
Pull Request #3027: refactor: remove the component suffix for standalone components and provide schematics #INFR-10654

5425 of 6642 branches covered (81.68%)

Branch coverage included in aggregate %.

323 of 333 new or added lines in 193 files covered. (97.0%)

36 existing lines in 8 files now uncovered.

13504 of 14250 relevant lines covered (94.76%)

981.28 hits per line

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

95.21
/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';
32✔
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

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

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

32✔
33
import { Subscription } from 'rxjs';
32✔
34

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

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

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

91
    /** emits true if value is a valid date */
2✔
92
    @Output() isValid = new EventEmitter<boolean>();
93

94
    // ui variables
2✔
95
    hours: string;
2✔
96
    minutes: string;
2✔
97
    seconds: string;
2✔
98
    meridian: string;
1✔
99

1✔
100
    get isEditable(): boolean {
1✔
101
        return !(this.readonlyInput || this.disabled);
1✔
102
    }
103

1✔
104
    // min/max validation for input fields
105
    invalidHours = false;
106
    invalidMinutes = false;
2✔
107
    invalidSeconds = false;
2✔
108

2✔
109
    // time picker controls state
2✔
110
    canIncrementHours: boolean;
1✔
111
    canIncrementMinutes: boolean;
1✔
112
    canIncrementSeconds: boolean;
1✔
113

1✔
114
    canDecrementHours: boolean;
115
    canDecrementMinutes: boolean;
1✔
116
    canDecrementSeconds: boolean;
117

118
    canToggleMeridian: boolean;
5✔
119

120
    // control value accessor methods
121
    onChange = Function.prototype;
122
    onTouched = Function.prototype;
123

124
    private timerPickerSubscription = new Subscription();
125

126
    constructor(_config: TimePickerConfig, private _cd: ChangeDetectorRef, private _store: ThyTimePickerStore) {
4!
127
        Object.assign(this, _config);
4!
128

4✔
129
        this.timerPickerSubscription.add(
1✔
130
            _store
1✔
131
                .select(state => state.value)
1✔
132
                .subscribe((value: Date) => {
133
                    // update UI values if date changed
3✔
134
                    this._renderTime(value);
135
                    this.onChange(value);
136
                    this._store.updateControls(getControlsValue(this));
137
                })
138
        );
139

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

151
    resetValidation(): void {
79✔
152
        this.invalidHours = false;
30✔
153
        this.invalidMinutes = false;
154
        this.invalidSeconds = false;
49!
155
    }
49✔
156

157
    isPM(): boolean {
158
        return this.showMeridian && this.meridian === this.meridians[1];
159
    }
32✔
160

161
    prevDef($event: Event) {
162
        $event.preventDefault();
32✔
163
    }
164

165
    wheelSign($event: WheelEventInit): number {
33✔
166
        return Math.sign($event.deltaY) * -1;
33✔
167
    }
168

169
    ngOnChanges(changes: SimpleChanges): void {
32✔
170
        this._store.updateControls(getControlsValue(this));
171
    }
172

80✔
173
    changeHours(step: number, source: TimeChangeSource = ''): void {
32✔
174
        this.resetValidation();
32✔
175
        this._store.changeHours({ step, source });
32✔
176
    }
32✔
177

32✔
178
    changeMinutes(step: number, source: TimeChangeSource = ''): void {
179
        this.resetValidation();
48✔
180
        this._store.changeMinutes({ step, source });
48✔
181
    }
48✔
182

48✔
183
    changeSeconds(step: number, source: TimeChangeSource = ''): void {
27✔
184
        this.resetValidation();
27✔
185
        this._store.changeSeconds({ step, source });
186
    }
27✔
187

6✔
188
    updateHours(hours: string): void {
189
        this.resetValidation();
190
        this.hours = hours;
48✔
191

48✔
192
        const isValid = isHourInputValid(this.hours, this.isPM()) && this.isValidLimit();
48✔
193

194
        if (!isValid) {
1✔
195
            this.invalidHours = true;
196
            this.isValid.emit(false);
197
            this.onChange(null);
198

199
            return;
1✔
200
        }
201

202
        this._updateTime();
203
    }
204

205
    updateMinutes(minutes: string) {
206
        this.resetValidation();
207
        this.minutes = minutes;
208

209
        const isValid = isMinuteInputValid(this.minutes) && this.isValidLimit();
210

211
        if (!isValid) {
212
            this.invalidMinutes = true;
213
            this.isValid.emit(false);
214
            this.onChange(null);
215

216
            return;
217
        }
218

219
        this._updateTime();
220
    }
1✔
221

222
    updateSeconds(seconds: string) {
223
        this.resetValidation();
224
        this.seconds = seconds;
225

226
        const isValid = isSecondInputValid(this.seconds) && this.isValidLimit();
227

228
        if (!isValid) {
229
            this.invalidSeconds = true;
230
            this.isValid.emit(false);
231
            this.onChange(null);
232

233
            return;
234
        }
235

236
        this._updateTime();
237
    }
238

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

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

259
            return;
260
        }
261

262
        this._store.setTime({
263
            hour: this.hours,
264
            minute: this.minutes,
265
            seconds: this.seconds,
266
            isPM: this.isPM()
267
        });
268
    }
269

270
    toggleMeridian(): void {
271
        if (!this.showMeridian || !this.isEditable) {
272
            return;
273
        }
274

275
        const _hoursPerDayHalf = 12;
276
        this._store.changeHours({
277
            step: _hoursPerDayHalf,
278
            source: ''
279
        });
280
    }
281

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

290
    registerOnChange(fn: (_: any) => {}): void {
291
        this.onChange = fn;
292
    }
293

294
    registerOnTouched(fn: () => {}): void {
295
        this.onTouched = fn;
296
    }
297

298
    setDisabledState(isDisabled: boolean): void {
299
        this.disabled = isDisabled;
300
        this._cd.markForCheck();
301
    }
302

303
    ngOnDestroy(): void {
304
        this.timerPickerSubscription.unsubscribe();
305
    }
306

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

314
            return;
315
        }
316

317
        const _value = parseTime(value);
318
        const _hoursPerDayHalf = 12;
319
        let _hours = _value.getHours();
320

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

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