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