(function () { function getCellValue(tr, idx) { const td = tr.children[idx]; if (!td) return ""; const v = td.getAttribute("data-sort"); return v !== null ? v : td.innerText.trim(); } function comparer(idx, asc) { return function (a, b) { const v1 = getCellValue(asc ? a : b, idx); const v2 = getCellValue(asc ? b : a, idx); const n1 = Number(v1), n2 = Number(v2); if (!Number.isNaN(n1) && !Number.isNaN(n2)) return n1 - n2; return v1.localeCompare(v2); }; } document.querySelectorAll("table[data-sortable='true'] thead th").forEach(th => { th.addEventListener("click", () => { const table = th.closest("table"); const tbody = table.querySelector("tbody"); const idx = Array.from(th.parentNode.children).indexOf(th); const asc = !(th.classList.contains("asc")); table.querySelectorAll("th").forEach(x => x.classList.remove("asc", "desc")); th.classList.add(asc ? "asc" : "desc"); Array.from(tbody.querySelectorAll("tr")) .sort(comparer(idx, asc)) .forEach(tr => tbody.appendChild(tr)); }); }); })();