// ==UserScript==
// @name Paginated Searchable Table
// @namespace http://tampermonkey.net/
// @version 0.2 // Updated version to reflect the change
// @description Converts a table with ID 'grvCitizenapplication' into a paginated and searchable table.
// @author Your Name
// @match https://labour.mponline.gov.in/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// Function to wait for the DOM to be ready
function waitForElm(selector) {
return new Promise(resolve => {
if (document.querySelector(selector)) {
return resolve(document.querySelector(selector));
}
const observer = new MutationObserver(mutations => {
if (document.querySelector(selector)) {
resolve(document.querySelector(selector));
observer.disconnect();
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
});
}
waitForElm('#grvCitizenapplication').then((table) => {
console.log('Table found:', table);
const rowsPerPage = 5; // Number of rows to display per page
let currentPage = 1;
let originalRows = []; // To store all original table rows (excluding header)
let filteredRows = []; // To store rows after search filtering
// Get the table body and all its rows
const tbody = table.querySelector('tbody');
if (!tbody) {
console.error('Table tbody not found.');
return;
}
// Store original rows and remove them from DOM temporarily
// Skip the first row if it's a header within tbody, or handle thead separately
const allRows = Array.from(tbody.rows);
// Assuming the first row of the tbody might be a header or not.
// If the table has a proper <thead>, then all tbody rows are data rows.
// If the table has no <thead> and the first tbody row is the header, adjust accordingly.
const hasThead = table.querySelector('thead');
if (hasThead) {
originalRows = allRows;
} else {
// If no thead, assume first row of tbody is header
originalRows = allRows.slice(1);
// Re-append the header row if it was part of tbody and we sliced it out
if (allRows.length > 0) {
tbody.prepend(allRows[0]);
}
}
// Clear existing rows from tbody to re-render them
tbody.innerHTML = '';
filteredRows = [...originalRows]; // Initially, all rows are filtered rows
// --------------------------------------------------------------------
// 1. Create Search Input
// --------------------------------------------------------------------
const searchContainer = document.createElement('div');
searchContainer.style.marginBottom = '10px';
searchContainer.style.padding = '10px';
searchContainer.style.backgroundColor = '#f9f9f9';
searchContainer.style.border = '1px solid #ddd';
searchContainer.style.borderRadius = '5px';
searchContainer.style.display = 'flex';
searchContainer.style.alignItems = 'center';
const searchLabel = document.createElement('label');
searchLabel.htmlFor = 'tableSearchInput';
searchLabel.textContent = 'Search Table: ';
searchLabel.style.marginRight = '10px';
searchLabel.style.fontWeight = 'bold';
searchLabel.style.color = '#333';
const searchInput = document.createElement('input');
searchInput.type = 'text';
searchInput.id = 'tableSearchInput';
searchInput.placeholder = 'Type to search...';
searchInput.style.padding = '8px';
searchInput.style.border = '1px solid #ccc';
searchInput.style.borderRadius = '4px';
searchInput.style.flexGrow = '1';
searchInput.style.fontSize = '14px';
searchContainer.appendChild(searchLabel);
searchContainer.appendChild(searchInput);
table.parentNode.insertBefore(searchContainer, table);
// --------------------------------------------------------------------
// 2. Create Pagination Controls
// --------------------------------------------------------------------
const paginationContainer = document.createElement('div');
paginationContainer.style.marginTop = '10px';
paginationContainer.style.padding = '10px';
paginationContainer.style.backgroundColor = '#f9f9f9';
paginationContainer.style.border = '1px solid #ddd';
paginationContainer.style.borderRadius = '5px';
paginationContainer.style.textAlign = 'center';
paginationContainer.style.display = 'flex';
paginationContainer.style.justifyContent = 'center';
paginationContainer.style.alignItems = 'center';
paginationContainer.style.gap = '10px';
const prevButton = document.createElement('button');
prevButton.textContent = 'Previous';
prevButton.style.padding = '8px 15px';
prevButton.style.border = '1px solid #007bff';
prevButton.style.borderRadius = '4px';
prevButton.style.backgroundColor = '#007bff';
prevButton.style.color = 'white';
prevButton.style.cursor = 'pointer';
prevButton.style.transition = 'background-color 0.3s ease';
prevButton.onmouseover = () => prevButton.style.backgroundColor = '#0056b3';
prevButton.onmouseout = () => prevButton.style.backgroundColor = '#007bff';
const nextButton = document.createElement('button');
nextButton.textContent = 'Next';
nextButton.style.padding = '8px 15px';
nextButton.style.border = '1px solid #007bff';
nextButton.style.borderRadius = '4px';
nextButton.style.backgroundColor = '#007bff';
nextButton.style.color = 'white';
nextButton.style.cursor = 'pointer';
nextButton.style.transition = 'background-color 0.3s ease';
nextButton.onmouseover = () => nextButton.style.backgroundColor = '#0056b3';
nextButton.onmouseout = () => nextButton.style.backgroundColor = '#007bff';
const pageInfo = document.createElement('span');
pageInfo.style.fontWeight = 'bold';
pageInfo.style.color = '#555';
pageInfo.style.minWidth = '120px'; // Ensure space for text
paginationContainer.appendChild(prevButton);
paginationContainer.appendChild(pageInfo);
paginationContainer.appendChild(nextButton);
table.parentNode.insertBefore(paginationContainer, table.nextSibling);
// --------------------------------------------------------------------
// 3. Core Rendering Function
// --------------------------------------------------------------------
function renderTable() {
tbody.innerHTML = ''; // Clear current rows
const totalPages = Math.ceil(filteredRows.length / rowsPerPage);
currentPage = Math.max(1, Math.min(currentPage, totalPages || 1)); // Ensure current page is valid
const startIndex = (currentPage - 1) * rowsPerPage;
const endIndex = startIndex + rowsPerPage;
const rowsToShow = filteredRows.slice(startIndex, endIndex);
if (rowsToShow.length === 0 && filteredRows.length > 0) {
// If filtering resulted in no rows on the current page, go to the last page with content
currentPage = totalPages;
renderTable(); // Re-render with the adjusted page
return;
} else if (rowsToShow.length === 0 && filteredRows.length === 0) {
// No results found at all
const noResultsRow = document.createElement('tr');
const noResultsCell = document.createElement('td');
noResultsCell.colSpan = table.querySelector('thead tr, tbody tr')?.children.length || 1; // Get column count dynamically
noResultsCell.textContent = 'No matching records found.';
noResultsCell.style.textAlign = 'center';
noResultsCell.style.padding = '20px';
noResultsCell.style.color = '#888';
noResultsRow.appendChild(noResultsCell);
tbody.appendChild(noResultsRow);
}
rowsToShow.forEach(row => tbody.appendChild(row));
pageInfo.textContent = `Page ${currentPage} of ${totalPages || 1} (Total: ${filteredRows.length} records)`;
prevButton.disabled = currentPage === 1;
nextButton.disabled = currentPage === totalPages || totalPages === 0;
// Update button styles based on disabled state
if (prevButton.disabled) {
prevButton.style.backgroundColor = '#cccccc';
prevButton.style.borderColor = '#bbbbbb';
prevButton.style.cursor = 'not-allowed';
prevButton.onmouseover = null;
prevButton.onmouseout = null;
} else {
prevButton.style.backgroundColor = '#007bff';
prevButton.style.borderColor = '#007bff';
prevButton.style.cursor = 'pointer';
prevButton.onmouseover = () => prevButton.style.backgroundColor = '#0056b3';
prevButton.onmouseout = () => prevButton.style.backgroundColor = '#007bff';
}
if (nextButton.disabled) {
nextButton.style.backgroundColor = '#cccccc';
nextButton.style.borderColor = '#bbbbbb';
nextButton.style.cursor = 'not-allowed';
nextButton.onmouseover = null;
nextButton.onmouseout = null;
} else {
nextButton.style.backgroundColor = '#007bff';
nextButton.style.borderColor = '#007bff';
nextButton.style.cursor = 'pointer';
nextButton.onmouseover = () => nextButton.style.backgroundColor = '#0056b3';
nextButton.onmouseout = () => nextButton.style.backgroundColor = '#007bff';
}
}
// --------------------------------------------------------------------
// 4. Event Listeners
// --------------------------------------------------------------------
// Search functionality
searchInput.addEventListener('keyup', () => {
const searchTerm = searchInput.value.toLowerCase().trim();
filteredRows = originalRows.filter(row => {
// Check if any cell in the row contains the search term
return Array.from(row.cells).some(cell =>
cell.textContent.toLowerCase().includes(searchTerm)
);
});
currentPage = 1; // Reset to first page on new search
renderTable();
});
// Pagination buttons
prevButton.addEventListener('click', (event) => { // Added event parameter
event.preventDefault(); // Prevent default button behavior (e.g., form submission)
if (currentPage > 1) {
currentPage--;
renderTable();
}
});
nextButton.addEventListener('click', (event) => { // Added event parameter
event.preventDefault(); // Prevent default button behavior (e.g., form submission)
const totalPages = Math.ceil(filteredRows.length / rowsPerPage);
if (currentPage < totalPages) {
currentPage++;
renderTable();
}
});
// Initial render of the table
renderTable();
});
})();