mapcomplete/UI/Input/DropDown.ts

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

103 lines
3.2 KiB
TypeScript
Raw Normal View History

2020-07-20 21:39:07 +02:00
import { InputElement } from "./InputElement"
2020-07-21 00:38:03 +02:00
import Translations from "../i18n/Translations"
import { UIEventSource } from "../../Logic/UIEventSource"
2021-06-10 01:36:20 +02:00
import BaseUIElement from "../BaseUIElement"
2020-07-20 21:39:07 +02:00
export class DropDown<T> extends InputElement<T> {
2021-06-10 01:36:20 +02:00
private static _nextDropdownId = 0
public IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false)
2021-06-10 01:36:20 +02:00
private readonly _element: HTMLElement
2021-06-10 01:36:20 +02:00
private readonly _value: UIEventSource<T>
private readonly _values: { value: T; shown: string | BaseUIElement }[]
2020-07-20 21:39:07 +02:00
/**
*
* const dropdown = new DropDown<number>("test",[{value: 42, shown: "the answer"}])
* dropdown.GetValue().data // => 42
*/
2021-06-10 01:36:20 +02:00
constructor(
label: string | BaseUIElement,
values: { value: T; shown: string | BaseUIElement }[],
value: UIEventSource<T> = undefined,
2021-06-10 01:36:20 +02:00
options?: {
select_class?: string
2020-07-20 21:39:07 +02:00
}
2021-06-10 01:36:20 +02:00
) {
super()
value = value ?? new UIEventSource<T>(values[0].value)
2021-06-15 16:18:58 +02:00
this._value = value
2021-06-12 02:58:32 +02:00
this._values = values
2021-06-10 01:36:20 +02:00
if (values.length <= 1) {
return
}
const id = DropDown._nextDropdownId
DropDown._nextDropdownId++
const el = document.createElement("form")
this._element = el
el.id = "dropdown" + id
{
const labelEl = Translations.W(label)?.ConstructElement()
2021-06-12 02:58:32 +02:00
if (labelEl !== undefined) {
const labelHtml = document.createElement("label")
labelHtml.appendChild(labelEl)
labelHtml.htmlFor = el.id
2021-06-13 15:04:55 +02:00
el.appendChild(labelHtml)
2021-06-12 02:58:32 +02:00
}
2021-06-10 01:36:20 +02:00
}
2021-06-15 16:18:58 +02:00
2021-06-14 17:42:26 +02:00
options = options ?? {}
2022-04-19 23:43:28 +02:00
options.select_class =
options.select_class ?? "w-full bg-indigo-100 p-1 rounded hover:bg-indigo-200"
2021-06-10 01:36:20 +02:00
{
const select = document.createElement("select")
2021-06-14 17:42:26 +02:00
select.classList.add(...(options.select_class.split(" ") ?? []))
2021-06-10 01:36:20 +02:00
for (let i = 0; i < values.length; i++) {
const option = document.createElement("option")
option.value = "" + i
option.appendChild(Translations.W(values[i].shown).ConstructElement())
2021-06-13 15:04:55 +02:00
select.appendChild(option)
2020-07-20 21:39:07 +02:00
}
2021-06-13 15:04:55 +02:00
el.appendChild(select)
2021-06-10 01:36:20 +02:00
select.onchange = () => {
const index = select.selectedIndex
2021-06-10 01:36:20 +02:00
value.setData(values[index].value)
2022-09-08 21:40:48 +02:00
}
2021-06-10 01:36:20 +02:00
value.addCallbackAndRun((selected) => {
for (let i = 0; i < values.length; i++) {
const value = values[i].value
if (value === selected) {
select.selectedIndex = i
}
2021-06-12 02:58:32 +02:00
}
2021-06-10 01:36:20 +02:00
})
2020-07-21 00:38:03 +02:00
}
2020-07-20 21:39:07 +02:00
2021-06-10 01:36:20 +02:00
this.onClick(() => {}) // by registering a click, the click event is consumed and doesn't bubble further to other elements, e.g. checkboxes
}
2020-07-20 21:39:07 +02:00
GetValue(): UIEventSource<T> {
return this._value
}
2021-06-10 01:36:20 +02:00
2020-07-20 21:39:07 +02:00
IsValid(t: T): boolean {
for (const value of this._values) {
2020-07-20 21:39:07 +02:00
if (value.value === t) {
return true
}
}
2020-07-20 21:39:07 +02:00
return false
}
2021-06-10 01:36:20 +02:00
protected InnerConstructElement(): HTMLElement {
return this._element
}
}