blob: effabd0e6064aedce46375809f70ea654dcb8097 [file] [log] [blame]
/********************************************************************************
* Copyright (c) 2020 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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 {ConnectedPosition} from "@angular/cdk/overlay";
import {DOCUMENT} from "@angular/common";
import {Component, ElementRef, EventEmitter, forwardRef, Inject, Input, Output, ViewChild} from "@angular/core";
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from "@angular/forms";
import {MomentInput} from "moment";
import {timer} from "rxjs";
import {momentFormatDisplayNumeric, momentFormatInternal, parseMomentToDate, parseMomentToString} from "../../../util";
import {DropDownDirective} from "../../drop-down";
@Component({
selector: "app-date-control",
templateUrl: "./date-control.component.html",
styleUrls: ["./date-control.component.scss"],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DateControlComponent),
multi: true
}
]
})
export class DateControlComponent implements ControlValueAccessor {
private static id = 0;
@Input()
public appId = `CalendarControlComponent${DateControlComponent.id++}`;
@Input()
public appDisabled = false;
@Input()
public appInfo = false;
@Input()
public appSuccess = false;
@Input()
public appWarning = false;
@Input()
public appDanger = false;
@Output()
public appValueChange = new EventEmitter<string>();
@Input()
public appInternalFormat = momentFormatInternal;
@Input()
public appDisplayFormat = momentFormatDisplayNumeric;
public value: Date = new Date();
public displayedValue: Date = this.value;
public readonly connectedPositions: ConnectedPosition[] = [
{
originX: "start",
originY: "bottom",
overlayX: "start",
overlayY: "top",
offsetX: 4,
offsetY: -1,
panelClass: "bottom"
},
{
originX: "start",
originY: "top",
overlayX: "start",
overlayY: "bottom",
offsetY: 1,
offsetX: 4,
panelClass: "top"
},
{
originX: "end",
originY: "top",
overlayX: "start",
overlayY: "top",
panelClass: "right"
},
{
originX: "start",
originY: "top",
overlayX: "end",
overlayY: "top",
panelClass: "left"
}
];
@ViewChild("inputElement")
private readonly inputElement: ElementRef<HTMLInputElement>;
@ViewChild(DropDownDirective)
private dropDownDirective: DropDownDirective;
public constructor(@Inject(DOCUMENT) private readonly document: Document) {
}
@Input()
public set appValue(value: MomentInput) {
this.writeValue(value);
this.onInputBlur();
}
public onChange = (_: string) => null;
public onTouch = () => null;
public onKeyDown(event: KeyboardEvent, tabToInput?: boolean) {
if (event.key === "Tab") {
this.toggle(false);
if (tabToInput) {
this.dropDownDirective.nativeElement.focus();
}
}
}
public onCalendarChange(event: any) {
this.writeValue(event, true);
this.onInputBlur();
this.inputElement.nativeElement.focus();
timer(0).toPromise().then(() => this.toggle(false));
}
public onInputChange(value: string) {
const date = parseMomentToDate(value, this.appDisplayFormat);
if (date != null) {
this.writeValue(date, true, true);
}
}
public onInputBlur(inputElement?: HTMLInputElement) {
this.displayedValue = this.value;
if (inputElement != null) {
inputElement.value = parseMomentToString(this.value, this.appInternalFormat, this.appDisplayFormat);
}
}
public onMouseDown(element: HTMLElement) {
if (this.document?.activeElement !== element) {
// Toggle calendar only if the element is not focused:
this.toggle(true);
}
}
public toggle(openOrClose?: boolean) {
this.dropDownDirective.toggle(openOrClose);
}
public writeValue(obj: any, emit?: boolean, doNotChangeDisplayedValue?: boolean): void {
this.value = parseMomentToDate(obj, this.appInternalFormat, new Date());
if (!doNotChangeDisplayedValue) {
this.displayedValue = this.value;
}
const internalValue = parseMomentToString(this.value, this.appInternalFormat, this.appInternalFormat);
if (obj !== internalValue || emit) {
this.onChange(internalValue);
}
if (emit) {
this.appValueChange.emit(internalValue);
this.onTouch();
}
}
public setDisabledState(isDisabled: boolean): void {
this.appDisabled = isDisabled;
}
public registerOnChange(fn: any): void {
this.onChange = fn;
}
public registerOnTouched(fn: any): void {
this.onTouch = fn;
}
}