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.

  1. // ==UserScript==
  2. // @name Enhanced AG Grid Functionality
  3. // @version 3.5
  4. // @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.
  5. // @match https://his.kaauh.org/lab/*
  6. // @author Hamad AlShegifi
  7. // @grant GM_addStyle
  8. // @namespace http://tampermonkey.net/
  9. // ==/UserScript==
  10.  
  11. (function () {
  12. 'use strict';
  13.  
  14. // Inject CSS for hover effect, status cell styling, and emergency highlighting
  15. GM_addStyle(`
  16. .ag-row {
  17. transition: background-color 0.3s ease;
  18. }
  19. .vibrant-hover {
  20. /* Background color and text color are now applied to cells within the hovered row */
  21. }
  22. .ag-row.vibrant-hover .ag-cell {
  23. background-color: #87dced !important; /* Light blue color */
  24. color: black !important; /* Black text color */
  25. font-weight: bold !important; /* Bold font */
  26. }
  27. .ag-cell[col-id="testStatus"].status-verified-level2,
  28. .ag-cell[col-id="testStatus"].status-verified-level1 {
  29. background-color: #90EE90 !important; /* Light green color */
  30. }
  31. .ag-cell[col-id="testStatus"].status-ordered {
  32. background-color: #FFFFE0 !important; /* Light yellow color */
  33. }
  34. .ag-cell[col-id="testStatus"].status-resulted {
  35. background-color: #FFA500 !important; /* Orange color */
  36. color: black !important; /* Ensure text is readable on orange */
  37. }
  38. .ag-cell[col-id="testStatus"].status-cancelled {
  39. background-color: #000000 !important; /* Brown color */
  40. color: white !important; /* White text for contrast */
  41. }
  42. .emergency-row {
  43. background-color: #ffe0e0 !important; /* Light red */
  44. }
  45. .ag-cell[col-id="sampleStatus"].status-received {
  46. background-color: #90EE90 !important; /* Light green color for Received sample status */
  47. }
  48. `);
  49.  
  50. // List of `col-id` attributes to target for hover effect
  51. const targetColumnIdsForHover = [
  52. "orderNo", "testId", "testDescription", "clusterMrn",
  53. "hospitalMrn", "patientName", "dob", "nationalIqamaId",
  54. "department", "clinic", "doctor", "analyzer",
  55. "orderDateAndTime", "lastUpdatedDate", "sampleStatus",
  56. "referenceLab", "accessionNo", "barcode", "sequenceNo",
  57. "primaryPatientId", "referenceLabDesc", "testStatus",
  58. "orderLastModifiedOnEpoch", "orderCreatedOnEpoch", "equipmentName", "doctorName", "localMrn",
  59. "dateOfBirth", "idNumber"
  60. ];
  61.  
  62. const columnsToUncheck = [
  63. 'Lab Order No', 'Hospital MRN', 'DOB', 'Test ID', 'National/Iqama Id',
  64. 'Department', 'Doctor', 'Analyzer', 'Reference Lab',
  65. 'Accession No', 'Sequence No','Age','Container Type','Storage Condition'
  66. ];
  67.  
  68. let hasRunOnce = false; // Prevents running the column unchecking code more than once
  69.  
  70. function isSpecificPage() {
  71. return window.location.href.endsWith('/#/lab-orders/lab-test-analyzer');
  72. }
  73.  
  74. function areColumnsChecked() {
  75. return columnsToUncheck.some(column => isColumnChecked(column));
  76. }
  77.  
  78. function isColumnChecked(labelText) {
  79. const labels = document.querySelectorAll('.ag-column-tool-panel-column-label');
  80. for (const label of labels) {
  81. if (label.textContent.trim() === labelText) {
  82. const checkbox = label.parentElement.querySelector('.ag-icon-checkbox-checked');
  83. if (checkbox) return true; // Column is checked
  84. }
  85. }
  86. return false; // Column is not checked
  87. }
  88.  
  89. function ensureColumnsUnchecked() {
  90. if (hasRunOnce || !isSpecificPage()) return;
  91. if (!areColumnsChecked()) return; // Do nothing if columns are not checked
  92.  
  93. hasRunOnce = true;
  94. console.log("Unchecking checked columns...");
  95.  
  96. setTimeout(() => {
  97. columnsToUncheck.forEach(column => clickColumnLabel(column));
  98. }, 1000);
  99. }
  100.  
  101. function ensureOtherColumnsChecked() {
  102. if (!isSpecificPage()) return;
  103. console.log("Ensuring all other columns are checked...");
  104.  
  105. const allLabels = document.querySelectorAll('.ag-column-tool-panel-column-label');
  106. allLabels.forEach(label => {
  107. const labelText = label.textContent.trim();
  108. if (!columnsToUncheck.includes(labelText)) {
  109. const checkbox = label.parentElement.querySelector('.ag-icon-checkbox-unchecked');
  110. if (checkbox) {
  111. label.click(); // Click to check the column if unchecked
  112. }
  113. }
  114. });
  115. }
  116.  
  117. function clickColumnLabel(labelText) {
  118. if (!isSpecificPage()) return;
  119. const labels = document.querySelectorAll('.ag-column-tool-panel-column-label');
  120. labels.forEach(label => {
  121. if (label.textContent.trim() === labelText) {
  122. const checkbox = label.parentElement.querySelector('.ag-icon-checkbox-checked');
  123. if (checkbox) {
  124. label.click(); // Click only if checked
  125. }
  126. }
  127. });
  128. }
  129.  
  130. function highlightEmergencyRows() {
  131. const rows = document.querySelectorAll('div[role="row"]');
  132.  
  133. rows.forEach(row => {
  134. const clinicCell = row.querySelector('div[col-id="clinic"]');
  135. if (clinicCell && clinicCell.textContent.trim() === 'EMERGENCY') {
  136. row.classList.add('emergency-row');
  137. } else {
  138. row.classList.remove('emergency-row'); // Remove the class if the condition is no longer met
  139. }
  140. });
  141. }
  142.  
  143. function initColumnToggle() {
  144. if (!isSpecificPage()) return;
  145. console.log("Checking if columns need to be unchecked and highlighting emergency rows...");
  146.  
  147. let attempts = 0;
  148. const interval = setInterval(() => {
  149. if (document.querySelector('.ag-side-buttons')) {
  150. ensureColumnsUnchecked();
  151. ensureOtherColumnsChecked();
  152. highlightEmergencyRows(); // Call the highlighting function here
  153. clearInterval(interval);
  154. }
  155. if (++attempts > 10) {
  156. highlightEmergencyRows(); // Ensure highlighting runs even if sidebar isn't found quickly
  157. clearInterval(interval);
  158. }
  159. }, 500);
  160.  
  161. // Also run highlighting on initial load attempt
  162. highlightEmergencyRows();
  163. }
  164.  
  165. // Function to apply hover effects to the entire row when any target cell is hovered
  166. function applyHoverEffect() {
  167. document.querySelectorAll('.ag-cell').forEach(cell => {
  168. const colId = cell.getAttribute('col-id');
  169. if (colId && targetColumnIdsForHover.includes(colId)) {
  170. const row = cell.closest('.ag-row'); // Find the parent row
  171. if (row) {
  172. // Add hover effect to the entire row on mouseenter
  173. cell.addEventListener('mouseenter', () => {
  174. row.classList.add('vibrant-hover'); // Add hover effect to the row
  175. });
  176. // Remove hover effect on mouseleave
  177. cell.addEventListener('mouseleave', () => {
  178. row.classList.remove('vibrant-hover'); // Remove hover effect from the row
  179. });
  180. }
  181. }
  182. });
  183. }
  184.  
  185. // Function to apply conditional background color to the "Status" column
  186. function applyStatusCellStyle() {
  187. document.querySelectorAll('.ag-cell[col-id="testStatus"]').forEach(cell => {
  188. const statusValue = cell.textContent.trim();
  189. cell.classList.remove('status-verified-level2', 'status-verified-level1', 'status-ordered', 'status-resulted', 'status-cancelled'); // Remove previous styles
  190.  
  191. if (statusValue === "VerifiedLevel2" || statusValue === "VerifiedLevel1") {
  192. cell.classList.add('status-verified-level2');
  193. } else if (statusValue === "Ordered") {
  194. cell.classList.add('status-ordered');
  195. } else if (statusValue === "Resulted") {
  196. cell.classList.add('status-resulted');
  197. } else if (statusValue === "Cancelled") {
  198. cell.classList.add('status-cancelled'); // Apply brown color for Cancelled
  199. }
  200. });
  201.  
  202. // Apply style for Sample Status = Received
  203. document.querySelectorAll('.ag-cell[col-id="sampleStatus"]').forEach(cell => {
  204. if (cell.textContent.trim() === "Received") {
  205. cell.classList.add('status-received');
  206. } else {
  207. cell.classList.remove('status-received'); // Ensure the class is removed if the value changes
  208. }
  209. });
  210. }
  211.  
  212. const observer = new MutationObserver(() => {
  213. applyHoverEffect();
  214. applyStatusCellStyle();
  215. highlightEmergencyRows(); // Call highlightEmergencyRows on every DOM change
  216.  
  217. if (isSpecificPage()) {
  218. hasRunOnce = false; // Reset run flag for repeated executions
  219. initColumnToggle();
  220. }
  221. });
  222.  
  223. // **Important: Observing the correct AG Grid body viewport**
  224. const gridBodyViewport = document.querySelector('.ag-body-viewport'); // Observe the grid body viewport
  225. if (gridBodyViewport) {
  226. observer.observe(gridBodyViewport, { childList: true, subtree: false }); // subtree should be false here as we are observing direct children (rows)
  227. } else {
  228. console.warn("AG Grid body viewport not found. Falling back to body observer.");
  229. observer.observe(document.body, { childList: true, subtree: true });
  230. }
  231.  
  232.  
  233. window.addEventListener('load', () => {
  234. applyHoverEffect();
  235. applyStatusCellStyle();
  236. if (isSpecificPage()) {
  237. initColumnToggle();
  238. }
  239. });
  240.  
  241. // Function to set the dropdown value (keeping this separate as it seems independent)
  242. (function() {
  243. 'use strict';
  244.  
  245. // Function to set the dropdown value
  246. function setDropdownValue() {
  247. const dropdown = document.getElementById("dropdownPaginationPageSize");
  248. if (dropdown && dropdown.value !== "100") {
  249. dropdown.value = "100"; // Set the value to "100"
  250.  
  251. // Trigger the 'change' event
  252. const event = new Event('change', { bubbles: true });
  253. dropdown.dispatchEvent(event);
  254.  
  255. console.log("Dropdown value set to 100");
  256. }
  257. }
  258.  
  259. // Function to observe changes in the DOM for the dropdown
  260. function observeDOMForDropdown() {
  261. const observer = new MutationObserver(() => {
  262. setDropdownValue(); // Check and set the dropdown value when changes are detected
  263. });
  264.  
  265. // Observe the entire document for changes
  266. observer.observe(document.body, {
  267. childList: true,
  268. subtree: true,
  269. });
  270.  
  271. console.log("MutationObserver is active for dropdown");
  272. }
  273.  
  274. // Run the function when the page is fully loaded
  275. window.addEventListener('load', () => {
  276. setDropdownValue(); // Initial check
  277. observeDOMForDropdown(); // Start observing for dynamic changes
  278. });
  279. })();
  280.  
  281. })();

QingJ © 2025

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