import {Component, Input, forwardRef, OnChanges, SimpleChanges} from '@angular/core'; import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms'; import {isNumber, padNumber, toInteger, isDefined} from '../util/util'; import {Ng2vTime} from './ng2v-time'; import {Ng2vTimepickerConfig} from './timepicker-config'; const NGB_TIMEPICKER_VALUE_ACCESSOR = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => Ng2vTimepicker), multi: true }; /** * A lightweight & configurable timepicker directive. */ @Component({ selector: 'ng2v-timepicker', styles: [` .ng2v-tp { display: flex; align-items: center; } .ng2v-tp-hour, .ng2v-tp-minute, .ng2v-tp-second, .ng2v-tp-meridian { display: flex; flex-direction: column; align-items: center; justify-content: space-around; } .ng2v-tp-spacer { width: 1em; text-align: center; } .chevron::before { border-style: solid; border-width: 0.29em 0.29em 0 0; content: ''; display: inline-block; height: 0.69em; left: 0.05em; position: relative; top: 0.15em; transform: rotate(-45deg); -webkit-transform: rotate(-45deg); -ms-transform: rotate(-45deg); vertical-align: middle; width: 0.71em; } .chevron.bottom:before { top: -.3em; -webkit-transform: rotate(135deg); -ms-transform: rotate(135deg); transform: rotate(135deg); } .btn-link { outline: 0; } .btn-link.disabled { cursor: not-allowed; opacity: .65; } input { text-align: center; display: inline-block; width: auto; } `], template: `
`, providers: [NGB_TIMEPICKER_VALUE_ACCESSOR] }) export class Ng2vTimepicker implements ControlValueAccessor, OnChanges { disabled: boolean; model: Ng2vTime; /** * Whether to display 12H or 24H mode. */ @Input() meridian: boolean; /** * Whether to display the spinners above and below the inputs. */ @Input() spinners: boolean; /** * Whether to display seconds input. */ @Input() seconds: boolean; /** * Number of hours to increase or decrease when using a button. */ @Input() hourStep: number; /** * Number of minutes to increase or decrease when using a button. */ @Input() minuteStep: number; /** * Number of seconds to increase or decrease when using a button. */ @Input() secondStep: number; /** * To make timepicker readonly */ @Input() readonlyInputs: boolean; /** * To set the size of the inputs and button */ @Input() size: 'small' | 'medium' | 'large'; constructor(config: Ng2vTimepickerConfig) { this.meridian = config.meridian; this.spinners = config.spinners; this.seconds = config.seconds; this.hourStep = config.hourStep; this.minuteStep = config.minuteStep; this.secondStep = config.secondStep; this.disabled = config.disabled; this.readonlyInputs = config.readonlyInputs; this.size = config.size; } onChange = (_: any) => {}; onTouched = () => {}; writeValue(value) { this.model = value ? new Ng2vTime(value.hour, value.minute, value.second) : new Ng2vTime(); if (!this.seconds && (!value || !isNumber(value.second))) { this.model.second = 0; } } registerOnChange(fn: (value: any) => any): void { this.onChange = fn; } registerOnTouched(fn: () => any): void { this.onTouched = fn; } setDisabledState(isDisabled: boolean) { this.disabled = isDisabled; } changeHour(step: number) { this.model.changeHour(step); this.propagateModelChange(); } changeMinute(step: number) { this.model.changeMinute(step); this.propagateModelChange(); } changeSecond(step: number) { this.model.changeSecond(step); this.propagateModelChange(); } updateHour(newVal: string) { this.model.updateHour(toInteger(newVal)); this.propagateModelChange(); } updateMinute(newVal: string) { this.model.updateMinute(toInteger(newVal)); this.propagateModelChange(); } updateSecond(newVal: string) { this.model.updateSecond(toInteger(newVal)); this.propagateModelChange(); } toggleMeridian() { if (this.meridian) { this.changeHour(12); } } formatHour(value: number) { if (isNumber(value)) { if (this.meridian) { return padNumber(value % 12 === 0 ? 12 : value % 12); } else { return padNumber(value % 24); } } else { return padNumber(NaN); } } formatMinSec(value: number) { return padNumber(value); } setFormControlSize() { return {'form-control-sm': this.size === 'small', 'form-control-lg': this.size === 'large'}; } setButtonSize() { return {'btn-sm': this.size === 'small', 'btn-lg': this.size === 'large'}; } ngOnChanges(changes: SimpleChanges): void { if (changes['seconds'] && !this.seconds && this.model && !isNumber(this.model.second)) { this.model.second = 0; this.propagateModelChange(false); } } private propagateModelChange(touched = true) { if (touched) { this.onTouched(); } if (this.model.isValid(this.seconds)) { this.onChange({hour: this.model.hour, minute: this.model.minute, second: this.model.second}); } else { this.onChange(null); } } }