class SmartTable { constructor(table) { this.table = table; this.tbody = table.querySelector("tbody"); this.rows = Array.from(this.tbody.querySelectorAll("tr")); this.currentPage = 1; this.rowsPerPage = 10; this.searchTerm = ""; this.sortIndex = null; this.sortOrder = "asc"; this.init(); } init() { this.createControls(); this.attachSortHandlers(); this.render(); } createControls() { const wrapper = this.table.parentNode; // Table controls (entries + search) this.controls = document.createElement("div"); this.controls.className = "table-controls"; // Entries select this.entriesSelect = document.createElement("select"); [5, 10, 25, 50, 100].forEach(n => { const opt = document.createElement("option"); opt.value = n; opt.textContent = n; if (n === this.rowsPerPage) opt.selected = true; this.entriesSelect.appendChild(opt); }); this.entriesSelect.addEventListener("change", () => { this.rowsPerPage = parseInt(this.entriesSelect.value); this.currentPage = 1; this.render(); }); // Search input this.searchInput = document.createElement("input"); this.searchInput.type = "text"; this.searchInput.placeholder = "Search..."; this.searchInput.addEventListener("input", () => { this.searchTerm = this.searchInput.value.toLowerCase(); this.currentPage = 1; this.render(); }); this.controls.appendChild(this.entriesSelect); this.controls.appendChild(this.searchInput); // Table footer (info + pagination) this.footer = document.createElement("div"); this.footer.className = "table-footer"; this.info = document.createElement("div"); this.info.className = "table-info"; this.pagination = document.createElement("ul"); this.pagination.className = "pagination"; this.footer.appendChild(this.info); this.footer.appendChild(this.pagination); // Wrap table in a scroll container (JS dynamic) this.scrollContainer = document.createElement("div"); this.scrollContainer.className = "table-scroll"; this.table.parentNode.insertBefore(this.scrollContainer, this.table); this.scrollContainer.appendChild(this.table); // Insert controls and footer wrapper.insertBefore(this.controls, this.scrollContainer); wrapper.appendChild(this.footer); } attachSortHandlers() { this.table.querySelectorAll("th").forEach((th, i) => { th.addEventListener("click", () => { if (this.sortIndex === i) { this.sortOrder = this.sortOrder === "asc" ? "desc" : "asc"; } else { this.sortIndex = i; this.sortOrder = "asc"; } this.render(); }); }); } render() { let filtered = this.rows.filter(row => row.innerText.toLowerCase().includes(this.searchTerm) ); if (this.sortIndex !== null) { filtered.sort((a, b) => { let textA = a.children[this.sortIndex].innerText.trim(); let textB = b.children[this.sortIndex].innerText.trim(); let numA = parseFloat(textA.replace(/[^0-9.-]+/g, "")); let numB = parseFloat(textB.replace(/[^0-9.-]+/g, "")); if (!isNaN(numA) && !isNaN(numB)) { textA = numA; textB = numB; } if (this.sortOrder === "asc") return textA > textB ? 1 : -1; else return textA < textB ? 1 : -1; }); } const totalRows = filtered.length; const totalPages = Math.ceil(totalRows / this.rowsPerPage); const start = (this.currentPage - 1) * this.rowsPerPage; const end = Math.min(start + this.rowsPerPage, totalRows); this.tbody.innerHTML = ""; if (totalRows === 0) { // Show "no data" row with image + message const tr = document.createElement("tr"); const td = document.createElement("td"); td.colSpan = this.table.querySelectorAll("th").length; td.className = "text-center p-4"; td.innerHTML = `