Made searchbar completely client-based

This commit is contained in:
Nicolas Margulies 2023-10-26 19:01:09 +02:00
parent 08b2fabe07
commit 5e39209ab1
2 changed files with 44 additions and 37 deletions

View File

@ -130,11 +130,11 @@ SPDX-License-Identifier: GPL-3.0-or-later
{% endfor %}
<div class="tab-pane" id="search">
<input class="form-control mx-auto d-block mb-3"
placeholder="{% trans "Search button..." %}" type="text" id="search-input"/>
placeholder="{% trans "Search button..." %}" type="search" id="search-input"/>
<div class="d-inline-flex flex-wrap justify-content-center" id="search-results">
{% for button in search_results %}
{% for button in all_buttons %}
{% if button.display %}
<button class="btn btn-outline-dark rounded-0 flex-fill"
<button class="btn btn-outline-dark rounded-0 flex-fill" hidden
id="search_button{{ button.id }}" name="button" value="{{ button.name }}">
{{ button.name }} ({{ button.amount | pretty_money }})
</button>
@ -202,33 +202,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
{% endfor %}
{% endfor %}
searchbar = document.getElementById("search-input")
const parser = new DOMParser();
old_pattern = null;
function updateSearch(force = false) {
let pattern = searchbar.value
if ((pattern === old_pattern || pattern === "") && !force)
return;
const xhr = new XMLHttpRequest();
xhr.open("GET", location.pathname + "?search=" +
encodeURI(pattern) + "#search", true)
xhr.onload = () => {
let newdoc = parser.parseFromString(xhr.responseText, "text/html");
document.getElementById("search-results").innerHTML =
newdoc.getElementById("search-results").innerHTML;
eval(newdoc.getElementById("search-script").text);
};
xhr.send();
}
searchbar.addEventListener("input", function (e) {
debounce(updateSearch)()
});
</script>
<script type="text/javascript" id="search-script">
{% for button in search_results %}
{% for button in all_buttons %}
{% if button.display %}
document.getElementById("search_button{{ button.id }}").addEventListener("click", function() {
addConso({{ button.destination_id }}, {{ button.amount }},
@ -237,5 +211,41 @@ SPDX-License-Identifier: GPL-3.0-or-later
});
{% endif %}
{% endfor %}
const searchbar = document.getElementById("search-input")
const search_results = document.getElementById("search-results")
var old_pattern = null;
var firstMatch = null;
/**
* Updates the button search tab
* @param force Forces the update even if the pattern didn't change
*/
function updateSearch(force = false) {
let pattern = searchbar.value
if (pattern === "")
firstMatch = null;
if ((pattern === old_pattern || pattern === "") && !force)
return;
firstMatch = null;
const re = new RegExp(pattern, "i");
Array.from(search_results.children).forEach(function(b) {
if (re.test(b.innerText)) {
b.hidden = false;
if (firstMatch === null) {
firstMatch = b;
}
} else
b.hidden = true;
});
}
searchbar.addEventListener("input", function (e) {
debounce(updateSearch)()
});
searchbar.addEventListener("keyup", function (e) {
if (firstMatch && e.key === "Enter")
firstMatch.click()
});
</script>
{% endblock %}

View File

@ -190,17 +190,14 @@ class ConsoView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
).order_by('name').all()
context['polymorphic_ctype'] = ContentType.objects.get_for_model(RecurrentTransaction).pk
if "search" in self.request.GET and self.request.GET["search"]:
pattern = self.request.GET["search"]
context['search_results'] = TransactionTemplate.objects.filter(
name__iregex=pattern
).filter(
PermissionBackend.filter_queryset(self.request, TransactionTemplate, "view")
).filter(display=True).order_by('name').all()
context['all_buttons'] = TransactionTemplate.objects.filter(
PermissionBackend.filter_queryset(self.request, TransactionTemplate, "view")
).filter(display=True).order_by('name').all()
return context
class TransactionSearchView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
model = Note
context_object_name = "note"