Enhance DropdownWidget with search and click handling functionality for improved user interaction

This commit is contained in:
Yaro Kasear 2025-07-25 09:46:23 -05:00
parent 2b72158375
commit e91af64c1c
2 changed files with 76 additions and 66 deletions

View file

@ -41,8 +41,47 @@ const DropdownWidget = (() => {
}); });
}); });
function handleDropdownClick(e, name) {
if (e.target.tagName === "A") {
const input = document.getElementById(name);
const button = document.getElementById(`${name}Button`);
const clearButton = document.getElementById(`${name}ClearButton`);
input.value = e.target.dataset.invValue;
button.textContent = e.target.textContent;
if (e.target.dataset.invValue) {
clearButton.classList.remove("d-none");
button.classList.add("rounded-end-0");
button.classList.remove("rounded-end");
} else {
clearButton.classList.add("d-none");
button.classList.remove("rounded-end-0");
button.classList.add("rounded-end");
}
}
};
function searchDropdown(name) {
const searchInput = document.getElementById(`search${name}`);
const dropdown = document.getElementById(`menu${name}`);
const filter = searchInput.value.toLowerCase();
const items = dropdown.querySelectorAll("a.dropdown-item");
items.forEach(item => {
if (item.textContent.toLowerCase().includes(filter)) {
item.style.display = "";
} else {
item.style.display = "none";
}
});
};
return { return {
clear, clear,
handleDropdownClick,
searchDropdown,
setButton setButton
}; };
})(); })();

View file

