projects/rebirth-ng/src/lib/time-picker/time-picker.component.ts
exportAs | timePicker |
providers |
{
: , : (() => ), : true
}
|
selector | re-time-picker |
styleUrls | time-picker.component.scss |
templateUrl | ./time-picker.component.html |
constructor(changeDetectorRef: ChangeDetectorRef)
|
||||||
Parameters :
|
maxTime
|
Type:
Default value: |
minTime
|
Type:
Default value: |
showSeconds
|
Default value: |
getCurrentTimestamp | ||||
getCurrentTimestamp(time: )
|
||||
Parameters :
Returns :
number
|
getDateByTime | ||||||
getDateByTime(time: TimePickerModel)
|
||||||
Parameters :
Returns :
any
|
Private getTimePickerModel |
getTimePickerModel()
|
Returns :
TimePickerModel
|
getValue | ||||||
getValue(value: , defaultValue: )
|
||||||
Parameters :
Returns :
any
|
handleKeyEvent | ||||||
handleKeyEvent(event: , type: )
|
||||||
Parameters :
Returns :
void
|
initConditionDate |
initConditionDate()
|
Returns :
void
|
isSafetyKeyPress |
isSafetyKeyPress(keyType: any, target: string, key: string)
|
Returns :
boolean
|
isSupportedKeyPress | ||||
isSupportedKeyPress(event: )
|
||||
Parameters :
Returns :
boolean
|
modifyTimeByKey |
modifyTimeByKey(value: number, key: string)
|
Returns :
void
|
modifyTimeByKeyPress |
modifyTimeByKeyPress(key: string, type: string, step: number)
|
Returns :
void
|
modifyTimeByKeyPressEvent |
modifyTimeByKeyPressEvent(type: string, keyEventType: string)
|
Returns :
void
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
onModelChange |
onModelChange()
|
Returns :
void
|
onTimeChange | ||||||
onTimeChange(key: string)
|
||||||
Parameters :
Returns :
void
|
registerOnChange | ||||
registerOnChange(fn: )
|
||||
Parameters :
Returns :
void
|
registerOnTouched | ||||
registerOnTouched(fn: )
|
||||
Parameters :
Returns :
void
|
setDisabledState | ||||
setDisabledState(disabled: )
|
||||
Parameters :
Returns :
void
|
updateTimeByMargin | |||||||||
updateTimeByMargin(key: string, marginDate: )
|
|||||||||
Parameters :
Returns :
void
|
writeValue | ||||||
writeValue(value: TimePickerModel)
|
||||||
Parameters :
Returns :
void
|
disabled |
disabled:
|
Type : boolean
|
hour |
hour:
|
Type : string
|
Default value : '00'
|
maxDate |
maxDate:
|
Type : Date
|
minDate |
minDate:
|
Type : Date
|
minute |
minute:
|
Type : string
|
Default value : '00'
|
Private onChange |
onChange:
|
Default value : (_: TimePickerModel) => null
|
Private onTouched |
onTouched:
|
Default value : () => null
|
second |
second:
|
Type : string
|
Default value : '00'
|
timeUnit |
timeUnit:
|
Default value : TIME_UNIT
|
import { ChangeDetectorRef, Component, forwardRef, Input, OnInit } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { keyBoardHelper } from '../utils/keyboard-utils';
function fillLeft(num: number) {
return (num || 0) < 10 ? `0${num}` : `${num}`;
}
const ARROW_DOWN = 'ArrowDown';
const ARROW_UP = 'ArrowUp';
const supportKeyType = [ARROW_UP, ARROW_DOWN];
export class TimePickerModel {
constructor(public hour: number, public minute: number, public second?: number) {
}
toString() {
return `${fillLeft(this.hour)}:${fillLeft(this.minute)}:${fillLeft(this.second)}`;
}
}
const BACKSPACE_KEY_CODE = 8;
const ENTER_KEY_CODE = 13;
const TAB_KEY_CODE = 9;
const SUPPORTED_KEY_CODE = [
BACKSPACE_KEY_CODE,
ENTER_KEY_CODE,
TAB_KEY_CODE
];
export const TIME_UNIT = {
HOUR: 'hour',
MINUTE: 'minute',
SECOND: 'second',
};
export const MAX_TIME_RANGE = {
hour: 23,
minute: 59,
second: 59,
};
@Component({
selector: 're-time-picker',
styleUrls: ['./time-picker.component.scss'],
templateUrl: './time-picker.component.html',
exportAs: 'timePicker',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TimePickerComponent),
multi: true
}
]
})
export class TimePickerComponent implements OnInit, ControlValueAccessor {
@Input() showSeconds = true;
@Input() minTime = new TimePickerModel(0, 0, 0);
@Input() maxTime = new TimePickerModel(23, 59, 59);
hour = '00';
minute = '00';
second = '00';
timeUnit = TIME_UNIT;
minDate: Date;
maxDate: Date;
disabled: boolean;
private onChange = (_: TimePickerModel) => null;
private onTouched = () => null;
constructor(private changeDetectorRef: ChangeDetectorRef) {
}
ngOnInit(): void {
this.initConditionDate();
}
initConditionDate() {
this.minDate = this.getDateByTime(this.minTime);
this.maxDate = this.getDateByTime(this.maxTime);
}
getDateByTime(time: TimePickerModel) {
return new Date((new Date()).setHours(time.hour || 0, time.minute || 0, time.second || 0));
}
getValue(value, defaultValue) {
if (value || value === 0) {
return value;
}
return defaultValue;
}
getCurrentTimestamp(time): number {
const hour = this.getValue(time.hour, parseInt(this.hour, 10));
const minute = this.getValue(time.minute, parseInt(this.minute, 10));
const second = this.getValue(time.second, parseInt(this.second, 10));
return (new Date()).setHours(hour, minute, second);
}
writeValue(value: TimePickerModel) {
if (value) {
this.hour = fillLeft(value.hour || 0);
this.minute = fillLeft(value.minute || 0);
this.second = fillLeft(value.second || 0);
this.changeDetectorRef.markForCheck();
}
}
registerOnChange(fn) {
this.onChange = fn;
}
registerOnTouched(fn) {
this.onTouched = fn;
}
setDisabledState(disabled) {
this.disabled = disabled;
this.changeDetectorRef.markForCheck();
}
updateTimeByMargin(key: string, marginDate) {
switch (key) {
case TIME_UNIT.HOUR:
this.hour = fillLeft(marginDate[TIME_UNIT.HOUR]);
this.minute = fillLeft(marginDate[TIME_UNIT.MINUTE]);
if (marginDate[TIME_UNIT.SECOND]) {
this.second = fillLeft(marginDate[TIME_UNIT.SECOND]);
}
break;
case TIME_UNIT.MINUTE:
this.minute = fillLeft(marginDate[TIME_UNIT.MINUTE]);
if (marginDate[TIME_UNIT.SECOND]) {
this.second = fillLeft(marginDate[TIME_UNIT.SECOND]);
}
break;
case TIME_UNIT.SECOND:
this.second = fillLeft(marginDate[TIME_UNIT.SECOND]);
break;
}
}
modifyTimeByKey(value: number, key: string) {
if (isNaN(value)) {
if (this.getCurrentTimestamp({ [key]: 0 }) < this.minDate.getTime()) {
this.updateTimeByMargin(key, this.minTime);
} else if (this.getCurrentTimestamp({ [key]: 0 }) > this.maxDate.getTime()) {
this.updateTimeByMargin(key, this.maxTime);
} else {
this.updateTimeByMargin(key, this.minTime);
}
} else if (value < 0) {
this[key] = fillLeft(0) || fillLeft(this.minTime[key]);
} else if (value > MAX_TIME_RANGE[key] || this.getCurrentTimestamp({ [key]: value }) > this.maxDate.getTime()) {
this.updateTimeByMargin(key, this.maxTime);
} else if (this.getCurrentTimestamp({ [key]: value }) < this.minDate.getTime()) {
this.updateTimeByMargin(key, this.minTime);
} else {
this[key] = fillLeft(value);
}
}
onTimeChange(key: string) {
this.onTouched();
this.modifyTimeByKey(parseInt(this[key], 10), key);
this.onModelChange();
}
onModelChange() {
this.onChange(this.getTimePickerModel());
}
private getTimePickerModel() {
const model = new TimePickerModel(parseInt(this.hour, 10), parseInt(this.minute, 10));
if (this.showSeconds) {
model.second = parseInt(this.second, 10);
}
return model;
}
isSafetyKeyPress(keyType: any, target: string, key: string) {
const parsedTarget = parseInt(target, 10);
return !(keyType === ARROW_DOWN && parsedTarget < 1) &&
(
(keyType === ARROW_DOWN && key === TIME_UNIT.HOUR && parsedTarget <= MAX_TIME_RANGE.hour) ||
(keyType === ARROW_DOWN && (key === TIME_UNIT.MINUTE || key === TIME_UNIT.SECOND) && parsedTarget <= MAX_TIME_RANGE.minute) ||
(keyType === ARROW_UP && key === TIME_UNIT.HOUR && parsedTarget < MAX_TIME_RANGE.hour) ||
(keyType === ARROW_UP && (key === TIME_UNIT.MINUTE || key === TIME_UNIT.SECOND) && parsedTarget < MAX_TIME_RANGE.minute)
);
}
isSupportedKeyPress(event): boolean {
return SUPPORTED_KEY_CODE.indexOf(event.keyCode) > -1 ||
keyBoardHelper.numberKeyBoard(event) ||
keyBoardHelper.smallKeyBoard(event) ||
keyBoardHelper.arrowKeyBoard(event);
}
handleKeyEvent(event, type) {
if (!this.isSupportedKeyPress(event)) {
event.preventDefault();
return;
}
const keyEventType = event.code;
if (supportKeyType.indexOf(keyEventType) === -1) {
return;
}
this.modifyTimeByKeyPressEvent(type, keyEventType);
}
modifyTimeByKeyPress(key: string, type: string, step: number) {
if (this.isSafetyKeyPress(type, this[key], key)) {
this[key] = fillLeft(parseInt(this[key], 10) + step);
}
}
modifyTimeByKeyPressEvent(type: string, keyEventType: string) {
let step = 1;
if (keyEventType === ARROW_DOWN) {
step = -1;
}
switch (type) {
case this.timeUnit.HOUR:
this.modifyTimeByKeyPress(TIME_UNIT.HOUR, keyEventType, step);
break;
case this.timeUnit.MINUTE:
this.modifyTimeByKeyPress(TIME_UNIT.MINUTE, keyEventType, step);
break;
case this.timeUnit.SECOND:
this.modifyTimeByKeyPress(TIME_UNIT.SECOND, keyEventType, step);
break;
}
}
}
<form class="form-inline time-picker">
<div class="form-group">
<input type="text"
#hours
[disabled]="disabled"
name="hours"
class="form-control"
maxlength="2"
max="23"
min="0"
autocomplete="off"
[(ngModel)]="hour"
(keydown)="handleKeyEvent($event, timeUnit.HOUR)"
(blur)="onTimeChange(timeUnit.HOUR)">
</div>
<span>:</span>
<div class="form-group">
<input type="text"
#minutes
[disabled]="disabled"
name="minutes"
class="form-control"
maxlength="2"
max="59"
min="0"
autocomplete="off"
[(ngModel)]="minute"
(keydown)="handleKeyEvent($event, timeUnit.MINUTE)"
(blur)="onTimeChange(timeUnit.MINUTE)">
</div>
<ng-container *ngIf="showSeconds">
<span>:</span>
<div class="form-group">
<input type="text"
#seconds
[disabled]="disabled"
name="seconds"
class="form-control"
max="59"
min="0"
maxlength="2"
autocomplete="off"
[(ngModel)]="second"
(keydown)="handleKeyEvent($event, timeUnit.SECOND)"
(blur)="onTimeChange(timeUnit.SECOND)">
</div>
</ng-container>
</form>