Skip to content

Commit

Permalink
feat: add search function to rank tables
Browse files Browse the repository at this point in the history
  • Loading branch information
thunderpoot committed Jan 2, 2025
1 parent af5e6e5 commit 7e27941
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 58 deletions.
125 changes: 96 additions & 29 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,28 @@
content: " ▼";
color: #666;
}
.search-container {
display: flex;
gap: 1rem;
align-items: baseline;
margin-bottom: 1rem;
}
.search-input {
padding: 0.5rem;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
flex-grow: 1;
max-width: 300px;
}
.search-input:focus {
outline: none;
border-color: #999;
}
.search-count {
color: #666;
font-size: 14px;
}

</style>
<script>
Expand Down Expand Up @@ -243,9 +265,21 @@
const thead = table.querySelector('thead');
if (!tbody || !thead) return;

const searchContainer = document.createElement('div');
searchContainer.className = 'search-container';
searchContainer.innerHTML = `
<input type="text" class="search-input" placeholder="Search table...">
<div class="search-count"></div>
`;
table.parentNode.insertBefore(searchContainer, table);

const searchInput = searchContainer.querySelector('.search-input');
const searchCount = searchContainer.querySelector('.search-count');

const rows = Array.from(tbody.querySelectorAll('tr'));
const rowsPerPage = 10;
const totalPages = Math.ceil(rows.length / rowsPerPage);
let filteredRows = rows;
let currentPage = 1;

const headers = thead.querySelectorAll('th');
headers.forEach((header, index) => {
Expand All @@ -263,8 +297,7 @@
const newSort = currentSort === 'asc' ? 'desc' : 'asc';
header.setAttribute('data-sort', newSort);

const rows = Array.from(tbody.querySelectorAll('tr'));
rows.sort((rowA, rowB) => {
filteredRows.sort((rowA, rowB) => {
const cellA = rowA.cells[index].textContent.trim();
const cellB = rowB.cells[index].textContent.trim();

Expand All @@ -280,48 +313,82 @@
}
});

rows.forEach(row => tbody.appendChild(row));
filteredRows.forEach(row => tbody.appendChild(row));

showPage(currentPage);
showPage(1);
});
});

if (totalPages <= 1) return;
function filterRows(searchTerm) {
if (!searchTerm) {
filteredRows = rows;
searchCount.textContent = '';
} else {
searchTerm = searchTerm.toLowerCase();
filteredRows = rows.filter(row => {
return Array.from(row.cells).some(cell =>
cell.textContent.toLowerCase().includes(searchTerm)
);
});
searchCount.textContent = `${filteredRows.length} matches`;
}

const controls = document.createElement('div');
controls.className = 'pagination-controls';
controls.innerHTML = `
<button class="prev-btn" disabled>&laquo; Previous</button>
<span class="page-info">Page <span class="current-page">1</span> of ${totalPages}</span>
<button class="next-btn">Next &raquo;</button>
`;
rows.forEach(row => row.style.display = 'none');

table.parentNode.insertBefore(controls, table.nextSibling);
const totalPages = Math.ceil(filteredRows.length / rowsPerPage);
if (controls) {
controls.querySelector('.total-pages').textContent = totalPages;
}

let currentPage = 1;
showPage(1);
}

searchInput.addEventListener('input', (e) => {
filterRows(e.target.value);
});

let controls = null;
const totalPages = Math.ceil(filteredRows.length / rowsPerPage);

if (totalPages > 1) {
controls = document.createElement('div');
controls.className = 'pagination-controls';
controls.innerHTML = `
<button class="prev-btn" disabled>&laquo; Previous</button>
<span class="page-info">Page <span class="current-page">1</span> of <span class="total-pages">${totalPages}</span></span>
<button class="next-btn">Next &raquo;</button>
`;

table.parentNode.insertBefore(controls, table.nextSibling);

controls.querySelector('.prev-btn').addEventListener('click', () => {
if (currentPage > 1) showPage(currentPage - 1);
});

controls.querySelector('.next-btn').addEventListener('click', () => {
const totalPages = Math.ceil(filteredRows.length / rowsPerPage);
if (currentPage < totalPages) showPage(currentPage + 1);
});
}

