Enhanced AG Grid Functionality

Adds vibrant row hover effect (overriding all cell colors), conditional status cell styling for test status and sample status, static red background for emergency rows in AG Grid.

// ==UserScript==
// @name         Enhanced AG Grid Functionality
// @version      3.5
// @description  Adds vibrant row hover effect (overriding all cell colors), conditional status cell styling for test status and sample status, static red background for emergency rows in AG Grid.
// @match        https://his.kaauh.org/lab/*
// @author       Hamad AlShegifi
// @grant        GM_addStyle
// @namespace    http://tampermonkey.net/
// ==/UserScript==

(function () {
    'use strict';

    // Inject CSS for hover effect, status cell styling, and emergency highlighting
    GM_addStyle(`
        .ag-row {
            transition: background-color 0.3s ease;
        }
        .vibrant-hover {
            /* Background color and text color are now applied to cells within the hovered row */
        }
        .ag-row.vibrant-hover .ag-cell {
            background-color: #87dced !important; /* Light blue color */
            color: black !important; /* Black text color */
            font-weight: bold !important; /* Bold font */
        }
        .ag-cell[col-id="testStatus"].status-verified-level2,
        .ag-cell[col-id="testStatus"].status-verified-level1 {
            background-color: #90EE90 !important; /* Light green color */
        }
        .ag-cell[col-id="testStatus"].status-ordered {
            background-color: #FFFFE0 !important; /* Light yellow color */
        }
        .ag-cell[col-id="testStatus"].status-resulted {
            background-color: #FFA500 !important; /* Orange color */
            color: black !important; /* Ensure text is readable on orange */
        }
        .ag-cell[col-id="testStatus"].status-cancelled {
            background-color: #000000 !important; /* Brown color */
            color: white !important; /* White text for contrast */
        }
        .emergency-row {
            background-color: #ffe0e0 !important; /* Light red */
        }
        .ag-cell[col-id="sampleStatus"].status-received {
            background-color: #90EE90 !important; /* Light green color for Received sample status */
        }
    `);

    // List of `col-id` attributes to target for hover effect
    const targetColumnIdsForHover = [
        "orderNo", "testId", "testDescription", "clusterMrn",
        "hospitalMrn", "patientName", "dob", "nationalIqamaId",
        "department", "clinic", "doctor", "analyzer",
        "orderDateAndTime", "lastUpdatedDate", "sampleStatus",
        "referenceLab", "accessionNo", "barcode", "sequenceNo",
        "primaryPatientId", "referenceLabDesc", "testStatus",
        "orderLastModifiedOnEpoch", "orderCreatedOnEpoch", "equipmentName", "doctorName", "localMrn",
        "dateOfBirth", "idNumber"
    ];

    const columnsToUncheck = [
        'Lab Order No', 'Hospital MRN', 'DOB', 'Test ID', 'National/Iqama Id',
        'Department', 'Doctor', 'Analyzer', 'Reference Lab',
        'Accession No', 'Sequence No','Age','Container Type','Storage Condition'
    ];

    let hasRunOnce = false; // Prevents running the column unchecking code more than once

    function isSpecificPage() {
        return window.location.href.endsWith('/#/lab-orders/lab-test-analyzer');
    }

    function areColumnsChecked() {
        return columnsToUncheck.some(column => isColumnChecked(column));
    }

    function isColumnChecked(labelText) {
        const labels = document.querySelectorAll('.ag-column-tool-panel-column-label');
        for (const label of labels) {
            if (label.textContent.trim() === labelText) {
                const checkbox = label.parentElement.querySelector('.ag-icon-checkbox-checked');
                if (checkbox) return true; // Column is checked
            }
        }
        return false; // Column is not checked
    }

    function ensureColumnsUnchecked() {
        if (hasRunOnce || !isSpecificPage()) return;
        if (!areColumnsChecked()) return; // Do nothing if columns are not checked

        hasRunOnce = true;
        console.log("Unchecking checked columns...");

        setTimeout(() => {
            columnsToUncheck.forEach(column => clickColumnLabel(column));
        }, 1000);
    }

    function ensureOtherColumnsChecked() {
        if (!isSpecificPage()) return;
        console.log("Ensuring all other columns are checked...");

        const allLabels = document.querySelectorAll('.ag-column-tool-panel-column-label');
        allLabels.forEach(label => {
            const labelText = label.textContent.trim();
            if (!columnsToUncheck.includes(labelText)) {
                const checkbox = label.parentElement.querySelector('.ag-icon-checkbox-unchecked');
                if (checkbox) {
                    label.click(); // Click to check the column if unchecked
                }
            }
        });
    }

    function clickColumnLabel(labelText) {
        if (!isSpecificPage()) return;
        const labels = document.querySelectorAll('.ag-column-tool-panel-column-label');
        labels.forEach(label => {
            if (label.textContent.trim() === labelText) {
                const checkbox = label.parentElement.querySelector('.ag-icon-checkbox-checked');
                if (checkbox) {
                    label.click(); // Click only if checked
                }
            }
        });
    }

    function highlightEmergencyRows() {
        const rows = document.querySelectorAll('div[role="row"]');

        rows.forEach(row => {
            const clinicCell = row.querySelector('div[col-id="clinic"]');
            if (clinicCell && clinicCell.textContent.trim() === 'EMERGENCY') {
                row.classList.add('emergency-row');
            } else {
                row.classList.remove('emergency-row'); // Remove the class if the condition is no longer met
            }
        });
    }

    function initColumnToggle() {
        if (!isSpecificPage()) return;
        console.log("Checking if columns need to be unchecked and highlighting emergency rows...");

        let attempts = 0;
        const interval = setInterval(() => {
            if (document.querySelector('.ag-side-buttons')) {
                ensureColumnsUnchecked();
                ensureOtherColumnsChecked();
                highlightEmergencyRows(); // Call the highlighting function here
                clearInterval(interval);
            }
            if (++attempts > 10) {
                highlightEmergencyRows(); // Ensure highlighting runs even if sidebar isn't found quickly
                clearInterval(interval);
            }
        }, 500);

        // Also run highlighting on initial load attempt
        highlightEmergencyRows();
    }

    // Function to apply hover effects to the entire row when any target cell is hovered
    function applyHoverEffect() {
        document.querySelectorAll('.ag-cell').forEach(cell => {
            const colId = cell.getAttribute('col-id');
            if (colId && targetColumnIdsForHover.includes(colId)) {
                const row = cell.closest('.ag-row'); // Find the parent row
                if (row) {
                    // Add hover effect to the entire row on mouseenter
                    cell.addEventListener('mouseenter', () => {
                        row.classList.add('vibrant-hover'); // Add hover effect to the row
                    });
                    // Remove hover effect on mouseleave
                    cell.addEventListener('mouseleave', () => {
                        row.classList.remove('vibrant-hover'); // Remove hover effect from the row
                    });
                }
            }
        });
    }

    // Function to apply conditional background color to the "Status" column
    function applyStatusCellStyle() {
        document.querySelectorAll('.ag-cell[col-id="testStatus"]').forEach(cell => {
            const statusValue = cell.textContent.trim();
            cell.classList.remove('status-verified-level2', 'status-verified-level1', 'status-ordered', 'status-resulted', 'status-cancelled'); // Remove previous styles

            if (statusValue === "VerifiedLevel2" || statusValue === "VerifiedLevel1") {
                cell.classList.add('status-verified-level2');
            } else if (statusValue === "Ordered") {
                cell.classList.add('status-ordered');
            } else if (statusValue === "Resulted") {
                cell.classList.add('status-resulted');
            } else if (statusValue === "Cancelled") {
                cell.classList.add('status-cancelled'); // Apply brown color for Cancelled
            }
        });

        // Apply style for Sample Status = Received
        document.querySelectorAll('.ag-cell[col-id="sampleStatus"]').forEach(cell => {
            if (cell.textContent.trim() === "Received") {
                cell.classList.add('status-received');
            } else {
                cell.classList.remove('status-received'); // Ensure the class is removed if the value changes
            }
        });
    }

    const observer = new MutationObserver(() => {
        applyHoverEffect();
        applyStatusCellStyle();
        highlightEmergencyRows(); // Call highlightEmergencyRows on every DOM change

        if (isSpecificPage()) {
            hasRunOnce = false; // Reset run flag for repeated executions
            initColumnToggle();
        }
    });

    // **Important: Observing the correct AG Grid body viewport**
    const gridBodyViewport = document.querySelector('.ag-body-viewport'); // Observe the grid body viewport
    if (gridBodyViewport) {
        observer.observe(gridBodyViewport, { childList: true, subtree: false }); // subtree should be false here as we are observing direct children (rows)
    } else {
        console.warn("AG Grid body viewport not found. Falling back to body observer.");
        observer.observe(document.body, { childList: true, subtree: true });
    }


    window.addEventListener('load', () => {
        applyHoverEffect();
        applyStatusCellStyle();
        if (isSpecificPage()) {
            initColumnToggle();
        }
    });

    // Function to set the dropdown value (keeping this separate as it seems independent)
    (function() {
        'use strict';

        // Function to set the dropdown value
        function setDropdownValue() {
            const dropdown = document.getElementById("dropdownPaginationPageSize");
            if (dropdown && dropdown.value !== "100") {
                dropdown.value = "100"; // Set the value to "100"

                // Trigger the 'change' event
                const event = new Event('change', { bubbles: true });
                dropdown.dispatchEvent(event);

                console.log("Dropdown value set to 100");
            }
        }

        // Function to observe changes in the DOM for the dropdown
        function observeDOMForDropdown() {
            const observer = new MutationObserver(() => {
                setDropdownValue(); // Check and set the dropdown value when changes are detected
            });

            // Observe the entire document for changes
            observer.observe(document.body, {
                childList: true,
                subtree: true,
            });

            console.log("MutationObserver is active for dropdown");
        }

        // Run the function when the page is fully loaded
        window.addEventListener('load', () => {
            setDropdownValue(); // Initial check
            observeDOMForDropdown(); // Start observing for dynamic changes
        });
    })();

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址