// ==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();
    });
})();

Previous Post