function showPage(page) {
const rows = Array.from(tbody.querySelectorAll('tr'));
const start = (page - 1) * rowsPerPage;
const end = start + rowsPerPage;

rows.forEach((row, index) => {
row.style.display = (index >= start && index < end) ? '' : 'none';
rows.forEach(row => row.style.display = 'none');

filteredRows.slice(start, end).forEach(row => {
row.style.display = '';
});

currentPage = page;
controls.querySelector('.current-page').textContent = page;
controls.querySelector('.prev-btn').disabled = page === 1;
controls.querySelector('.next-btn').disabled = page === totalPages;
}

controls.querySelector('.prev-btn').addEventListener('click', () => {
if (currentPage > 1) showPage(currentPage - 1);
});

controls.querySelector('.next-btn').addEventListener('click', () => {
if (currentPage < totalPages) showPage(currentPage + 1);
});
if (controls) {
controls.querySelector('.current-page').textContent = page;
controls.querySelector('.prev-btn').disabled = page === 1;
controls.querySelector('.next-btn').disabled = page === Math.ceil(filteredRows.length / rowsPerPage);
}
}

table.setAttribute('data-pagination-initialized', 'true');

Expand Down
103 changes: 74 additions & 29 deletions src/pagination.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,21 @@ function setupPagination() {
const thead = table.querySelector('thead');
if (!tbody || !thead) return;

const searchContainer = document.createElement('div');
searchContainer.className = 'search-container';
searchContainer.innerHTML = `
<input type="text" class="search-input" placeholder="Search table...">
<div class="search-count"></div>
`;
table.parentNode.insertBefore(searchContainer, table);

const searchInput = searchContainer.querySelector('.search-input');
const searchCount = searchContainer.querySelector('.search-count');

const rows = Array.from(tbody.querySelectorAll('tr'));
const rowsPerPage = 10;
const totalPages = Math.ceil(rows.length / rowsPerPage);
let filteredRows = rows;
let currentPage = 1;

const headers = thead.querySelectorAll('th');
headers.forEach((header, index) => {
Expand All @@ -31,8 +43,7 @@ function setupPagination() {
const newSort = currentSort === 'asc' ? 'desc' : 'asc';
header.setAttribute('data-sort', newSort);

const rows = Array.from(tbody.querySelectorAll('tr'));
rows.sort((rowA, rowB) => {
filteredRows.sort((rowA, rowB) => {
const cellA = rowA.cells[index].textContent.trim();
const cellB = rowB.cells[index].textContent.trim();

Expand All @@ -48,48 +59,82 @@ function setupPagination() {
}
});

rows.forEach(row => tbody.appendChild(row));
filteredRows.forEach(row => tbody.appendChild(row));

showPage(currentPage);
showPage(1);
});
});

if (totalPages <= 1) return;
function filterRows(searchTerm) {
if (!searchTerm) {
filteredRows = rows;
searchCount.textContent = '';
} else {
searchTerm = searchTerm.toLowerCase();
filteredRows = rows.filter(row => {
return Array.from(row.cells).some(cell =>
cell.textContent.toLowerCase().includes(searchTerm)
);
});
searchCount.textContent = `${filteredRows.length} matches`;
}

const controls = document.createElement('div');
controls.className = 'pagination-controls';
controls.innerHTML = `
<button class="prev-btn" disabled>&laquo; Previous</button>
<span class="page-info">Page <span class="current-page">1</span> of ${totalPages}</span>
<button class="next-btn">Next &raquo;</button>
`;
rows.forEach(row => row.style.display = 'none');

table.parentNode.insertBefore(controls, table.nextSibling);
const totalPages = Math.ceil(filteredRows.length / rowsPerPage);
if (controls) {
controls.querySelector('.total-pages').textContent = totalPages;
}

let currentPage = 1;
showPage(1);
}

searchInput.addEventListener('input', (e) => {
filterRows(e.target.value);
});

let controls = null;
const totalPages = Math.ceil(filteredRows.length / rowsPerPage);

if (totalPages > 1) {
controls = document.createElement('div');
controls.className = 'pagination-controls';
controls.innerHTML = `
<button class="prev-btn" disabled>&laquo; Previous</button>
<span class="page-info">Page <span class="current-page">1</span> of <span class="total-pages">${totalPages}</span></span>
<button class="next-btn">Next &raquo;</button>
`;

table.parentNode.insertBefore(controls, table.nextSibling);

controls.querySelector('.prev-btn').addEventListener('click', () => {
if (currentPage > 1) showPage(currentPage - 1);
});

controls.querySelector('.next-btn').addEventListener('click', () => {
const totalPages = Math.ceil(filteredRows.length / rowsPerPage);
if (currentPage < totalPages) showPage(currentPage + 1);
});
}

function showPage(page) {
const rows = Array.from(tbody.querySelectorAll('tr'));
const start = (page - 1) * rowsPerPage;
const end = start + rowsPerPage;

rows.forEach((row, index) => {
row.style.display = (index >= start && index < end) ? '' : 'none';
rows.forEach(row => row.style.display = 'none');

filteredRows.slice(start, end).forEach(row => {
row.style.display = '';
});

currentPage = page;
controls.querySelector('.current-page').textContent = page;
controls.querySelector('.prev-btn').disabled = page === 1;
controls.querySelector('.next-btn').disabled = page === totalPages;
}

controls.querySelector('.prev-btn').addEventListener('click', () => {
if (currentPage > 1) showPage(currentPage - 1);
});

controls.querySelector('.next-btn').addEventListener('click', () => {
if (currentPage < totalPages) showPage(currentPage + 1);
});
if (controls) {
controls.querySelector('.current-page').textContent = page;
controls.querySelector('.prev-btn').disabled = page === 1;
controls.querySelector('.next-btn').disabled = page === Math.ceil(filteredRows.length / rowsPerPage);
}
}

table.setAttribute('data-pagination-initialized', 'true');

Expand Down
22 changes: 22 additions & 0 deletions src/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,25 @@ th[data-sort="desc"]::after {
content: " ▼";
color: #666;
}
.search-container {
display: flex;
gap: 1rem;
align-items: baseline;
margin-bottom: 1rem;
}
.search-input {
padding: 0.5rem;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
flex-grow: 1;
max-width: 300px;
}
.search-input:focus {
outline: none;
border-color: #999;
}
.search-count {
color: #666;
font-size: 14px;
}

0 comments on commit 7e27941

Please sign in to comment.