From 86f13b1f430d160585ad2107f314e4088bde6f7f Mon Sep 17 00:00:00 2001 From: DarkWargs Date: Sat, 8 Jun 2024 14:13:57 +0200 Subject: [PATCH 1/8] fixed a readme error --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ede049c..68e11c9 100644 --- a/README.md +++ b/README.md @@ -75,5 +75,5 @@ CHECKOUT_TOKEN=koala # database docker-compose up -d # server -nix-shell --run "./manage.py runserver" +dotenv nix-shell --run "./manage.py runserver" ``` From 2bcf0fa731ede941ce4a7ca386cde1dd4e43cc86 Mon Sep 17 00:00:00 2001 From: DarkWargs Date: Mon, 10 Jun 2024 20:13:31 +0200 Subject: [PATCH 2/8] Extended filter functionality for filtering on category and status --- .../static/AdminBoardView/products.js | 46 ++++++++++++++++++- admin_board_view/templates/products.html | 6 +-- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/admin_board_view/static/AdminBoardView/products.js b/admin_board_view/static/AdminBoardView/products.js index 16b1fe6..c533975 100644 --- a/admin_board_view/static/AdminBoardView/products.js +++ b/admin_board_view/static/AdminBoardView/products.js @@ -54,11 +54,26 @@ function delete_product(id) { const filter_input = document.getElementById("filter-products"); if (filter_input) { filter_input.addEventListener("keyup", e => { - const filter = filter_input.value.toLowerCase(); + if(e.key != "Enter") return; + const filter_string = filter_input.value.toLowerCase(); + const filters = getFilters(filter_string) const products = document.getElementsByClassName("product-row"); Array.from(products).forEach(product => { + const name = product.querySelector(".product-name").innerHTML.toLowerCase(); - if (name.includes(filter)) { + const category = product.querySelector(".product-category").innerHTML.toLowerCase(); + const active = product.getAttribute("data-status").toLowerCase(); + + let activeFilter = "" + if(active == "true") activeFilter = "active"; + if(active == "false") activeFilter = "inactive"; + + const nameMatches = !filters.name || name.includes(filters.name); + const categoryMatches = !filters.category || category.includes(filters.category); + const statusMatches = !filters.status || activeFilter == filters.status; + + //hide elements not matching all filters + if (nameMatches && categoryMatches && statusMatches) { product.style.display = ""; } else { product.style.display = "none"; @@ -67,6 +82,33 @@ if (filter_input) { }); } +function getFilters(filter_string) +{ + strings = filter_string.split(" "); + filters = { + "category" : "", + "status" : "", + "name" : "" + } + + strings.forEach(string => { + let [type, value] = string.toLowerCase().split(":") + //If type is specified + if(value != undefined){ + if(filters.hasOwnProperty(type)){ + filters[type] = value + } + } + //Add to name search if no type is specified + else{ + filters["name"] += type + " " + } + } + ) + filters.name = filters.name.trim(); // Remove trailing space + return filters //Return dictionary of filters +} + const params = new URLSearchParams(window.location.search); if (params.get("edit")) { productModal.show() diff --git a/admin_board_view/templates/products.html b/admin_board_view/templates/products.html index 6debca3..bfbd8ea 100644 --- a/admin_board_view/templates/products.html +++ b/admin_board_view/templates/products.html @@ -9,7 +9,7 @@

Products

- +
@@ -23,11 +23,11 @@

Products

