blob: b9a4ec94a377b0e784930b96c90d0a18fec26400 [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 {Component, EventEmitter, forwardRef, Input, Output, ViewChild} from "@angular/core";
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from "@angular/forms";
import {EKeyboardKeys} from "../../../util/events";
import {DropDownDirective} from "../../drop-down";
import {ISelectOption} from "../ISelectOption";
@Component({
selector: "app-select",
templateUrl: "./select.component.html",
styleUrls: ["./select.component.scss"],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SelectComponent),
multi: true
}
]
})
export class SelectComponent implements ControlValueAccessor {
private static id = 0;
@Input()
public appId = `CalendarControlComponent${SelectComponent.id++}`;
@Input()
public appPlaceholder = "";
@Input()
public appValue: any;
@Input()
public appOptions: ISelectOption[] = [];
@Output()
public appValueChange = new EventEmitter<any>();
@ViewChild(DropDownDirective)
public dropDown: DropDownDirective;
public readonly connectedPositions: ConnectedPosition[] = [
{
originX: "start",
originY: "bottom",
overlayX: "start",
overlayY: "top",
offsetX: 4,
panelClass: "bottom"
},
{
originX: "start",
originY: "top",
overlayX: "start",
overlayY: "bottom",
offsetX: 4,
panelClass: "top"
},
{
originX: "start",
originY: "center",
overlayX: "start",
overlayY: "center",
panelClass: "center",
offsetX: 4
}
];
@Input()
public appDisabled = false;
public onChange = (_: any) => null;
public onTouch = () => null;
public writeValue(obj: any, emit?: boolean) {
const oldValue = this.appValue;
this.appValue = obj;
if (emit && oldValue !== obj) {
this.appValueChange.emit(obj);
this.onChange(obj);
this.onTouch();
}
}
public registerOnChange(fn: any) {
this.onChange = typeof fn === "function" ? fn : this.onChange;
}
public registerOnTouched(fn: any) {
this.onTouch = typeof fn === "function" ? fn : this.onTouch;
}
public setDisabledState(isDisabled: boolean) {
this.appDisabled = isDisabled;
}
public toggle(openOrClose?: boolean) {
this.dropDown.toggle(openOrClose);
}
public onClickOnOption(value: any) {
this.toggle(false);
if (this.appDisabled) {
return;
}
this.writeValue(value, true);
}
public onKeyDown(event: KeyboardEvent) {
switch (event?.key) {
case EKeyboardKeys.ESCAPE:
case EKeyboardKeys.TAB:
return this.toggle(false);
case EKeyboardKeys.ARROW_DOWN:
case EKeyboardKeys.ARROW_RIGHT: {
const value = this.getNextValue();
if (this.appDisabled || value == null) {
return;
}
event.preventDefault();
return this.writeValue(value, true);
}
case EKeyboardKeys.ARROW_UP:
case EKeyboardKeys.ARROW_LEFT: {
const value = this.getPreviousValue();
if (this.appDisabled || value == null) {
return;
}
event.preventDefault();
return this.writeValue(value, true);
}
}
}
public getNextValue() {
if (!Array.isArray(this.appOptions)) {
return;
}
if (this.appValue == null) {
return this.appOptions[0]?.value;
} else {
const index = this.appOptions.findIndex((o) => o?.value === this.appValue) + 1;
return this.appOptions[index < this.appOptions?.length ? index : 0]?.value;
}
}
public getPreviousValue() {
if (!Array.isArray(this.appOptions)) {
return;
}
if (this.appValue == null) {
return this.appOptions[this.appOptions.length - 1]?.value;
} else {
const index = this.appOptions.findIndex((o) => o?.value === this.appValue) - 1;
return this.appOptions[index > -1 ? index : this.appOptions.length - 1]?.value;
}
}
}