import { Component, Input, ElementRef, ViewChild, Output, EventEmitter, forwardRef, HostListener, NgZone } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; @Component({ selector: 'farris-time-spinner', template: `
`, styles: [ ` .btn-group { height: 1.50003rem; flex-direction: column; } .half-btn { height: 50%; display: flex; } .icon { flex: 1; line-height: 1; } ` ], providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TimeSpinnerComponent), multi: true } ] }) export class TimeSpinnerComponent implements ControlValueAccessor { @ViewChild('input') input: ElementRef; @Input() set disabled(v: boolean) { this._disabled = v !== false; } get disabled() { return this._disabled; } @Input() set readonly(v: boolean) { this._readonly = v !== false; } get readonly() { return this._readonly; } @Input() set editable(v: any) { this._editable = v === true || v === ''; } get editable() { return this._editable; } @Input() set use12Hours(v: boolean) { this._use12Hours = v !== false; } get use12Hours() { return this._use12Hours; } @Input() placeHolder: string = '请选择时间'; @Input() format: string = 'hh:mm:ss'; @Input() hourStep: number = 1; @Input() minuteStep: number = 1; @Input() secondStep: number = 1; @Input() max: string; @Input() min: string; @Input() set disabledSeconds(v: boolean) { this._disabledSeconds = v !== false; } get disabledSeconds() { return this._disabledSeconds; } @Input() separator: string = ':'; @Input() set value(v: string) { if (v === '') return; let time = this.parseTime(v); if (!time) return; const maxTime = this.parseTime(this.max); const minTime = this.parseTime(this.min); if (minTime && minTime > time) { time = minTime; } if (maxTime && maxTime < time) { time = maxTime; } let tt = [ this.formatTime(time.getHours()), this.formatTime(time.getMinutes()) ]; if (!this.disabledSeconds) { tt.push(this.formatTime(time.getSeconds())); } let newValue = tt.join(this.separator); if (this.use12Hours) { let hour = Number(newValue.substr(0, 2)); if (hour >= 12) { newValue = this.formatTime(hour - 12) + newValue.substr(2) + ' PM'; } else { newValue = newValue + ' AM'; } } if (this._value !== newValue) { this.change.emit({ newValue, oldValue: this._value }); } this.onChangeCallback(newValue); this.onTouchedCallback(newValue); this._value = newValue; } get value() { return this._value; } @Output() change = new EventEmitter(); @Output() onBlur = new EventEmitter(); @Output() focus = new EventEmitter(); private _disabledSeconds: boolean = false; private _disabled: boolean = false; private _readonly: boolean = false; private _editable: boolean = true; private _use12Hours: boolean = false; _value: string; private selObj: any; private start: number = 0; private end: number = 2; private onTouchedCallback = (obj: any) => { }; private onChangeCallback = (obj: any) => { }; constructor(private ngZone: NgZone) { this.selObj = window.getSelection(); } onClick() { const cursor = this.input.nativeElement.selectionStart; if (this.use12Hours) { if (cursor <= 2) { this.start = 0; this.end = 2; } else if (cursor > 2 && cursor <= 5) { this.start = 3; this.end = 5; } else if (cursor > 5 && cursor <= 8) { this.start = 6; this.end = 8; } else { this.start = 9; this.end = 11; } } else { if (cursor <= 2) { this.start = 0; this.end = 2; } else if (cursor > 2 && cursor <= 5) { this.start = 3; this.end = 5; } else { this.start = 6; this.end = 8; } } this.input.nativeElement.setSelectionRange(this.start, this.end); } blur() { this.value = this.input.nativeElement.value; this.onBlur.emit(); } onFocus() { this.focus.emit(); } up() { this.compute('up'); } down() { this.compute('down'); } compute(type: string) { //if (isNaN(this.selObj.toString())) return if (this.disabled) return; let step: number, newValue: string; let tempMax = this.start < 2 ? 24 : 60; if (this.start === 0) { step = this.hourStep; } else if (this.start === 3) { step = this.minuteStep; } else { step = this.secondStep; } step = Number(step); if (this.use12Hours && isNaN(this.selObj.toString())) { if (this.selObj.toString() === 'PM') { this.value = this.value.substr(0, this.value.length - 2) + 'AM'; } else { this.value = this.value.substr(0, this.value.length - 2) + 'PM'; } } else { if (type === 'up') { newValue = this.formatTime( Number(this.selObj.toString()) + step ); } else { newValue = this.formatTime( Number(this.selObj.toString()) - step ); } if (Number(newValue) >= tempMax) { newValue = this.formatTime(0); } if (Number(newValue) < 0) { newValue = this.formatTime(tempMax + newValue); } this.value = this.value.substring(0, this.start) + newValue + this.value.substring(this.end, this.value.length); } this.ngZone.runOutsideAngular(() => { setTimeout(() => { this.input.nativeElement.focus(); this.input.nativeElement.setSelectionRange(this.start, this.end); }, 0); }); } formatTime(value) { if (value < 0) return value; return (value < 10 ? '0' : '') + value; } parseTime(value: string) { if (!value) { return; } const separators: any[] = value.split(this.separator); if (this.use12Hours) { if (separators[separators.length - 1].indexOf('PM') > 0) { separators[0] = Number(separators[0]) + 12 + ''; separators[separators.length - 1] = separators[ separators.length - 1 ].substr(0, 2); } if (separators[separators.length - 1].indexOf('AM') > 0) { separators[separators.length - 1] = separators[ separators.length - 1 ].substr(0, 2); } } for (let i = 0; i < separators.length; i++) { if (isNaN(separators[i])) { return null; } } while (separators.length < 3) { separators.push(0); } return new Date( 1900, 0, 0, separators[0], separators[1], separators[2] ); } clearDate() { if (!this.disabled) { this.change.emit({ newValue: '', oldValue: this._value }); this._value = ''; this.onChangeCallback(''); } } @HostListener('mouseenter', ['$event']) onMouseEnter(event) { if ( this.input.nativeElement.value && !this.readonly && !this.disabled ) { event.target.querySelector('.input-group-clear').style.display = ''; } } @HostListener('mouseleave', ['$event']) onMouseLeave(event) { if (!this.readonly && !this.disabled) { event.target.querySelector('.input-group-clear').style.display = 'none'; } } onChange() { this.onChangeCallback(this.value); } writeValue(val: any): void { if (val) { this.value = val; } else { this.value = '0'; } } registerOnChange(fn: any): void { this.onChangeCallback = fn; } registerOnTouched(fn: any): void { this.onTouchedCallback = fn; } setDisabledState?(isDisabled: boolean): void { } }