From 4cf7c9fa4970767f18f29b53f7ddf67549f70ce5 Mon Sep 17 00:00:00 2001 From: Giorgio Ravera Date: Tue, 26 May 2026 23:34:33 +0200 Subject: [PATCH] restored filter based on html field --- frontend/js/aliases.js | 105 +++++++++++++++++++++++------------------ frontend/js/common.js | 5 +- frontend/js/devices.js | 97 +++++++++++++++++++++---------------- frontend/js/hosts.js | 92 +++++++++++++++++++++--------------- frontend/js/leases.js | 92 +++++++++++++++++++++--------------- 5 files changed, 224 insertions(+), 167 deletions(-) diff --git a/frontend/js/aliases.js b/frontend/js/aliases.js index a01dca6..2488b2b 100644 --- a/frontend/js/aliases.js +++ b/frontend/js/aliases.js @@ -1,12 +1,13 @@ // Import common js -import { loadModals, showToast, sortTable, initSortableTable, resetSorting, filterData, clearSearch } from './common.js'; +import { loadModals, showToast, sortTable, initSortableTable, resetSorting, filterTable, clearSearch } from './common.js'; import { reloadDNS, reloadDHCP } from './services.js'; import { apiMap, fetchData } from './api.js'; // ----------------------------- // State variables // ----------------------------- -let aliasesList = []; +let allAliases = []; +let viewAliases = []; let editingAliasId = null; const sortState = { sortDirection: {}, lastSort: null }; @@ -15,7 +16,6 @@ const sortState = { sortDirection: {}, lastSort: null }; // ----------------------------- async function fetchAliases () { const loader = document.getElementById("loader"); - const container = document.getElementById("devices-container"); const dataTable = document.getElementById("dataTable"); // hide table during loading to avoid flickering and show loader @@ -26,22 +26,26 @@ async function fetchAliases () { loader.style.display = "block"; // Fetch aliases - aliasesList = await fetchData(apiMap.aliases); + allAliases = await fetchData(apiMap.aliases); + viewAliases = [...allAliases]; } catch (err) { - console.error(err?.message || "Error loading aliases"); - showToast(err?.message || "Error loading aliase", false); - aliasesList = []; - // hide loader and show table - loader.style.display = "none"; - dataTable.classList.remove("d-none"); + console.error(err?.message || "Error loading aliases"); + showToast(err?.message || "Error loading aliase", false); + allAliases = []; + viewAliases = []; + // hide loader and show table + loader.style.display = "none"; + dataTable.classList.remove("d-none"); } } // ----------------------------- -// Update table with current hosts +// Update table with current aliases // ----------------------------- function updateTable () { + const loader = document.getElementById("loader"); + const dataTable = document.getElementById("dataTable"); // DOM Reference const tbody = document.querySelector("#dataTable tbody"); @@ -54,7 +58,7 @@ function updateTable () { tbody.innerHTML = ""; // if no aliases, show an empty row - if (!aliasesList.length) { + if (!viewAliases.length) { const trEmpty = document.createElement("tr"); const tdEmpty = document.createElement("td"); tdEmpty.colSpan = 7; @@ -71,7 +75,7 @@ function updateTable () { // fragment per performance const frag = document.createDocumentFragment(); - aliasesList.forEach(h => { + viewAliases.forEach(h => { const id = Number(h.id); const tr = document.createElement("tr"); @@ -215,16 +219,25 @@ function updateTable () { tbody.appendChild(frag); // apply last sorting - if (typeof lastSort === "object" && lastSort && Array.isArray(sortDirection)) { - if (Number.isInteger(lastSort.colIndex)) { - sortDirection[lastSort.colIndex] = !lastSort.ascending; - sortTable(lastSort.colIndex, sortState); - } + const { lastSort, sortDirection } = sortState; + + if (lastSort && Number.isInteger(lastSort.colIndex)) { + sortDirection[lastSort.colIndex] = !lastSort.ascending; + sortTable(lastSort.colIndex, sortState); } // hide loader and show table loader.style.display = "none"; dataTable.classList.remove("d-none"); + + // apply current search filter + const searchInput = document.getElementById("searchInput"); + if (searchInput) { + const term = searchInput.value.trim().toLowerCase(); + if (term) { + filterTable(term); + } + } } // ----------------------------- @@ -428,6 +441,7 @@ async function handleAddAliasSubmit(e) { // close modal and reload aliases closeAddAliasModal(); await loadAliases(); + updateTable(); return true } @@ -595,17 +609,9 @@ function initSearch() { // clean input on load input.value = ""; // live filter for each keystroke - input.addEventListener("input", filterData); - // Escape management when focus is in the input - input.addEventListener("keydown", (e) => { - if (e.key === "Escape") { - e.preventDefault(); // evita side-effect (es. chiusure di modali del browser) - e.stopPropagation(); // evita che arrivi al listener globale - resetSorting(sortState); - clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione) - updateTable(); // aggiorna tabella - filterData(''); // ripristina tabella - } + input.addEventListener("input", (e) => { + const term = e.target.value.trim().toLowerCase(); + filterTable(term); }); } @@ -700,26 +706,35 @@ async function handleActionClick(e) { // KEYBOARD (ESC + accessibility) // ----------------------------- function handleKeyboard(e) { - // Ignore if focus is in a typing field - const tag = (e.target.tagName || "").toLowerCase(); - const isTypingField = - tag === "input" || tag === "textarea" || tag === "select" || e.target.isContentEditable; - - // global ESC key listener to clear search and reset sorting - if (e.key === "Escape" && !isTypingField) { - // Prevent default form submission - e.preventDefault(); // evita side-effect (es. chiusure di modali del browser) - resetSorting(sortState); - clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione) - updateTable(); // aggiorna tabella - filterData(''); // ripristina tabella - } - // Button event delegation (Enter, Space) + // Button event delegation (Escape, Enter, Space) + const isEscape = e.key === 'Escape'; const isEnter = e.key === 'Enter'; const isSpace = e.key === ' '; - if (!isEnter && !isSpace) return; + if (!isEscape && !isEnter && !isSpace) return; + + // ESC delegation: clear search and reset sorting + if (isEscape) { + // Ignore if focus is in a typing field + const tag = (e.target.tagName || "").toLowerCase(); + const isTypingField = + tag === "input" || tag === "textarea" || tag === "select" || e.target.isContentEditable; + const isSearchInput = e.target.id === "searchInput"; + + // ESC should clear search and reset sorting only if not focused on a typing field, or if focused on the search input (to allow quick clearing of search) + if (!isTypingField || isSearchInput) { + // Prevent default form submission + e.preventDefault(); // evita side-effect (es. chiusure di modali del browser) + resetSorting(sortState); + clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione) + viewAliases = [...allAliases]; + updateTable(); // aggiorna tabella + } + return; + } + + // Enter / Space delegation const el = e.target.closest('[data-action]'); if (!el) return; diff --git a/frontend/js/common.js b/frontend/js/common.js index ae2f0bf..63b4758 100644 --- a/frontend/js/common.js +++ b/frontend/js/common.js @@ -332,13 +332,12 @@ export function initSortableTable() { /** * Live filter: mostra solo le righe che contengono il testo di ricerca (case-insensitive) */ -export function filterData() { - const query = document.getElementById("searchInput").value.toLowerCase(); +export function filterTable(term) { const rows = document.querySelectorAll("#dataTable tbody tr"); rows.forEach(row => { const text = row.textContent.toLowerCase(); - row.style.display = text.includes(query) ? "" : "none"; + row.style.display = text.includes(term) ? "" : "none"; }); } diff --git a/frontend/js/devices.js b/frontend/js/devices.js index fbde4ac..edf65f0 100644 --- a/frontend/js/devices.js +++ b/frontend/js/devices.js @@ -1,12 +1,13 @@ // Import common js -import { loadModals, isValidIPv4, isValidIPv6, isValidMAC, showToast, sortTable, initSortableTable, resetSorting, filterData, clearSearch } from './common.js'; +import { loadModals, isValidIPv4, isValidIPv6, isValidMAC, showToast, sortTable, initSortableTable, resetSorting, filterTable, clearSearch } from './common.js'; import { reloadDNS, reloadDHCP } from './services.js'; import { apiMap, fetchData } from './api.js'; // ----------------------------- // State variables // ----------------------------- -let devicesList = []; +let allDevices = []; +let viewDevices = []; let editingHostId = null; const sortState = { sortDirection: {}, lastSort: null }; @@ -15,7 +16,6 @@ const sortState = { sortDirection: {}, lastSort: null }; // ----------------------------- async function fetchDevices () { const loader = document.getElementById("loader"); - const container = document.getElementById("devices-container"); const dataTable = document.getElementById("dataTable"); // hide table during loading to avoid flickering and show loader @@ -26,12 +26,14 @@ async function fetchDevices () { loader.style.display = "block"; // Fetch devices - devicesList = await fetchData(apiMap.devices); + allDevices = await fetchData(apiMap.devices); + viewDevices = [...allDevices]; } catch (err) { console.error(err?.message || "Error loading devices"); showToast(err?.message || "Error loading devices", false); - devicesList = []; + allDevices = []; + viewDevices = []; // hide loader and show table loader.style.display = "none"; dataTable.classList.remove("d-none"); @@ -42,6 +44,8 @@ async function fetchDevices () { // Update table with current devices // ----------------------------- function updateTable () { + const loader = document.getElementById("loader"); + const dataTable = document.getElementById("dataTable"); // DOM Reference const tbody = document.querySelector("#dataTable tbody"); @@ -54,7 +58,7 @@ function updateTable () { tbody.innerHTML = ""; // if no devices, show an empty row - if (!devicesList.length) { + if (!viewDevices.length) { const trEmpty = document.createElement("tr"); const tdEmpty = document.createElement("td"); tdEmpty.colSpan = 7; @@ -71,7 +75,7 @@ function updateTable () { // fragment per performance const frag = document.createDocumentFragment(); - devicesList.forEach(d => { + viewDevices.forEach(d => { const id = d.id; let type = 0; @@ -259,9 +263,9 @@ function updateTable () { delSpan.appendChild(i); } - if(type == 1) { + if (type === 1) { td.appendChild(editSpan); - } else if (type == 2) { + } else if (type === 2) { td.appendChild(addSpan); } else { } @@ -276,16 +280,25 @@ function updateTable () { tbody.appendChild(frag); // apply last sorting - if (typeof lastSort === "object" && lastSort && Array.isArray(sortDirection)) { - if (Number.isInteger(lastSort.colIndex)) { - sortDirection[lastSort.colIndex] = !lastSort.ascending; - sortTable(lastSort.colIndex, sortState); - } + const { lastSort, sortDirection } = sortState; + + if (lastSort && Number.isInteger(lastSort.colIndex)) { + sortDirection[lastSort.colIndex] = !lastSort.ascending; + sortTable(lastSort.colIndex, sortState); } // hide loader and show table loader.style.display = "none"; dataTable.classList.remove("d-none"); + + // apply current search filter + const searchInput = document.getElementById("searchInput"); + if (searchInput) { + const term = searchInput.value.trim().toLowerCase(); + if (term) { + filterTable(term); + } + } } // ----------------------------- @@ -527,6 +540,7 @@ async function handleAddHostSubmit(e) { // close modal and reload hosts closeAddHostModal(); await loadDevices(); + updateTable(); return true } @@ -710,17 +724,9 @@ function initSearch() { // clean input on load input.value = ""; // live filter for each keystroke - input.addEventListener("input", filterData); - // Escape management when focus is in the input - input.addEventListener("keydown", (e) => { - if (e.key === "Escape") { - e.preventDefault(); // evita side-effect (es. chiusure di modali del browser) - e.stopPropagation(); // evita che arrivi al listener globale - resetSorting(sortState); - clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione) - updateTable(); // aggiorna tabella - filterData(''); // ripristina tabella - } + input.addEventListener("input", (e) => { + const term = e.target.value.trim().toLowerCase(); + filterTable(term); }); } @@ -815,26 +821,35 @@ async function handleActionClick(e) { // KEYBOARD (ESC + accessibility) // ----------------------------- function handleKeyboard(e) { - // Ignore if focus is in a typing field - const tag = (e.target.tagName || "").toLowerCase(); - const isTypingField = - tag === "input" || tag === "textarea" || tag === "select" || e.target.isContentEditable; - - // global ESC key listener to clear search and reset sorting - if (e.key === "Escape" && !isTypingField) { - // Prevent default form submission - e.preventDefault(); // evita side-effect (es. chiusure di modali del browser) - resetSorting(sortState); - clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione) - updateTable(); // aggiorna tabella - filterData(''); // ripristina tabella - } - // Button event delegation (Enter, Space) + // Button event delegation (Escape, Enter, Space) + const isEscape = e.key === 'Escape'; const isEnter = e.key === 'Enter'; const isSpace = e.key === ' '; - if (!isEnter && !isSpace) return; + if (!isEscape && !isEnter && !isSpace) return; + + // ESC delegation: clear search and reset sorting + if (isEscape) { + // Ignore if focus is in a typing field + const tag = (e.target.tagName || "").toLowerCase(); + const isTypingField = + tag === "input" || tag === "textarea" || tag === "select" || e.target.isContentEditable; + const isSearchInput = e.target.id === "searchInput"; + + // ESC should clear search and reset sorting only if not focused on a typing field, or if focused on the search input (to allow quick clearing of search) + if (!isTypingField || isSearchInput) { + // Prevent default form submission + e.preventDefault(); // evita side-effect (es. chiusure di modali del browser) + resetSorting(sortState); + clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione) + viewDevices = [...allDevices]; + updateTable(); // aggiorna tabella + } + return; + } + + // Enter / Space delegation const el = e.target.closest('[data-action]'); if (!el) return; diff --git a/frontend/js/hosts.js b/frontend/js/hosts.js index acb2d46..364590e 100644 --- a/frontend/js/hosts.js +++ b/frontend/js/hosts.js @@ -1,12 +1,13 @@ // Import common js -import { loadModals, isValidIPv4, isValidIPv6, isValidMAC, showToast, sortTable, initSortableTable, resetSorting, filterData, clearSearch } from './common.js'; +import { loadModals, isValidIPv4, isValidIPv6, isValidMAC, showToast, sortTable, initSortableTable, resetSorting, filterTable, clearSearch } from './common.js'; import { reloadDNS, reloadDHCP } from './services.js'; import { apiMap, fetchData } from './api.js'; // ----------------------------- // State variables // ----------------------------- -let hostsList = []; +let allHosts = []; +let viewHosts = []; let editingHostId = null; const sortState = { sortDirection: {}, lastSort: null }; @@ -15,7 +16,6 @@ const sortState = { sortDirection: {}, lastSort: null }; // ----------------------------- async function fetchHosts () { const loader = document.getElementById("loader"); - const container = document.getElementById("devices-container"); const dataTable = document.getElementById("dataTable"); // hide table during loading to avoid flickering and show loader @@ -26,12 +26,14 @@ async function fetchHosts () { loader.style.display = "block"; // Fetch hosts - hostsList = await fetchData(apiMap.hosts); + allHosts = await fetchData(apiMap.hosts); + viewHosts = [...allHosts]; } catch (err) { console.error(err?.message || "Error loading hosts"); showToast(err?.message || "Error loading hosts", false); - hostsList = []; + allHosts = []; + viewHosts = []; // hide loader and show table loader.style.display = "none"; dataTable.classList.remove("d-none"); @@ -42,6 +44,8 @@ async function fetchHosts () { // Update table with current hosts // ----------------------------- function updateTable () { + const loader = document.getElementById("loader"); + const dataTable = document.getElementById("dataTable"); // DOM Reference const tbody = document.querySelector("#dataTable tbody"); @@ -54,7 +58,7 @@ function updateTable () { tbody.innerHTML = ""; // if no hosts, show an empty row - if (!hostsList.length) { + if (!viewHosts.length) { const trEmpty = document.createElement("tr"); const tdEmpty = document.createElement("td"); tdEmpty.colSpan = 7; @@ -71,7 +75,7 @@ function updateTable () { // fragment per performance const frag = document.createDocumentFragment(); - hostsList.forEach(h => { + viewHosts.forEach(h => { const id = Number(h.id); const tr = document.createElement("tr"); @@ -225,16 +229,25 @@ function updateTable () { tbody.appendChild(frag); // apply last sorting - if (typeof lastSort === "object" && lastSort && Array.isArray(sortDirection)) { - if (Number.isInteger(lastSort.colIndex)) { - sortDirection[lastSort.colIndex] = !lastSort.ascending; - sortTable(lastSort.colIndex, sortState); - } + const { lastSort, sortDirection } = sortState; + + if (lastSort && Number.isInteger(lastSort.colIndex)) { + sortDirection[lastSort.colIndex] = !lastSort.ascending; + sortTable(lastSort.colIndex, sortState); } // hide loader and show table loader.style.display = "none"; dataTable.classList.remove("d-none"); + + // apply current search filter + const searchInput = document.getElementById("searchInput"); + if (searchInput) { + const term = searchInput.value.trim().toLowerCase(); + if (term) { + filterTable(term); + } + } } // ----------------------------- @@ -620,17 +633,9 @@ function initSearch() { // clean input on load input.value = ""; // live filter for each keystroke - input.addEventListener("input", filterData); - // Escape management when focus is in the input - input.addEventListener("keydown", (e) => { - if (e.key === "Escape") { - e.preventDefault(); // evita side-effect (es. chiusure di modali del browser) - e.stopPropagation(); // evita che arrivi al listener globale - resetSorting(sortState); - clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione) - updateTable(); // aggiorna tabella - filterData(''); // ripristina tabella - } + input.addEventListener("input", (e) => { + const term = e.target.value.trim().toLowerCase(); + filterTable(term); }); } @@ -725,26 +730,35 @@ async function handleActionClick(e) { // KEYBOARD (ESC + accessibility) // ----------------------------- function handleKeyboard(e) { - // Ignore if focus is in a typing field - const tag = (e.target.tagName || "").toLowerCase(); - const isTypingField = - tag === "input" || tag === "textarea" || tag === "select" || e.target.isContentEditable; - - // global ESC key listener to clear search and reset sorting - if (e.key === "Escape" && !isTypingField) { - // Prevent default form submission - e.preventDefault(); // evita side-effect (es. chiusure di modali del browser) - resetSorting(sortState); - clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione) - updateTable(); // aggiorna tabella - filterData(''); // ripristina tabella - } - // Button event delegation (Enter, Space) + // Button event delegation (Escape, Enter, Space) + const isEscape = e.key === 'Escape'; const isEnter = e.key === 'Enter'; const isSpace = e.key === ' '; - if (!isEnter && !isSpace) return; + if (!isEscape && !isEnter && !isSpace) return; + + // ESC delegation: clear search and reset sorting + if (isEscape) { + // Ignore if focus is in a typing field + const tag = (e.target.tagName || "").toLowerCase(); + const isTypingField = + tag === "input" || tag === "textarea" || tag === "select" || e.target.isContentEditable; + const isSearchInput = e.target.id === "searchInput"; + + // ESC should clear search and reset sorting only if not focused on a typing field, or if focused on the search input (to allow quick clearing of search) + if (!isTypingField || isSearchInput) { + // Prevent default form submission + e.preventDefault(); // evita side-effect (es. chiusure di modali del browser) + resetSorting(sortState); + clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione) + viewHosts = [...allHosts]; + updateTable(); // aggiorna tabella + } + return; + } + + // Enter / Space delegation const el = e.target.closest('[data-action]'); if (!el) return; diff --git a/frontend/js/leases.js b/frontend/js/leases.js index c4d28e4..51ed645 100644 --- a/frontend/js/leases.js +++ b/frontend/js/leases.js @@ -1,12 +1,13 @@ // Import common js -import { loadModals, isValidIPv4, isValidIPv6, isValidMAC, showToast, sortTable, initSortableTable, resetSorting, filterData, clearSearch } from './common.js'; +import { loadModals, isValidIPv4, isValidIPv6, isValidMAC, showToast, sortTable, initSortableTable, resetSorting, filterTable, clearSearch } from './common.js'; import { reloadDNS, reloadDHCP } from './services.js'; import { apiMap, fetchData } from './api.js'; // ----------------------------- // State variables // ----------------------------- -let leasesList = []; +let allLeases = []; +let viewLeases = []; const sortState = { sortDirection: {}, lastSort: null }; // ----------------------------- @@ -14,7 +15,6 @@ const sortState = { sortDirection: {}, lastSort: null }; // ----------------------------- async function fetchLeases () { const loader = document.getElementById("loader"); - const container = document.getElementById("devices-container"); const dataTable = document.getElementById("dataTable"); // hide table during loading to avoid flickering and show loader @@ -25,12 +25,14 @@ async function fetchLeases () { loader.style.display = "block"; // Fetch leases - leasesList = await fetchData(apiMap.leases); + allLeases = await fetchData(apiMap.leases); + viewLeases = [...allLeases]; } catch (err) { console.error(err?.message || "Error loading leases"); showToast(err?.message || "Error loading leases", false); - leasesList = []; + allLeases = []; + viewLeases = []; // hide loader and show table loader.style.display = "none"; dataTable.classList.remove("d-none"); @@ -41,6 +43,8 @@ async function fetchLeases () { // Update table with current hosts // ----------------------------- function updateTable () { + const loader = document.getElementById("loader"); + const dataTable = document.getElementById("dataTable"); // DOM Reference const tbody = document.querySelector("#dataTable tbody"); @@ -53,7 +57,7 @@ function updateTable () { tbody.innerHTML = ""; // if no leases, show an empty row - if (!leasesList.length) { + if (!viewLeases.length) { const trEmpty = document.createElement("tr"); const tdEmpty = document.createElement("td"); tdEmpty.colSpan = 7; @@ -70,7 +74,7 @@ function updateTable () { // fragment per performance const frag = document.createDocumentFragment(); - leasesList.forEach(l => { + viewLeases.forEach(l => { const id = Number(l.id); const tr = document.createElement("tr"); @@ -240,16 +244,25 @@ function updateTable () { tbody.appendChild(frag); // apply last sorting - if (typeof lastSort === "object" && lastSort && Array.isArray(sortDirection)) { - if (Number.isInteger(lastSort.colIndex)) { - sortDirection[lastSort.colIndex] = !lastSort.ascending; - sortTable(lastSort.colIndex, sortState); - } + const { lastSort, sortDirection } = sortState; + + if (lastSort && Number.isInteger(lastSort.colIndex)) { + sortDirection[lastSort.colIndex] = !lastSort.ascending; + sortTable(lastSort.colIndex, sortState); } // hide loader and show table loader.style.display = "none"; dataTable.classList.remove("d-none"); + + // apply current search filter + const searchInput = document.getElementById("searchInput"); + if (searchInput) { + const term = searchInput.value.trim().toLowerCase(); + if (term) { + filterTable(term); + } + } } // ----------------------------- @@ -584,17 +597,9 @@ function initSearch() { // clean input on load input.value = ""; // live filter for each keystroke - input.addEventListener("input", filterData); - // Escape management when focus is in the input - input.addEventListener("keydown", (e) => { - if (e.key === "Escape") { - e.preventDefault(); // evita side-effect (es. chiusure di modali del browser) - e.stopPropagation(); // evita che arrivi al listener globale - resetSorting(sortState); - clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione) - updateTable(); // aggiorna tabella - filterData(''); // ripristina tabella - } + input.addEventListener("input", (e) => { + const term = e.target.value.trim().toLowerCase(); + filterTable(term); }); } @@ -681,26 +686,35 @@ async function handleActionClick(e) { // KEYBOARD (ESC + accessibility) // ----------------------------- function handleKeyboard(e) { - // Ignore if focus is in a typing field - const tag = (e.target.tagName || "").toLowerCase(); - const isTypingField = - tag === "input" || tag === "textarea" || tag === "select" || e.target.isContentEditable; - - // global ESC key listener to clear search and reset sorting - if (e.key === "Escape" && !isTypingField) { - // Prevent default form submission - e.preventDefault(); // evita side-effect (es. chiusure di modali del browser) - resetSorting(sortState); - clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione) - updateTable(); // aggiorna tabella - filterData(''); // ripristina tabella - } - // Button event delegation (Enter, Space) + // Button event delegation (Escape, Enter, Space) + const isEscape = e.key === 'Escape'; const isEnter = e.key === 'Enter'; const isSpace = e.key === ' '; - if (!isEnter && !isSpace) return; + if (!isEscape && !isEnter && !isSpace) return; + + // ESC delegation: clear search and reset sorting + if (isEscape) { + // Ignore if focus is in a typing field + const tag = (e.target.tagName || "").toLowerCase(); + const isTypingField = + tag === "input" || tag === "textarea" || tag === "select" || e.target.isContentEditable; + const isSearchInput = e.target.id === "searchInput"; + + // ESC should clear search and reset sorting only if not focused on a typing field, or if focused on the search input (to allow quick clearing of search) + if (!isTypingField || isSearchInput) { + // Prevent default form submission + e.preventDefault(); // evita side-effect (es. chiusure di modali del browser) + resetSorting(sortState); + clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione) + viewLeases = [...allLeases]; + updateTable(); // aggiorna tabella + } + return; + } + + // Enter / Space delegation const el = e.target.closest('[data-action]'); if (!el) return; -- 2.47.3