102 lines
		
	
	
	
		
			3.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			102 lines
		
	
	
	
		
			3.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import { InputElement } from "./InputElement"
 | 
						|
import Translations from "../i18n/Translations"
 | 
						|
import { UIEventSource } from "../../Logic/UIEventSource"
 | 
						|
import BaseUIElement from "../BaseUIElement"
 | 
						|
 | 
						|
export class DropDown<T> extends InputElement<T> {
 | 
						|
    private static _nextDropdownId = 0
 | 
						|
    public IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false)
 | 
						|
 | 
						|
    private readonly _element: HTMLElement
 | 
						|
 | 
						|
    private readonly _value: UIEventSource<T>
 | 
						|
    private readonly _values: { value: T; shown: string | BaseUIElement }[]
 | 
						|
 | 
						|
    /**
 | 
						|
     *
 | 
						|
     * const dropdown = new DropDown<number>("test",[{value: 42, shown: "the answer"}])
 | 
						|
     * dropdown.GetValue().data // => 42
 | 
						|
     */
 | 
						|
    constructor(
 | 
						|
        label: string | BaseUIElement,
 | 
						|
        values: { value: T; shown: string | BaseUIElement }[],
 | 
						|
        value: UIEventSource<T> = undefined,
 | 
						|
        options?: {
 | 
						|
            select_class?: string
 | 
						|
        }
 | 
						|
    ) {
 | 
						|
        super()
 | 
						|
        value = value ?? new UIEventSource<T>(values[0].value)
 | 
						|
        this._value = value
 | 
						|
        this._values = values
 | 
						|
        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()
 | 
						|
            if (labelEl !== undefined) {
 | 
						|
                const labelHtml = document.createElement("label")
 | 
						|
                labelHtml.appendChild(labelEl)
 | 
						|
                labelHtml.htmlFor = el.id
 | 
						|
                el.appendChild(labelHtml)
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        options = options ?? {}
 | 
						|
        options.select_class =
 | 
						|
            options.select_class ?? "w-full bg-indigo-100 p-1 rounded hover:bg-indigo-200"
 | 
						|
 | 
						|
        {
 | 
						|
            const select = document.createElement("select")
 | 
						|
            select.classList.add(...(options.select_class.split(" ") ?? []))
 | 
						|
            for (let i = 0; i < values.length; i++) {
 | 
						|
                const option = document.createElement("option")
 | 
						|
                option.value = "" + i
 | 
						|
                option.appendChild(Translations.W(values[i].shown).ConstructElement())
 | 
						|
                select.appendChild(option)
 | 
						|
            }
 | 
						|
            el.appendChild(select)
 | 
						|
 | 
						|
            select.onchange = () => {
 | 
						|
                const index = select.selectedIndex
 | 
						|
                value.setData(values[index].value)
 | 
						|
            }
 | 
						|
 | 
						|
            value.addCallbackAndRun((selected) => {
 | 
						|
                for (let i = 0; i < values.length; i++) {
 | 
						|
                    const value = values[i].value
 | 
						|
                    if (value === selected) {
 | 
						|
                        select.selectedIndex = i
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            })
 | 
						|
        }
 | 
						|
 | 
						|
        this.onClick(() => {}) // by registering a click, the click event is consumed and doesn't bubble further to other elements, e.g. checkboxes
 | 
						|
    }
 | 
						|
 | 
						|
    GetValue(): UIEventSource<T> {
 | 
						|
        return this._value
 | 
						|
    }
 | 
						|
 | 
						|
    IsValid(t: T): boolean {
 | 
						|
        for (const value of this._values) {
 | 
						|
            if (value.value === t) {
 | 
						|
                return true
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return false
 | 
						|
    }
 | 
						|
 | 
						|
    protected InnerConstructElement(): HTMLElement {
 | 
						|
        return this._element
 | 
						|
    }
 | 
						|
}
 |