export class Dropdown { #element: HTMLElement; #options: HTMLElement; #value: HTMLElement; #callback: CallableFunction; #defaultValue: string; #optionsList: string[] = []; #index: number = 0; constructor(ID: string, callback: CallableFunction, options: string[] | null = null) { this.#element = document.getElementById(ID); this.#options = this.#element.querySelector(".ol-select-options"); this.#value = this.#element.querySelector(".ol-select-value"); this.#defaultValue = this.#value.innerText; this.#callback = callback; if (options != null) { this.setOptions(options); } this.#value.addEventListener("click", (ev) => { this.#element.classList.toggle("is-open"); this.#clip(); }); document.addEventListener("click", (ev) => { if (!(this.#value.contains(ev.target as Node) || this.#options.contains(ev.target as Node) || this.#element.contains(ev.target as Node))) { this.#element.classList.remove("is-open"); } }); this.#options.classList.add( "ol-scrollable" ); } setOptions(optionsList: string[]) { this.#optionsList = optionsList; this.#options.replaceChildren(...optionsList.map((option: string, idx: number) => { var div = document.createElement("div"); var button = document.createElement("button"); button.textContent = option; div.appendChild(button); if (option === this.#defaultValue) this.#index = idx; button.addEventListener("click", (e: MouseEvent) => { e.stopPropagation(); this.#value.innerText = option; this.#close(); this.#callback(option, e); this.#index = idx; }); return div; })); } selectText( text:string ) { const index = [].slice.call( this.#options.children ).findIndex( ( opt:Element ) => opt.querySelector( "button" )?.innerText === text ); if ( index > -1 ) { this.selectValue( index ); } } selectValue(idx: number) { if (idx < this.#optionsList.length) { var option = this.#optionsList[idx]; this.#value.innerText = option; this.#index = idx; this.#close(); this.#callback(option); return true; } else return false; } reset() { this.#options.replaceChildren(); this.#value.innerText = this.#defaultValue; } getValue() { return this.#value.innerText; } setValue(value: string) { var index = this.#optionsList.findIndex((option) => {return option === value}); if (index > -1) this.selectValue(index); } getIndex() { return this.#index; } #clip() { const options = this.#options; const bounds = options.getBoundingClientRect(); this.#element.dataset.position = ( bounds.bottom > window.innerHeight ) ? "top" : ""; } #close() { this.#element.classList.remove( "is-open" ); this.#element.dataset.position = ""; } #open() { this.#element.classList.add( "is-open" ); } #toggle() { if ( this.#element.classList.contains( "is-open" ) ) { this.#close(); } else { this.#open(); } } }