{% for product in products %} - + - +
{{ product.image_view }} {{ product.name }} {{ product.euro }}{{ product.category }}{{ product.category }}
From 7233a2cb18f1cfdf6dee76412991d1656eaa66c5 Mon Sep 17 00:00:00 2001 From: DarkWargs Date: Fri, 14 Jun 2024 15:30:41 +0200 Subject: [PATCH 3/8] added autocomplete (manual types) no arrow nav --- .../static/AdminBoardView/products.js | 118 ++++++++++++++---- .../static/AdminBoardView/styles.css | 24 ++++ admin_board_view/templates/products.html | 1 + 3 files changed, 116 insertions(+), 27 deletions(-) diff --git a/admin_board_view/static/AdminBoardView/products.js b/admin_board_view/static/AdminBoardView/products.js index c533975..8c48746 100644 --- a/admin_board_view/static/AdminBoardView/products.js +++ b/admin_board_view/static/AdminBoardView/products.js @@ -51,34 +51,98 @@ function delete_product(id) { } // Filter products -const filter_input = document.getElementById("filter-products"); -if (filter_input) { - filter_input.addEventListener("keyup", e => { - if(e.key != "Enter") return; - const filter_string = filter_input.value.toLowerCase(); - const filters = getFilters(filter_string) - const products = document.getElementsByClassName("product-row"); - Array.from(products).forEach(product => { - - const name = product.querySelector(".product-name").innerHTML.toLowerCase(); - const category = product.querySelector(".product-category").innerHTML.toLowerCase(); - const active = product.getAttribute("data-status").toLowerCase(); - - let activeFilter = "" - if(active == "true") activeFilter = "active"; - if(active == "false") activeFilter = "inactive"; - - const nameMatches = !filters.name || name.includes(filters.name); - const categoryMatches = !filters.category || category.includes(filters.category); - const statusMatches = !filters.status || activeFilter == filters.status; - - //hide elements not matching all filters - if (nameMatches && categoryMatches && statusMatches) { - product.style.display = ""; - } else { - product.style.display = "none"; +const filterInput = document.getElementById("filter-products"); +const suggestionsContainer = document.getElementById("autocomplete-suggestions"); + +// Sample categories and statuses for demonstration purposes +const categories = ["electronics", "furniture", "clothing", "books"]; +const statuses = ["active", "inactive"]; + +if (filterInput) { + filterInput.addEventListener("keyup", e => { + const filterString = filterInput.value.toLowerCase(); + if(e.key != "Enter"){ + + cursorPos = filterInput.selectionStart + const lastWord = filterString.slice(0,cursorPos).split(" ").pop(); + suggestionsContainer.innerHTML = ''; + + if (lastWord.startsWith("category:")) { + showSuggestions(categories, lastWord.replace("category:", "").trim()); + } else if (lastWord.startsWith("status:")) { + showSuggestions(statuses, lastWord.replace("status:", "").trim()); + } + } + else { + const filters = getFilters(filterString); + const products = document.getElementsByClassName("product-row"); + Array.from(products).forEach(product => { + const name = product.querySelector(".product-name").innerHTML.toLowerCase(); + const category = product.querySelector(".product-category").innerHTML.toLowerCase(); + const active = product.getAttribute("data-status").toLowerCase(); + + let activeFilter = ""; + if (active == "true") activeFilter = "active"; + if (active == "false") activeFilter = "inactive"; + + // Only filter by criteria if they are specified (non-empty) + const nameMatches = !filters.name || name.includes(filters.name); + const categoryMatches = !filters.category || category.includes(filters.category); + const statusMatches = !filters.status || activeFilter == filters.status; + + if (nameMatches && categoryMatches && statusMatches) { + product.style.display = ""; + } else { + product.style.display = "none"; + } + }); + } + }); + + suggestionsContainer.addEventListener("click", e => { + if (e.target && e.target.matches("div.suggestion")) { + firstPart = filterInput.value.slice(0,filterInput.selectionStart) + lastPart = filterInput.value.slice(filterInput.selectionStart) + firstPart = firstPart.slice(0,firstPart.lastIndexOf(':')+1) + filterInput.value = firstPart + e.target.innerText + lastPart + suggestionsContainer.innerHTML = ''; + } + }); +} + +function getFilters(filterString) { + const strings = filterString.split(" "); + const filters = { + category: "", + status: "", + name: "" + }; + + strings.forEach(string => { + let [type, value] = string.toLowerCase().split(":"); + if (value != undefined) { + if (filters.hasOwnProperty(type)) { + filters[type] = value; } - }); + } else { + filters.name += type + " "; + } + }); + + filters.name = filters.name.trim(); // Remove trailing space + return filters; +} + +function showSuggestions(suggestions, input) { + const filteredSuggestions = suggestions.filter(suggestion => + suggestion.startsWith(input) + ); + + filteredSuggestions.forEach(suggestion => { + const suggestionElement = document.createElement("div"); + suggestionElement.className = "suggestion"; + suggestionElement.innerText = suggestion; + suggestionsContainer.appendChild(suggestionElement); }); } diff --git a/admin_board_view/static/AdminBoardView/styles.css b/admin_board_view/static/AdminBoardView/styles.css index 3d16992..048b98d 100644 --- a/admin_board_view/static/AdminBoardView/styles.css +++ b/admin_board_view/static/AdminBoardView/styles.css @@ -47,6 +47,29 @@ a { text-decoration: none; } +.autocomplete-suggestions { + border: 1px solid #ccc; + max-height: 150px; + overflow-y: auto; + position: absolute; + background-color: white; + z-index: 1000; + width: calc(100% - 2px); +} + +.suggestion { + padding: 1%; + cursor: pointer; +} + +.suggestion:hover { + background-color: #e0e0e0; +} +.suggestion-active { + /*when navigating through the items using the arrow keys:*/ + background-color: DodgerBlue !important; + color: #ffffff; +} .pagination { width: fit-content; @@ -65,3 +88,4 @@ a { /* Margin to make sure it's properly aligned: (50-16)/2 */ margin: 17px; } + diff --git a/admin_board_view/templates/products.html b/admin_board_view/templates/products.html index bfbd8ea..9488e7a 100644 --- a/admin_board_view/templates/products.html +++ b/admin_board_view/templates/products.html @@ -10,6 +10,7 @@

