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 { }
}