unicorn-components
Version:
<a target="_blank" href="https://getunicorn.io"><img src="https://bitbucket-assetroot.s3.amazonaws.com/c/photos/2017/Jul/07/2615006260-5-nitsnetsstudios-ondemand-UNI_avatar.png" align="left"></a>
175 lines (156 loc) • 5.98 kB
text/typescript
import { Component, EventEmitter, HostBinding, Input, OnChanges, Output } from '@angular/core';
import { pad } from '../../../utils';
const HOUR_PATTERN = /^(\d|[01]\d|2[0-3]):?([0-5]\d)$/;
export class UniClockComponent implements OnChanges {
componentClass = true;
model = '00:00';
modelChange = new EventEmitter();
set min(value: string) {
if (!value) { return; }
if (!HOUR_PATTERN.test(value)) { console.warn(`Invalid hour format: ${value}`); return; }
const arr = value.split(':');
this.hourMin = +arr[0];
this.minuteMin = +arr[1];
this.refreshModeAvailability();
this.refreshHoursAvailable();
this.refreshMinutesAvailable();
const { hour, minute } = this.getHourMinuteFromModel();
this.updateValue(hour, minute);
};
set max(value: string) {
if (!value) { return; }
if (!HOUR_PATTERN.test(value)) { console.warn(`Invalid hour format: ${value}`); return; }
const arr = value.split(':');
this.hourMax = +arr[0];
this.minuteMax = +arr[1];
this.refreshModeAvailability();
this.refreshHoursAvailable();
this.refreshMinutesAvailable();
this.updateValueFromModel();
};
mode: 'AM' | 'PM' = 'AM';
modeAvailability = {
AM: true,
PM: true
};
hoursModes = {
AM: ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11'],
PM: ['12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23']
};
hours: string[] = this.hoursModes['AM'];
minutes: string[] = ['00', '05', '10', '15', '20', '25', '30', '35', '40', '45', '50', '55'];
minutesAvailable: boolean[] = this.minutes.map(h => true);
hoursAvailable: boolean[] = this.hours.map(h => true);
hour = 0;
hourIndex = 0;
hourDegrees = 0;
hourMax = 23;
hourMin = 0;
minute = 0;
minuteIndex = 0;
minuteDegrees = 0;
minuteMax = 59;
minuteMin = 0;
ngOnChanges(changes) {
if (changes.model) {
this.updateValueFromModel();
this.refreshHoursAvailable();
this.refreshMinutesAvailable();
}
}
selectMode(mode) {
if (!this.modeAvailability[mode]) { return; }
this.setMode(mode);
this.updateValueFromIndex();
this.refreshHoursAvailable();
this.refreshMinutesAvailable();
}
selectHour(index) {
if (!this.hoursAvailable[index]) { return; }
this.hourIndex = index;
this.updateValueFromIndex();
this.refreshMinutesAvailable();
}
selectMinute(index) {
if (!this.minutesAvailable[index]) { return; }
this.minuteIndex = index;
this.updateValueFromIndex();
}
private refreshModeAvailability() {
this.modeAvailability = {
AM: this.hourMin < 12,
PM: this.hourMax >= 12
};
}
private refreshHoursAvailable() {
this.hoursAvailable = this.hours.map(h => +h >= this.hourMin && +h <= this.hourMax);
}
private refreshMinutesAvailable() {
if (this.hour > this.hourMin && this.hour < this.hourMax) {
return this.minutesAvailable = this.minutes.map(m => true);
}
if (this.hour < this.hourMin || this.hour > this.hourMax) {
return this.minutesAvailable = this.minutes.map(m => false);
}
const minMinute = this.hour === this.hourMin ? this.minuteMin : 0;
const maxMinute = this.hour === this.hourMax ? this.minuteMax : 59;
this.minutesAvailable = this.minutes.map(m => +m >= minMinute && +m <= maxMinute)
}
private setMode(mode) {
this.mode = mode;
this.hours = this.hoursModes[mode];
}
private applyDegrees() {
this.minuteDegrees = 6 * this.minute;
this.hourDegrees = 30 * (this.hour % 12) + this.minuteDegrees / 12;
}
private updateValue(hour, minute) {
// Set the clock hours and minutes as integers
if (hour < this.hourMin) {
this.hour = this.hourMin;
this.minute = this.minuteMin;
} else if (hour > this.hourMax) {
this.hour = this.hourMax;
this.minute = this.minuteMax;
} else {
this.hour = hour;
this.minute = minute;
if (hour === this.hourMin) { this.minute = Math.max(this.minuteMin, this.minute); }
if (hour === this.hourMax) { this.minute = Math.min(this.minuteMax, this.minute); }
}
// Set the right mode
if (this.hour >= 12 && this.mode !== 'PM') {
this.setMode('PM');
} else if (this.hour < 12 && this.mode !== 'AM') {
this.setMode('AM');
}
const paddedHour = pad(this.hour, 2);
const paddedMinute = pad(this.minute, 2);
// Set the clock indexes to highlight the numbers
this.hourIndex = this.hours.indexOf(paddedHour);
this.minuteIndex = this.minutes.indexOf(paddedMinute);
this.model = `${paddedHour}:${paddedMinute}`;
this.modelChange.emit(this.model);
this.applyDegrees();
}
private updateValueFromIndex() {
const { hour, minute } = this.getHourMinuteFromIndex();
this.updateValue(hour, minute);
}
private updateValueFromModel() {
const { hour, minute } = this.getHourMinuteFromModel();
this.updateValue(hour, minute);
}
private getHourMinuteFromIndex() {
return { hour: +this.hours[this.hourIndex], minute: +this.minutes[this.minuteIndex] };
}
private getHourMinuteFromModel() {
const timeSplitted = (this.model || '00:00').split(':');
return { hour: +timeSplitted[0], minute: +timeSplitted[1] };
}
}