| /******************************************************************************** |
| * Copyright © 2020 Basys GmbH. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| ********************************************************************************/ |
| |
| import {Component, ElementRef, EventEmitter, forwardRef, Input, OnChanges, SimpleChanges, ViewChild} from '@angular/core'; |
| import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms'; |
| |
| @Component({ |
| selector: 'ok-stepper-control', |
| styleUrls: ['stepper-control.component.scss'], |
| templateUrl: 'stepper-control.component.html', |
| providers: [ |
| { |
| provide: NG_VALUE_ACCESSOR, |
| multi: true, |
| useExisting: forwardRef(() => StepperControlComponent) |
| } |
| ] |
| }) |
| export class StepperControlComponent implements ControlValueAccessor, OnChanges { |
| |
| private static id = 0; |
| |
| @Input() |
| public controlId = `StepperControlComponent${StepperControlComponent.id++}`; |
| |
| @Input() |
| public isDisabled: boolean; |
| |
| @Input() |
| public placeholder: string; |
| |
| @Input() |
| public minValue; |
| |
| @Input() |
| public maxValue; |
| |
| @Input() |
| public step = 1; |
| |
| @Input() |
| public value: number; |
| |
| @Input() |
| public digits: number; |
| |
| @Input() |
| public cyclic: boolean; |
| |
| @Input() |
| public valueChange = new EventEmitter<number>(); |
| |
| @ViewChild('inputElementRef') |
| private inputElementRef: ElementRef<HTMLInputElement>; |
| |
| private onTouch = () => null; |
| |
| private onChange: (value: number) => void = () => null; |
| |
| public ngOnChanges(changes: SimpleChanges) { |
| if (changes.value) { |
| this.reformatInput(); |
| } |
| } |
| |
| public parseInput(inputValue: string) { |
| this.onTouch(); |
| this.setNewValue(parseInt(inputValue, 10), false); |
| } |
| |
| public decrement(step: number) { |
| step = Number.isInteger(step) && step > 0 ? step : 1; |
| const value = Number.isInteger(this.value) ? this.value : 0; |
| this.onTouch(); |
| this.setNewValue(value - step); |
| this.reformatInput(); |
| } |
| |
| public increment(step: number) { |
| step = Number.isInteger(step) && step > 0 ? step : 1; |
| const value = Number.isInteger(this.value) ? this.value : 0; |
| this.onTouch(); |
| this.setNewValue(value + step); |
| this.reformatInput(); |
| } |
| |
| public setNewValue(value: number, cyclic: boolean = this.cyclic) { |
| if (Number.isInteger(value)) { |
| if (Number.isInteger(this.step) && this.step > 0) { |
| value = Math.round(value / this.step) * this.step; |
| } |
| |
| const minValue = Number.isInteger(this.minValue) ? this.minValue : value; |
| const maxValue = Number.isInteger(this.maxValue) ? this.maxValue : value; |
| cyclic = [cyclic, Number.isInteger(this.minValue), Number.isInteger(this.maxValue)].every((_) => _); |
| |
| if (value < minValue) { |
| value = cyclic ? maxValue : minValue; |
| } |
| if (value > maxValue) { |
| value = cyclic ? minValue : maxValue; |
| } |
| |
| this.value = value; |
| this.onChange(value); |
| this.valueChange.emit(value); |
| } |
| } |
| |
| public reformatInput() { |
| if (Number.isFinite(this.value)) { |
| this.setInputValue(formatNumber(this.value, this.digits)); |
| } else { |
| this.value = null; |
| this.setInputValue(''); |
| } |
| } |
| |
| public writeValue(obj: any) { |
| this.value = Number.isInteger(obj) ? obj : this.value; |
| this.reformatInput(); |
| } |
| |
| public registerOnChange(fn: any) { |
| this.onChange = fn; |
| } |
| |
| public registerOnTouched(fn: any) { |
| this.onTouch = fn; |
| } |
| |
| public setDisabledState(isDisabled: boolean) { |
| this.isDisabled = isDisabled; |
| } |
| |
| private setInputValue(value: string) { |
| this.inputElementRef.nativeElement.value = value; |
| } |
| |
| } |
| |
| function formatNumber(value: number, digits?: number): string { |
| return Number.isInteger(digits) && digits > 0 ? |
| (value < 0 ? '-' : '') + Math.abs(value).toString().padStart(digits, '0') : |
| value.toString(); |
| } |