Auto Sort Purelymail Routing Table by Domain

Automatically sort and group the Purelymail routing table by domain on page load with toggleable headers and gap for each domain group. Removes borders and background from gaps and striped rows.

// ==UserScript==
// @name         Auto Sort Purelymail Routing Table by Domain
// @namespace    http://tampermonkey.net/
// @version      3.4
// @description  Automatically sort and group the Purelymail routing table by domain on page load with toggleable headers and gap for each domain group. Removes borders and background from gaps and striped rows.
// @author       V3ctor Design
// @license      MIT
// @match        https://purelymail.com/manage/routing
// @grant        GM_registerMenuCommand
// ==/UserScript==

(function () {
    'use strict';

    // User setting to toggle headers
    let showHeaders = true;

    // Register a menu command to toggle headers
    GM_registerMenuCommand("Toggle Domain Headers", () => {
        showHeaders = !showHeaders;
        sortAndGroupTableByDomain();
    });

    // Inject custom CSS to override existing styles for borders and striping
    const style = document.createElement('style');
    style.textContent = `
        /* Remove borders from the table, header, and cells */
        .borderedTable, .borderedTable th, .borderedTable td {
            border: none !important;
        }

        /* Remove background color for even rows (striping) */
        table.striped tr:nth-of-type(2n) {
            background-color: transparent !important;
        }
    `;
    document.head.appendChild(style);

    // Function to sort and group the table by domain
    function sortAndGroupTableByDomain() {
        const table = document.querySelector('table.striped'); // Get the table element

        if (!table) {
            console.log("Table not found yet.");
            return false; // Retry if table is not available
        }

        // Remove default table background and border styles
        table.style.backgroundColor = 'transparent';
        table.style.border = 'none';

        const domainColIndex = 0; // "Domain" is the first column
        const tbody = table.querySelector('tbody'); // Get tbody

        if (!tbody) {
            console.log("Tbody not found.");
            return false;
        }

        const rows = Array.from(tbody.querySelectorAll('tr')); // Get all rows

        if (rows.length === 0) {
            console.log("No rows found.");
            return false;
        }

        // Sort rows by domain
        const sortedRows = rows.sort((rowA, rowB) => {
            const domainA = rowA.querySelectorAll('td')[domainColIndex].querySelector('select').selectedOptions[0].textContent.trim().toLowerCase();
            const domainB = rowB.querySelectorAll('td')[domainColIndex].querySelector('select').selectedOptions[0].textContent.trim().toLowerCase();
            return domainA.localeCompare(domainB); // Sort domains alphabetically
        });

        tbody.innerHTML = ''; // Clear existing rows

        let lastDomain = null;

        // Append sorted rows with headers for each domain group
        sortedRows.forEach(row => {
            const currentDomain = row.querySelectorAll('td')[domainColIndex].querySelector('select').selectedOptions[0].textContent.trim().toLowerCase();

            if (lastDomain !== currentDomain) {
                // Add a gap (spacer) before the new group
                const spacerRow = document.createElement('tr');
                const spacerCell = document.createElement('td');
                spacerCell.colSpan = row.children.length;
                spacerCell.style.height = '20px';
                spacerRow.appendChild(spacerCell);
                tbody.appendChild(spacerRow);

                // Create and add the header row for the new domain group if headers are enabled
                if (showHeaders) {
                    const headerRow = document.createElement('tr');
                    const headerCell = document.createElement('td');
                    headerCell.colSpan = row.children.length;
                    headerCell.style.backgroundColor = '#ddd'; // Apply background color to header
                    headerCell.style.fontWeight = 'bold';
                    headerCell.style.padding = '5px';
                    headerCell.textContent = currentDomain;
                    headerRow.appendChild(headerCell);
                    tbody.appendChild(headerRow);
                }
            }

            // Add the row to the table
            row.style.backgroundColor = 'transparent'; // Ensure rows have no background color
            tbody.appendChild(row);
            lastDomain = currentDomain;
        });

        console.log("Table sorted and grouped by domain with headers and gaps.");
        return true;
    }

    // Function to poll for the table to be fully loaded
    function pollForTable() {
        const maxAttempts = 20; // Number of retries (adjust as needed)
        let attempts = 0;

        const interval = setInterval(() => {
            attempts++;
            const sorted = sortAndGroupTableByDomain();

            if (sorted) {
                clearInterval(interval); // Stop polling once sorting is successful
            }

            if (attempts >= maxAttempts) {
                clearInterval(interval); // Stop after max attempts
                console.log("Failed to sort and group the table after maximum attempts.");
            }
        }, 100); // Poll every 100ms
    }

    // Start polling for the table after the page has loaded
    window.addEventListener('load', pollForTable);
})();