Products

+

From eeb362a9654d206f2a4c8fae4e0fac5ab6bac68a Mon Sep 17 00:00:00 2001 From: DarkWargs Date: Mon, 17 Jun 2024 21:49:58 +0200 Subject: [PATCH 4/8] Finished autocomplete bar --- .../static/AdminBoardView/products.js | 180 +++++++++++------- admin_board_view/urls.py | 1 + admin_board_view/views.py | 4 + 3 files changed, 114 insertions(+), 71 deletions(-) diff --git a/admin_board_view/static/AdminBoardView/products.js b/admin_board_view/static/AdminBoardView/products.js index 8c48746..0f2cc28 100644 --- a/admin_board_view/static/AdminBoardView/products.js +++ b/admin_board_view/static/AdminBoardView/products.js @@ -54,83 +54,148 @@ function delete_product(id) { const filterInput = document.getElementById("filter-products"); const suggestionsContainer = document.getElementById("autocomplete-suggestions"); -// Sample categories and statuses for demonstration purposes -const categories = ["electronics", "furniture", "clothing", "books"]; +// console.log($.getJSON({ +// url: '/product/category', // URL to your Django view +// data: { +// "csrfmiddlewaretoken": csrf_token, +// } +// }) +// ) +let categories = [] +fetch('/product/category', { data: { csrfmiddlewaretoken: csrf_token } }) + .then(response => response.json()) + .then(data => categories = data.map(cat => cat.toLowerCase())) + const statuses = ["active", "inactive"]; +// fetch('/product/category_json').then(response => categories = response.json()) + +let currFocus = -1; if (filterInput) { - filterInput.addEventListener("keyup", e => { - const filterString = filterInput.value.toLowerCase(); + filterInput.addEventListener("input", e => { + // console.log(e.key); + const filterString = filterInput.value.toLowerCase(); + suggestions = suggestionsContainer.getElementsByTagName("div") + cursorPos = filterInput.selectionStart + if(e.key != "Enter"){ - cursorPos = filterInput.selectionStart + //Get last word before cursor position const lastWord = filterString.slice(0,cursorPos).split(" ").pop(); + console.log(lastWord, cursorPos); suggestionsContainer.innerHTML = ''; - + if (lastWord.startsWith("category:")) { showSuggestions(categories, lastWord.replace("category:", "").trim()); } else if (lastWord.startsWith("status:")) { showSuggestions(statuses, lastWord.replace("status:", "").trim()); } } + //On submit else { - const filters = getFilters(filterString); - const products = document.getElementsByClassName("product-row"); - Array.from(products).forEach(product => { - const name = product.querySelector(".product-name").innerHTML.toLowerCase(); - const category = product.querySelector(".product-category").innerHTML.toLowerCase(); - const active = product.getAttribute("data-status").toLowerCase(); - - let activeFilter = ""; - if (active == "true") activeFilter = "active"; - if (active == "false") activeFilter = "inactive"; - - // Only filter by criteria if they are specified (non-empty) - const nameMatches = !filters.name || name.includes(filters.name); - const categoryMatches = !filters.category || category.includes(filters.category); - const statusMatches = !filters.status || activeFilter == filters.status; - - if (nameMatches && categoryMatches && statusMatches) { - product.style.display = ""; - } else { - product.style.display = "none"; - } - }); + } }); + filterInput.addEventListener("keydown", e => { + const filterString = filterInput.value.toLowerCase(); + if(e.key == "ArrowDown"){ + e.preventDefault(); + currFocus++; + addActive(suggestions) + } else if(e.key == "ArrowUp"){ + e.preventDefault(); + currFocus--; + addActive(suggestions) + } else if (e.key === "Enter") { + if(currFocus > -1 && suggestions.length > 0){ + suggestions[currFocus].click(); + } + showFilters(filterString); + } + return false; + }) + + //Finish word when element is pressed suggestionsContainer.addEventListener("click", e => { if (e.target && e.target.matches("div.suggestion")) { + //Split on cursor position firstPart = filterInput.value.slice(0,filterInput.selectionStart) lastPart = filterInput.value.slice(filterInput.selectionStart) + //Trim to last colon and combine firstPart = firstPart.slice(0,firstPart.lastIndexOf(':')+1) filterInput.value = firstPart + e.target.innerText + lastPart suggestionsContainer.innerHTML = ''; + currFocus = -1; } }); + function addActive(suggestions) { + if (!suggestions || suggestions.length == 0) return false; + removeActive(suggestions); + if (currFocus >= suggestions.length) currFocus = 0; + if (currFocus < 0) currFocus = (suggestions.length - 1); + suggestions[currFocus].classList.add("suggestion-active"); + } + + function removeActive(suggestions) { + for (var i = 0; i < suggestions.length; i++) { + suggestions[i].classList.remove("suggestion-active"); + } + } } -function getFilters(filterString) { - const strings = filterString.split(" "); - const filters = { +//Hide all elements not matching filter +function showFilters(filterString){ + const filters = getFilters(filterString); + const products = document.getElementsByClassName("product-row"); + Array.from(products).forEach(product => { + //Get product properties + const name = product.querySelector(".product-name").innerHTML.toLowerCase(); + const category = product.querySelector(".product-category").innerHTML.toLowerCase(); + const active = product.getAttribute("data-status").toLowerCase(); + + //Convert bool to activity string + let activeFilter = ""; + if (active == "true") activeFilter = "active"; + if (active == "false") activeFilter = "inactive"; + + // Only filter by criteria if they are specified (non-empty) + const nameMatches = !filters.name || name.includes(filters.name); + const categoryMatches = !filters.category || category.includes(filters.category); + const statusMatches = !filters.status || activeFilter == filters.status; + + if (nameMatches && categoryMatches && statusMatches) { + product.style.display = ""; + } else { + product.style.display = "none"; + } + }) + + //Turn filter string into filter object + function getFilters(filterString) { + + const strings = filterString.split(" "); + const filters = { category: "", status: "", name: "" - }; - - strings.forEach(string => { - let [type, value] = string.toLowerCase().split(":"); - if (value != undefined) { - if (filters.hasOwnProperty(type)) { - filters[type] = value; + }; + + //Check if filter exists then assign value in object + strings.forEach(string => { + let [type, value] = string.toLowerCase().split(":"); + if (value != undefined) { + if (filters.hasOwnProperty(type)) { + filters[type] = value; + } + } else { + filters.name += type + " "; } - } else { - filters.name += type + " "; - } - }); + }); - filters.name = filters.name.trim(); // Remove trailing space - return filters; + filters.name = filters.name.trim(); // Remove trailing space + return filters; + } } function showSuggestions(suggestions, input) { @@ -146,33 +211,6 @@ function showSuggestions(suggestions, input) { }); } -function getFilters(filter_string) -{ - strings = filter_string.split(" "); - filters = { - "category" : "", - "status" : "", - "name" : "" - } - - strings.forEach(string => { - let [type, value] = string.toLowerCase().split(":") - //If type is specified - if(value != undefined){ - if(filters.hasOwnProperty(type)){ - filters[type] = value - } - } - //Add to name search if no type is specified - else{ - filters["name"] += type + " " - } - } - ) - filters.name = filters.name.trim(); // Remove trailing space - return filters //Return dictionary of filters -} - const params = new URLSearchParams(window.location.search); if (params.get("edit")) { productModal.show() diff --git a/admin_board_view/urls.py b/admin_board_view/urls.py index 199464a..037ecc7 100644 --- a/admin_board_view/urls.py +++ b/admin_board_view/urls.py @@ -14,6 +14,7 @@ path('product/toggle', views.toggle, name='toggle'), path('product/delete', views.delete, name='delete'), + path('product/category', views.categories_json, name='category_json'), path('category/edit', views.category, name='category'), path('vat/edit', views.vat, name='vat'), diff --git a/admin_board_view/views.py b/admin_board_view/views.py index e9b8bd4..16b9a7f 100644 --- a/admin_board_view/views.py +++ b/admin_board_view/views.py @@ -70,6 +70,10 @@ def products(request): categories = Category.objects.all() return render(request, "products.html", { "products": products, "categories": categories, "product_form": pf, "current_product": product, "product_sales": product_sales }) +@dashboard_admin +def categories_json(request): + categories = list(Category.objects.values_list('name', flat=True)) + return JsonResponse(categories, safe=False) @dashboard_admin def delete(request): From 932fea28c2afeeb9658ff85377a2b022d9f60852 Mon Sep 17 00:00:00 2001 From: DarkWargs Date: Tue, 18 Jun 2024 19:47:56 +0200 Subject: [PATCH 5/8] Added comments and removed commented code --- .../static/AdminBoardView/products.js | 26 ++++++------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/admin_board_view/static/AdminBoardView/products.js b/admin_board_view/static/AdminBoardView/products.js index 0f2cc28..a22580b 100644 --- a/admin_board_view/static/AdminBoardView/products.js +++ b/admin_board_view/static/AdminBoardView/products.js @@ -54,21 +54,13 @@ function delete_product(id) { const filterInput = document.getElementById("filter-products"); const suggestionsContainer = document.getElementById("autocomplete-suggestions"); -// console.log($.getJSON({ -// url: '/product/category', // URL to your Django view -// data: { -// "csrfmiddlewaretoken": csrf_token, -// } -// }) -// ) +//Define suggestions let categories = [] fetch('/product/category', { data: { csrfmiddlewaretoken: csrf_token } }) .then(response => response.json()) .then(data => categories = data.map(cat => cat.toLowerCase())) const statuses = ["active", "inactive"]; -// fetch('/product/category_json').then(response => categories = response.json()) - let currFocus = -1; if (filterInput) { @@ -77,9 +69,9 @@ if (filterInput) { const filterString = filterInput.value.toLowerCase(); suggestions = suggestionsContainer.getElementsByTagName("div") cursorPos = filterInput.selectionStart - + + //Change suggestions based on input keys if(e.key != "Enter"){ - //Get last word before cursor position const lastWord = filterString.slice(0,cursorPos).split(" ").pop(); console.log(lastWord, cursorPos); @@ -91,12 +83,9 @@ if (filterInput) { showSuggestions(statuses, lastWord.replace("status:", "").trim()); } } - //On submit - else { - - } }); + //Adjust autocomplete focus and submit filterInput.addEventListener("keydown", e => { const filterString = filterInput.value.toLowerCase(); if(e.key == "ArrowDown"){ @@ -116,7 +105,7 @@ if (filterInput) { return false; }) - //Finish word when element is pressed + //Finish word when suggestion is pressed suggestionsContainer.addEventListener("click", e => { if (e.target && e.target.matches("div.suggestion")) { //Split on cursor position @@ -149,6 +138,7 @@ function showFilters(filterString){ const filters = getFilters(filterString); const products = document.getElementsByClassName("product-row"); Array.from(products).forEach(product => { + //Get product properties const name = product.querySelector(".product-name").innerHTML.toLowerCase(); const category = product.querySelector(".product-category").innerHTML.toLowerCase(); @@ -192,8 +182,8 @@ function showFilters(filterString){ filters.name += type + " "; } }); - - filters.name = filters.name.trim(); // Remove trailing space + // Remove trailing space + filters.name = filters.name.trim(); return filters; } } From cf6d8f8ccfa7697e3642e07881721c24163e0116 Mon Sep 17 00:00:00 2001 From: David <105985369+DavidVanDeursen@users.noreply.github.com> Date: Wed, 11 Sep 2024 22:35:49 +0200 Subject: [PATCH 6/8] shortened if statement to ternary Co-authored-by: Job Vonk --- admin_board_view/static/AdminBoardView/products.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/admin_board_view/static/AdminBoardView/products.js b/admin_board_view/static/AdminBoardView/products.js index a22580b..e68fe65 100644 --- a/admin_board_view/static/AdminBoardView/products.js +++ b/admin_board_view/static/AdminBoardView/products.js @@ -145,9 +145,7 @@ function showFilters(filterString){ const active = product.getAttribute("data-status").toLowerCase(); //Convert bool to activity string - let activeFilter = ""; - if (active == "true") activeFilter = "active"; - if (active == "false") activeFilter = "inactive"; + const activeFilter = active === "true" ? "active" : "inactive"; // Only filter by criteria if they are specified (non-empty) const nameMatches = !filters.name || name.includes(filters.name); From ecfa30675dd4b4f3ce867fe6bca2935f42684935 Mon Sep 17 00:00:00 2001 From: David <105985369+DavidVanDeursen@users.noreply.github.com> Date: Wed, 11 Sep 2024 22:36:06 +0200 Subject: [PATCH 7/8] shortened if statement to ternary Co-authored-by: Job Vonk --- admin_board_view/static/AdminBoardView/products.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/admin_board_view/static/AdminBoardView/products.js b/admin_board_view/static/AdminBoardView/products.js index e68fe65..19f17cc 100644 --- a/admin_board_view/static/AdminBoardView/products.js +++ b/admin_board_view/static/AdminBoardView/products.js @@ -152,11 +152,9 @@ function showFilters(filterString){ const categoryMatches = !filters.category || category.includes(filters.category); const statusMatches = !filters.status || activeFilter == filters.status; - if (nameMatches && categoryMatches && statusMatches) { - product.style.display = ""; - } else { - product.style.display = "none"; - } + product.style.display = nameMatches && categoryMatches && statusMatches + ? "" + : "none"; }) //Turn filter string into filter object From b7900c5a28648f7ad25e76f3365147d08aa3aae6 Mon Sep 17 00:00:00 2001 From: DarkWargs Date: Tue, 17 Sep 2024 18:17:39 +0200 Subject: [PATCH 8/8] Refactored getFilters function, renamed addActive function and added comments --- .../static/AdminBoardView/products.js | 41 +++++++++---------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/admin_board_view/static/AdminBoardView/products.js b/admin_board_view/static/AdminBoardView/products.js index 19f17cc..4e68af0 100644 --- a/admin_board_view/static/AdminBoardView/products.js +++ b/admin_board_view/static/AdminBoardView/products.js @@ -74,7 +74,6 @@ if (filterInput) { if(e.key != "Enter"){ //Get last word before cursor position const lastWord = filterString.slice(0,cursorPos).split(" ").pop(); - console.log(lastWord, cursorPos); suggestionsContainer.innerHTML = ''; if (lastWord.startsWith("category:")) { @@ -91,11 +90,11 @@ if (filterInput) { if(e.key == "ArrowDown"){ e.preventDefault(); currFocus++; - addActive(suggestions) + highlightFocussed(suggestions) } else if(e.key == "ArrowUp"){ e.preventDefault(); currFocus--; - addActive(suggestions) + highlightFocussed(suggestions) } else if (e.key === "Enter") { if(currFocus > -1 && suggestions.length > 0){ suggestions[currFocus].click(); @@ -118,15 +117,18 @@ if (filterInput) { currFocus = -1; } }); - function addActive(suggestions) { + //Add highlight to the active suggestion + function highlightFocussed(suggestions) { if (!suggestions || suggestions.length == 0) return false; - removeActive(suggestions); + + //Clear all highlights and highlight the focussed + removeAllHighlights(suggestions); if (currFocus >= suggestions.length) currFocus = 0; if (currFocus < 0) currFocus = (suggestions.length - 1); suggestions[currFocus].classList.add("suggestion-active"); } - function removeActive(suggestions) { + function removeAllHighlights(suggestions) { for (var i = 0; i < suggestions.length; i++) { suggestions[i].classList.remove("suggestion-active"); } @@ -135,7 +137,7 @@ if (filterInput) { //Hide all elements not matching filter function showFilters(filterString){ - const filters = getFilters(filterString); + const [searchTerm, filters] = getFilters(filterString); const products = document.getElementsByClassName("product-row"); Array.from(products).forEach(product => { @@ -148,7 +150,7 @@ function showFilters(filterString){ const activeFilter = active === "true" ? "active" : "inactive"; // Only filter by criteria if they are specified (non-empty) - const nameMatches = !filters.name || name.includes(filters.name); + const nameMatches = name.includes(searchTerm); const categoryMatches = !filters.category || category.includes(filters.category); const statusMatches = !filters.status || activeFilter == filters.status; @@ -159,32 +161,27 @@ function showFilters(filterString){ //Turn filter string into filter object function getFilters(filterString) { - + const filterNames = ["category", "status"] const strings = filterString.split(" "); - const filters = { - category: "", - status: "", - name: "" - }; + const filters = {}; + const searchTerm = []; //Check if filter exists then assign value in object strings.forEach(string => { - let [type, value] = string.toLowerCase().split(":"); - if (value != undefined) { - if (filters.hasOwnProperty(type)) { + const [type, value] = string.toLowerCase().split(":"); + if (value && filterNames.includes(type)) { filters[type] = value; - } } else { - filters.name += type + " "; + searchTerm.push(string); } }); - // Remove trailing space - filters.name = filters.name.trim(); - return filters; + return [searchTerm.join(" ").trim(), filters]; } } +//Add divs for each suggestion to the suggestionContainer function showSuggestions(suggestions, input) { + //Get list of suggestions that match input so far const filteredSuggestions = suggestions.filter(suggestion => suggestion.startsWith(input) );