@ -2,71 +2,42 @@
{% import "fragments/_link_fragment.html" as links %} {% import "fragments/_link_fragment.html" as links %}
{% macro render_dropdown(id, list, label, current_item = None, entry_link = None, enabled = True) %} {% macro render_dropdown(id, list, label, current_item = None, entry_link = None, enabled = True) %}
<label for="{{ id }}" class="form-label"> <label for="{{ id }}" class="form-label">
{{ label }} {{ label }}
{% if entry_link %} {% if entry_link %}
{{ links.entry_link(entry_link, current_item.id) }} {{ links.entry_link(entry_link, current_item.id) }}
{% endif %} {% endif %}
</label> </label>
<div class="dropdown"> <div class="dropdown">
<div class="btn-group w-100"> <div class="btn-group w-100">
<button class="btn btn-outline-dark dropdown-toggle overflow-x-hidden w-100 rounded-end{% if current_item %}-0 border-end-0{% endif %} dropdown-button" type="button" data-bs-toggle="dropdown" <button
data-inv-value="{{ current_item.id if current_item else '' }}" id="{{ id }}Button"{% if not enabled %} disabled{% endif %} class="btn btn-outline-dark dropdown-toggle overflow-x-hidden w-100 rounded-end{% if current_item %}-0 border-end-0{% endif %} dropdown-button"
style="border-color: rgb(222, 226, 230);{% if not enabled %} background-color: rgb(233, 236, 239); color: rgb(0, 0, 0);{% endif %}"> type="button" data-bs-toggle="dropdown" data-inv-value="{{ current_item.id if current_item else '' }}"
{{ current_item.identifier if current_item else '-' }} id="{{ id }}Button" {% if not enabled %} disabled{% endif %}
</button> style="border-color: rgb(222, 226, 230);{% if not enabled %} background-color: rgb(233, 236, 239); color: rgb(0, 0, 0);{% endif %}">
<button class="btn btn-outline-danger rounded-end font-weight-bold border-start-0{% if not current_item %} d-none{% endif %}" type="button" id="{{ id }}ClearButton" {{ current_item.identifier if current_item else '-' }}
style="z-index: 9999; border-color: rgb(222, 226, 230);{% if not enabled %} background-color: rgb(233, 236, 239); color: rgb(0, 0, 0);{% endif %}" onclick="DropdownWidget.clear('{{ id }}')"> </button>
{{ icons.render_icon('x-lg', 16) }} <button
</button> class="btn btn-outline-danger rounded-end font-weight-bold border-start-0{% if not current_item %} d-none{% endif %}"
<input type="hidden" name="{{ id }}" id="{{ id }}" value="{{ current_item.id if current_item else '' }}"> type="button" id="{{ id }}ClearButton"
<ul class="dropdown-menu w-100 pt-0" style="max-height: 40vh; z-index: 9999;" id="menu{{ id }}"> style="z-index: 9999; border-color: rgb(222, 226, 230);{% if not enabled %} background-color: rgb(233, 236, 239); color: rgb(0, 0, 0);{% endif %}"
<input type="text" class="form-control rounded-bottom-0 border-start-0 border-top-0 border-end-0 dropdown-search-input" id="search{{ id }}" placeholder="Search..."> onclick="DropdownWidget.clear('{{ id }}')">
<div class="overflow-auto overflow-x-hidden" style="z-index: 9999;" id="{{ id }}DropdownContent"> {{ icons.render_icon('x-lg', 16) }}
{% for item in list %} </button>
<li><a class="dropdown-item" data-inv-value="{{ item.id }}" onclick="DropdownWidget.setButton('{{ id }}', {{ item.id }}, '{{ item.identifier }}')">{{ item.identifier }}</a></li> <input type="hidden" name="{{ id }}" id="{{ id }}" value="{{ current_item.id if current_item else '' }}">
{% endfor %} <ul class="dropdown-menu w-100 pt-0" style="max-height: 40vh; z-index: 9999;" id="menu{{ id }}"
</div> onclick="DropdownWidget.handleDropdownClick(event, '{{ id }}')">
</ul> <input type="text"
</div> class="form-control rounded-bottom-0 border-start-0 border-top-0 border-end-0 dropdown-search-input"
id="search{{ id }}" placeholder="Search..." oninput="DropdownWidget.searchDropdown('{{ id }}')">
<div class="overflow-auto overflow-x-hidden" style="z-index: 9999;" id="{{ id }}DropdownContent">
{% for item in list %}
<li><a class="dropdown-item" data-inv-value="{{ item.id }}"
onclick="DropdownWidget.setButton('{{ id }}', {{ item.id }}, '{{ item.identifier }}')">{{
item.identifier }}</a></li>
{% endfor %}
</div>
</ul>
</div> </div>
<script> </div>
document.addEventListener("DOMContentLoaded", () => {
const {{ id }}Dropdown = document.getElementById("menu{{ id }}");
const {{ id }}Input = document.getElementById("{{ id }}");
const {{ id }}SearchInput = document.getElementById("search{{ id }}");
const {{ id }}DropdownContent = document.getElementById("{{ id }}DropdownContent");
const {{ id }}Button = document.getElementById("{{ id }}Button");
const {{ id }}ClearButton = document.getElementById("{{ id }}ClearButton");
{{ id }}Dropdown.addEventListener("click", (e) => {
if (e.target.tagName === "A") {
{{ id }}Input.value = e.target.dataset.invValue;
{{ id }}Button.textContent = e.target.textContent;
if (e.target.dataset.invValue) {
{{ id }}ClearButton.classList.remove("d-none");
{{ id }}Button.classList.add("rounded-end-0");
{{ id }}Button.classList.remove("rounded-end");
} else {
{{ id }}ClearButton.classList.add("d-none");
{{ id }}Button.classList.remove("rounded-end-0");
{{ id }}Button.classList.add("rounded-end");
}
}
});
{{ id }}SearchInput.addEventListener("input", () => {
const filter = {{ id }}SearchInput.value.toLowerCase();
const items = {{ id }}Dropdown.querySelectorAll("a.dropdown-item");
items.forEach(item => {
if (item.textContent.toLowerCase().includes(filter)) {
item.style.display = "";
} else {
item.style.display = "none";
}
});
});
});
</script>
{% endmacro %} {% endmacro %}