mirror of
https://github.com/coalaura/whiskr.git
synced 2025-09-09 09:19:54 +00:00
various improvements
This commit is contained in:
123
static/js/dropdown.js
Normal file
123
static/js/dropdown.js
Normal file
@@ -0,0 +1,123 @@
|
||||
(() => {
|
||||
class Dropdown {
|
||||
#_select;
|
||||
#_dropdown;
|
||||
#_selected;
|
||||
|
||||
#selected = false;
|
||||
#options = [];
|
||||
|
||||
constructor(el) {
|
||||
this.#_select = el;
|
||||
|
||||
this.#_select.querySelectorAll("option").forEach((option) => {
|
||||
this.#options.push({
|
||||
value: option.value,
|
||||
label: option.textContent.trim(),
|
||||
});
|
||||
});
|
||||
|
||||
this.#build();
|
||||
|
||||
if (this.#options.length) {
|
||||
this.#set(this.#options[0].value);
|
||||
}
|
||||
}
|
||||
|
||||
#build() {
|
||||
// prepare and hide original select
|
||||
this.#_select.style.display = "none";
|
||||
|
||||
const descriptor = Object.getOwnPropertyDescriptor(
|
||||
HTMLSelectElement.prototype,
|
||||
"value",
|
||||
);
|
||||
|
||||
Object.defineProperty(this.#_select, "value", {
|
||||
get: () => {
|
||||
return descriptor.get.call(this.#_select);
|
||||
},
|
||||
set: (value) => {
|
||||
descriptor.set.call(this.#_select, value);
|
||||
|
||||
this.#set(value);
|
||||
},
|
||||
});
|
||||
|
||||
// dropdown
|
||||
this.#_dropdown = make("div", "dropdown");
|
||||
|
||||
this.#_dropdown.addEventListener("click", () => {
|
||||
this.#_dropdown.classList.add("open");
|
||||
});
|
||||
|
||||
// selected item
|
||||
this.#_selected = make("div", "selected");
|
||||
|
||||
this.#_dropdown.appendChild(this.#_selected);
|
||||
|
||||
// option wrapper
|
||||
const _options = make("div", "options");
|
||||
|
||||
this.#_dropdown.appendChild(_options);
|
||||
|
||||
// options
|
||||
for (const option of this.#options) {
|
||||
const _opt = make("div", "option");
|
||||
|
||||
_opt.textContent = option.label;
|
||||
|
||||
_opt.addEventListener("click", () => {
|
||||
this.#set(option.value);
|
||||
});
|
||||
|
||||
option.el = _opt;
|
||||
}
|
||||
|
||||
// add to dom
|
||||
this.#_select.after(this.#_dropdown);
|
||||
|
||||
this.#render();
|
||||
}
|
||||
|
||||
#render() {
|
||||
if (this.#selected === false) {
|
||||
this.#_selected.textContent = "";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const selection = this.#options[this.#selected];
|
||||
|
||||
this.#_selected.textContent = selection.label;
|
||||
}
|
||||
|
||||
#set(value) {
|
||||
console.log("value", value);
|
||||
|
||||
const index = this.#options.findIndex((option) => option.value === value);
|
||||
|
||||
if (this.#selected === index) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.#selected = index !== -1 ? index : false;
|
||||
|
||||
this.#render();
|
||||
}
|
||||
}
|
||||
|
||||
document.body.addEventListener("click", (event) => {
|
||||
const clicked = event.target.closest(".dropdown");
|
||||
|
||||
document.querySelectorAll(".dropdown").forEach((element) => {
|
||||
if (element === clicked) {
|
||||
return;
|
||||
}
|
||||
|
||||
element.classList.remove("open");
|
||||
});
|
||||
});
|
||||
|
||||
window.dropdown = (el) => new Dropdown(el);
|
||||
})();
|
Reference in New Issue
Block a user