KAAUH Lab Enhancement Suite 1 (Buttons, Alerts, Auto-Actions)

Combines verification buttons (F7/F8), dynamic alerts (>, NO RESULT, X-NORESULT, CL/CH) with modals that persist until dismissed, checkbox automation, toggle back-nav.

当前为 2025-04-04 提交的版本,查看 最新版本

// ==UserScript==
// @name         KAAUH Lab Enhancement Suite 1 (Buttons, Alerts, Auto-Actions)
// @namespace    Violentmonkey Scripts
// @version      5.6.2
// @description  Combines verification buttons (F7/F8), dynamic alerts (>, NO RESULT, X-NORESULT, CL/CH) with modals that persist until dismissed, checkbox automation, toggle back-nav.
// @match        *://his.kaauh.org/lab/*
// @grant        none
// @author       Hamad AlShegifi
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    // --- Configuration ---
    const CONFIG = {
        // General & Debugging
        DEBUG_MODE: true,
        PERSISTENT_MODALS: true, // Modals require manual dismissal
        NO_RESULT_MESSAGE: "NO-RESULT DETECTED!!", // Standardized message

        // Script 1: Buttons & Verification
        TARGET_EDIT_PAGE_URL_PREFIX: 'https://his.kaauh.org/lab/#/lab-orders/edit-lab-order/',
        EXCLUDE_WORDS: ['culture', "gram's stain", 'stain', 'bacterial', 'fungal', 'culture', 'pcr', 'Meningitis', 'MRSA', 'Mid', 'stream', 'Cryptococcus'],
        VERIFY1_BUTTON_SELECTOR: '#custom-script-buttons button.btn-success',
        VERIFY2_BUTTON_SELECTOR: '#custom-script-buttons button.btn-primary',
        COMPLETE_TECH_VERIFY_SELECTOR: 'button.dropdown-item[translateid="test-results.CompleteTechnicalVerification"]',
        COMPLETE_MED_VERIFY_SELECTOR: 'button.dropdown-item[translateid="test-results.CompleteMedicalVerification"]',
        FINAL_VERIFY_BUTTON_SELECTOR: 'button.btn-success.btn-sm.min-width[translateid="test-verification.Verify"]',
        NEXT_BUTTON_SELECTOR: 'button#btnNext',
        TEST_DESC_SELECTOR: 'div[col-id="TestDesc"]',
        UNCHECKED_BOX_SELECTOR: 'span.ag-icon-checkbox-unchecked[unselectable="on"]',
        CHECKBOX_PARENT_ROW_SELECTOR: '.ag-row',

        // Script 2: Alerts & Scanning
        SCAN_INTERVAL: 150,
        FLASH_COLOR: "pink",
        FLASH_INTERVAL: 500,
        MODAL_TIMEOUT: 10000,
        RESULT_CELL_SELECTOR: 'div[role="gridcell"][col-id="TestResult"] app-result-value-render div',
        CRITICAL_FLAG_SELECTOR: 'div[role="gridcell"][col-id="LTFlag"] app-ref-high-low div span.critial-alret-indication',

        // Script 3 & General Toast Handling
        UNDEFINED_URL_CHECK_INTERVAL: 200,
        TOAST_CONTAINER_SELECTOR: '#toast-container',
        TOAST_CLOSE_BUTTON_SELECTOR: 'button.toast-close-button',
        SUCCESS_TOAST_SELECTOR: '.toast-success',
    };

    // --- State Variables ---
    let verify1Toggle = localStorage.getItem('verify1Toggle') === 'true';
    let verify2Toggle = localStorage.getItem('verify2Toggle') === 'true';
    let verify1Clicked = false;
    let verify2Clicked = false;
    let issueScanIntervalId = null;
    let isScanningActive = false;
    const activeModals = new Set();

    // --- Utility Functions ---
    function logDebug(message) {
        if (CONFIG.DEBUG_MODE) console.log(`[Lab Suite v5.6] ${message}`);
    }

    function loadFontAwesome() {
        const existingLink = document.querySelector('link[href*="font-awesome"]');
        if (!existingLink) {
            const link = document.createElement('link');
            link.href = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css';
            link.rel = 'stylesheet';
            document.head.appendChild(link);
            logDebug('Font Awesome loaded');
        }
    }

    function isVisible(element) {
        return !!(element && (element.offsetWidth || element.offsetHeight || element.getClientRects().length));
    }

    // --- Modal Functions ---
    function showModal(message) {
        // Remove duplicate modals with same message
        document.querySelectorAll('.lab-suite-modal').forEach(modal => {
            if (modal.textContent.includes(message)) {
                const overlay = document.querySelector('.lab-suite-modal-overlay');
                if (overlay) overlay.remove();
                modal.remove();
            }
        });

        logDebug(`Showing modal: ${message}`);
        const overlay = document.createElement("div");
        overlay.className = 'lab-suite-modal-overlay';
        overlay.style.position = "fixed";
        overlay.style.top = "0";
        overlay.style.left = "0";
        overlay.style.width = "100%";
        overlay.style.height = "100%";
        overlay.style.backgroundColor = "rgba(0, 0, 0, 0.5)";
        overlay.style.zIndex = "2000";
        overlay.style.opacity = "0";
        overlay.style.transition = "opacity 0.3s ease";
        document.body.appendChild(overlay);

        const modal = document.createElement("div");
        modal.className = 'lab-suite-modal';
        modal.style.position = "fixed";
        modal.style.top = "50%";
        modal.style.left = "50%";
        modal.style.transform = "translate(-50%, -50%) scale(0.5)";
        modal.style.backgroundColor = "#f4f4f9";
        modal.style.padding = "30px";
        modal.style.boxShadow = "0px 10px 30px rgba(0, 0, 0, 0.15)";
        modal.style.zIndex = "2001";
        modal.style.borderRadius = "15px";
        modal.style.textAlign = "center";
        modal.style.transition = "transform 0.3s ease, opacity 0.3s ease";
        modal.style.opacity = "0";
        modal.style.maxWidth = "450px";
        modal.setAttribute('role', 'alert');
        modal.setAttribute('aria-live', 'assertive');

        const heading = document.createElement("h2");
        heading.textContent = "Attention!";
        heading.style.fontFamily = "'Arial', sans-serif";
        heading.style.color = "#333";
        heading.style.marginBottom = "10px";
        heading.style.fontSize = "24px";
        modal.appendChild(heading);

        const content = document.createElement("p");
        // Standardize NO RESULT messages
        if (message.includes("NO RESULT") || message.includes("X-NORESULT")) {
            message = CONFIG.NO_RESULT_MESSAGE;
        }
        content.textContent = message;
        content.style.fontFamily = "'Arial', sans-serif";
        content.style.color = "#555";
        content.style.marginBottom = "20px";
        content.style.fontSize = "16px";
        content.style.lineHeight = "1.5";
        modal.appendChild(content);

        const okButton = createModalButton("OK", "#ff4081", () => {
            logDebug("Modal manually dismissed.");
            closeModal(modal, overlay);
        });
        modal.appendChild(okButton);

        document.body.appendChild(modal);

        // Animate appearance
        setTimeout(() => {
            overlay.style.opacity = "1";
            modal.style.transform = "translate(-50%, -50%) scale(1)";
            modal.style.opacity = "1";
        }, 10);

        activeModals.add(modal);
    }

    function createModalButton(text, backgroundColor, onClick) {
        const button = document.createElement("button");
        button.textContent = text;
        button.style.padding = "10px 20px";
        button.style.border = "none";
        button.style.backgroundColor = backgroundColor;
        button.style.color = "white";
        button.style.borderRadius = "30px";
        button.style.cursor = "pointer";
        button.style.fontSize = "16px";
        button.style.transition = "background-color 0.3s ease, transform 0.2s ease";
        button.style.minWidth = '80px';
        button.style.margin = '0 5px';

        button.addEventListener("mouseenter", () => {
            button.style.backgroundColor = darkenColor(backgroundColor, 20);
            button.style.transform = "scale(1.05)";
        });
        button.addEventListener("mouseleave", () => {
            button.style.backgroundColor = backgroundColor;
            button.style.transform = "scale(1)";
        });
        button.addEventListener("click", onClick);
        return button;
    }

    function closeModal(modal, overlay) {
        if (!modal || !overlay || !document.body.contains(modal)) return;
        logDebug("Closing modal.");
        modal.style.transform = "translate(-50%, -50%) scale(0.5)";
        modal.style.opacity = "0";
        overlay.style.opacity = "0";

        setTimeout(() => {
            if (document.body.contains(modal)) document.body.removeChild(modal);
            if (document.body.contains(overlay)) document.body.removeChild(overlay);
            activeModals.delete(modal);
        }, 300);
    }

    function darkenColor(color, percent) {
        try {
            let num = parseInt(color.slice(1), 16);
            let amt = Math.round(2.55 * percent);
            let R = (num >> 16) - amt;
            let G = ((num >> 8) & 0x00ff) - amt;
            let B = (num & 0x0000ff) - amt;
            R = R < 0 ? 0 : R;
            G = G < 0 ? 0 : G;
            B = B < 0 ? 0 : B;
            return `#${(0x1000000 + R * 0x10000 + G * 0x100 + B).toString(16).slice(1)}`;
        } catch (e) {
            logDebug(`Error darkening color ${color}: ${e}`);
            return color;
        }
    }

    // --- Script 1 Functions ---
    function isCorrectPage() {
        return window.location.href.startsWith(CONFIG.TARGET_EDIT_PAGE_URL_PREFIX);
    }

    function createVerifyButton(label, className, onClick) {
        let button = document.createElement('button');
        button.type = 'button';
        button.innerHTML = label;
        button.className = className;

        let buttonColors = {
            'btn btn-success btn-sm': '#28a745',
            'btn btn-primary btn-sm': '#2594d9'
        };

        button.style.cssText = `
            font-family: 'Arial', sans-serif !important;
            font-size: 14px !important;
            font-weight: normal !important;
            color: #ffffff !important;
            background-color: ${buttonColors[className] || '#6c757d'} !important;
            padding: 8px 16px !important;
            border: none !important;
            border-radius: 5px !important;
            text-shadow: none !important;
            cursor: pointer !important;
            margin-right: 5px !important;
            line-height: 1.5 !important;
        `;
        button.onclick = onClick;
        return button;
    }

    function createToggleIcon(id, isActive, onClick) {
        let icon = document.createElement('span');
        icon.id = id;
        icon.innerHTML = `<i class="fa fa-arrow-circle-left" aria-hidden="true" style="color: ${isActive ? '#008000' : '#d1cfcf'}; font-size: 1.3em; vertical-align: middle;"></i>`;
        icon.style.cursor = 'pointer';
        icon.style.marginRight = '10px';
        icon.style.marginLeft = '-1px';
        icon.onclick = onClick;
        icon.title = "Go back after this verification";
        return icon;
    }

    function handleVerify1IconToggle() {
        verify1Toggle = !verify1Toggle;
        localStorage.setItem('verify1Toggle', verify1Toggle);
        const iconElement = document.querySelector('#verify1Icon i');
        if (iconElement) iconElement.style.color = verify1Toggle ? '#008000' : '#d1cfcf';
        logDebug(`Verify1 Toggle set to: ${verify1Toggle}`);
    }

    function handleVerify2IconToggle() {
        verify2Toggle = !verify2Toggle;
        localStorage.setItem('verify2Toggle', verify2Toggle);
        const iconElement = document.querySelector('#verify2Icon i');
        if (iconElement) iconElement.style.color = verify2Toggle ? '#008000' : '#d1cfcf';
        logDebug(`Verify2 Toggle set to: ${verify2Toggle}`);
    }

    function addButtons() {
        if (document.getElementById('custom-script-buttons') || !isCorrectPage()) return;

        const nextButton = document.querySelector(CONFIG.NEXT_BUTTON_SELECTOR);
        if (nextButton && nextButton.parentNode) {
            logDebug("Adding custom VERIFY buttons.");
            let buttonDiv = document.createElement('div');
            buttonDiv.id = 'custom-script-buttons';
            buttonDiv.style.display = 'inline-block';
            buttonDiv.style.marginLeft = '10px';
            buttonDiv.style.verticalAlign = 'middle';

            // VERIFY1 Button & Toggle
            let verify1Button = createVerifyButton('VERIFY1 (F7)', 'btn btn-success btn-sm', () => {
                logDebug("VERIFY1 button clicked.");
                verify1Clicked = true;
                verify2Clicked = false;
                checkAllVisibleBoxesWithoutDuplicates();
                setTimeout(() => { clickCompleteTechnicalVerificationButton(); }, 500);
            });
            let verify1Icon = createToggleIcon('verify1Icon', verify1Toggle, handleVerify1IconToggle);

            // VERIFY2 Button & Toggle
            let verify2Button = createVerifyButton('VERIFY2 (F8)', 'btn btn-primary btn-sm', () => {
                logDebug("VERIFY2 button clicked.");
                verify2Clicked = true;
                verify1Clicked = false;
                checkAllVisibleBoxesWithoutDuplicates();
                setTimeout(() => { clickCompleteMedicalVerificationButton(); }, 500);
            });
            let verify2Icon = createToggleIcon('verify2Icon', verify2Toggle, handleVerify2IconToggle);

            // Author Credit
            let modedByText = document.createElement('span');
            modedByText.textContent = "Moded by: Hamad AlShegifi";
            modedByText.style.fontSize = '12px';
            modedByText.style.fontWeight = 'bold';
            modedByText.style.color = '#ff0000';
            modedByText.style.position = 'relative';
            modedByText.style.left = '0px';
            modedByText.style.top = '0px';
            modedByText.style.border = '1.5px solid #ff0000';
            modedByText.style.borderRadius = '8px';
            modedByText.style.padding = '4px';
            modedByText.style.backgroundColor = 'white';

            buttonDiv.appendChild(verify1Button);
            buttonDiv.appendChild(verify1Icon);
            buttonDiv.appendChild(verify2Button);
            buttonDiv.appendChild(verify2Icon);
            buttonDiv.appendChild(modedByText);

            nextButton.parentNode.insertBefore(buttonDiv, nextButton.nextSibling);
        } else {
            logDebug("Could not find Next button to anchor custom buttons.");
        }
    }

    function checkAllVisibleBoxesWithoutDuplicates() {
        logDebug("Checking checkboxes...");
        const testDivs = document.querySelectorAll(CONFIG.TEST_DESC_SELECTOR);
        let seenTests = new Set();
        let boxesChecked = 0;
        const excludeWordsLower = CONFIG.EXCLUDE_WORDS.map(word => word.toLowerCase());

        testDivs.forEach(testDiv => {
            const testName = testDiv.textContent?.trim().toLowerCase() || '';
            if (!testName) return;

            if (excludeWordsLower.some(word => testName.includes(word))) {
                return;
            }

            if (seenTests.has(testName)) {
                return;
            }

            seenTests.add(testName);
            const parentRow = testDiv.closest(CONFIG.CHECKBOX_PARENT_ROW_SELECTOR);
            if (parentRow) {
                const checkbox = parentRow.querySelector(CONFIG.UNCHECKED_BOX_SELECTOR);
                if (checkbox && isVisible(checkbox)) {
                    logDebug(`Clicking checkbox for test: ${testName}`);
                    const event = new MouseEvent('click', { bubbles: true, cancelable: true, view: window });
                    checkbox.dispatchEvent(event);
                    boxesChecked++;
                }
            }
        });
        logDebug(`${boxesChecked} unique, non-excluded checkboxes were checked.`);
    }

    function clickCompleteTechnicalVerificationButton() {
        const button = document.querySelector(CONFIG.COMPLETE_TECH_VERIFY_SELECTOR);
        if (button) {
            button.click();
            logDebug("Complete Technical Verification button clicked!");
            setTimeout(() => { clickFinalVerifyButton(); }, 700);
        } else {
            logDebug("Complete Technical Verification button not found!");
            showModal("Error: Unable to find the 'Complete Technical Verification' button.");
        }
    }

    function clickCompleteMedicalVerificationButton() {
        const button = document.querySelector(CONFIG.COMPLETE_MED_VERIFY_SELECTOR);
        if (button) {
            button.click();
            logDebug("Complete Medical Verification button clicked!");
            setTimeout(() => { clickFinalVerifyButton(); }, 700);
        } else {
            logDebug("Complete Medical Verification button not found!");
            showModal("Error: Unable to find the 'Complete Medical Verification' button.");
        }
    }

    function clickFinalVerifyButton() {
        const verifyButton = document.querySelector(CONFIG.FINAL_VERIFY_BUTTON_SELECTOR);
        if (verifyButton) {
            verifyButton.click();
            logDebug("Final Verify button clicked!");
        } else {
            logDebug("Final Verify button not found!");
            showModal("Error: Unable to find the final 'Verify' button.");
        }
    }

    // --- Script 2 Functions ---
    function applyFlashingEffect(rows) {
        rows.forEach(row => {
            if (row.dataset.flashing) return;
            row.dataset.flashing = 'true';
            logDebug("Applying flashing effect to a row.");

            row.style.transition = "background-color 0.5s ease";
            let isPink = false;
            const originalBg = row.style.backgroundColor || 'transparent';

            const intervalId = setInterval(() => {
                if (!document.contains(row)) {
                    clearInterval(intervalId);
                    delete row.dataset.flashing;
                    return;
                }
                isPink = !isPink;
                row.style.backgroundColor = isPink ? CONFIG.FLASH_COLOR : originalBg;
            }, CONFIG.FLASH_INTERVAL);

            row.dataset.flashIntervalId = intervalId;
        });
    }

    function getNotificationSessionKey(type, identifier = 'general') {
        return `labSuiteNotified_${window.location.pathname}_${type}_${identifier}`;
    }

    function hasAlreadyNotified(type, identifier = 'general') {
        const key = getNotificationSessionKey(type, identifier);
        return sessionStorage.getItem(key) === 'true';
    }

    function setNotificationFlag(type, identifier = 'general') {
        const key = getNotificationSessionKey(type, identifier);
        logDebug(`Setting notification flag for key: ${key}`);
        sessionStorage.setItem(key, 'true');
    }

    function checkForIssues() {
        const resultDivs = document.querySelectorAll(CONFIG.RESULT_CELL_SELECTOR);
        const criticalDivs = document.querySelectorAll(CONFIG.CRITICAL_FLAG_SELECTOR);

        function scrollToRow(element) {
            const row = element.closest(CONFIG.CHECKBOX_PARENT_ROW_SELECTOR);
            if (row) {
                const rowId = row.getAttribute('row-id');
                logDebug(`Scrolling to row: ${rowId || 'ID not found'}`);
                row.scrollIntoView({ behavior: 'smooth', block: 'center' });
                const originalBg = row.style.backgroundColor;
                row.style.backgroundColor = 'yellow';
                setTimeout(() => {
                    if (row.style.backgroundColor === 'yellow') {
                        row.style.backgroundColor = originalBg;
                    }
                }, 2000);
                return { scrolled: true, rowId: rowId };
            }
            return { scrolled: false };
        }

        let alertShownThisCycle = false;

        // 1. Check for Critical Flags (CL/CH)
        if (!alertShownThisCycle && !hasAlreadyNotified('critical')) {
            criticalDivs.forEach(div => {
                if (alertShownThisCycle) return;

                const text = div.textContent?.trim() || '';
                if (text === "CL" || text === "CH") {
                    const scrollResult = scrollToRow(div);
                    if (scrollResult.scrolled) {
                        const specificRowKey = scrollResult.rowId || text;
                        if (!hasAlreadyNotified('critical', specificRowKey)) {
                            logDebug(`Found ${text} for row ${specificRowKey}`);
                            const message = text === "CL" ? "CRITICAL LOW RESULT DETECTED !!" : "CRITICAL HIGH RESULT DETECTED !!";
                            showModal(message);
                            setNotificationFlag('critical', specificRowKey);
                            setNotificationFlag('critical');
                            alertShownThisCycle = true;
                        }
                    }
                }
            });
        }

        // 2. Check for "NO RESULT" / "X-NORESULT"
        if (!alertShownThisCycle && !hasAlreadyNotified('noresult')) {
            resultDivs.forEach(div => {
                if (alertShownThisCycle) return;

                const text = div.textContent?.trim().toLowerCase() || '';
                const isNoResultType = (text === "no result" || text === "no-xresult" || text === "x-noresult");

                if (isNoResultType) {
                    const scrollResult = scrollToRow(div);
                    if (scrollResult.scrolled) {
                        const specificRowKey = scrollResult.rowId || text.replace(/[\s-]+/g, '_');
                        if (!hasAlreadyNotified('noresult', specificRowKey)) {
                            logDebug(`Found ${text} for row ${specificRowKey}`);
                            showModal(CONFIG.NO_RESULT_MESSAGE);
                            setNotificationFlag('noresult', specificRowKey);
                            setNotificationFlag('noresult');
                            alertShownThisCycle = true;
                        }
                    }
                }
            });
        }

        // 3. Check for ">" (Dilution Required)
        if (!alertShownThisCycle) {
            resultDivs.forEach(div => {
                const text = div.textContent?.trim().toLowerCase() || '';
                if (text.includes(">")) {
                    const rowElement = div.closest(CONFIG.CHECKBOX_PARENT_ROW_SELECTOR);
                    const rowId = rowElement?.getAttribute('row-id') || text;
                    const eventKey = `greaterThan_${rowId}`;

                    if (!hasAlreadyNotified('greaterThan', rowId)) {
                        if (rowElement) {
                            logDebug(`Found '>' for row ${rowId}`);
                            applyFlashingEffect([rowElement]);
                            showModal("Dilution is required for this sample (> detected)!");
                            setNotificationFlag('greaterThan', rowId);
                        }
                    }
                }
            });
        }

        return alertShownThisCycle;
    }

    function startContinuousScanning() {
        if (isScanningActive) return;
        logDebug("Starting continuous issue scanning...");
        isScanningActive = true;

        if (issueScanIntervalId) clearInterval(issueScanIntervalId);

        issueScanIntervalId = setInterval(() => {
            const resultsGridExists = document.querySelector(CONFIG.RESULT_CELL_SELECTOR) || document.querySelector(CONFIG.CRITICAL_FLAG_SELECTOR);
            if (!resultsGridExists) {
                logDebug("Monitored elements disappeared, stopping issue scan.");
                stopContinuousScanning();
                return;
            }
            checkForIssues();
        }, CONFIG.SCAN_INTERVAL);
    }

    function stopContinuousScanning() {
        if (issueScanIntervalId) {
            clearInterval(issueScanIntervalId);
            issueScanIntervalId = null;
            logDebug("Stopped continuous issue scanning.");
        }
        isScanningActive = false;
    }

    // --- Script 3 Function ---
    function checkUrlAndTriggerClickForUndefined() {
        const currentUrl = window.location.href;
        if (currentUrl.endsWith('/undefined')) {
            const toastContainer = document.querySelector(CONFIG.TOAST_CONTAINER_SELECTOR);
            if (toastContainer) {
                const closeButton = toastContainer.querySelector(CONFIG.TOAST_CLOSE_BUTTON_SELECTOR);
                if (closeButton && isVisible(closeButton)) {
                    logDebug('URL ends with /undefined. Found visible toast close button. Clicking...');
                    closeButton.click();
                }
            }
        }
    }

    // --- Event Listeners & Observers ---
    document.addEventListener('keydown', function (event) {
        if (event.key === 'F7') {
            event.preventDefault();
            logDebug("F7 pressed: Triggering VERIFY1 button click");
            const verify1Button = document.querySelector(CONFIG.VERIFY1_BUTTON_SELECTOR);
            if (verify1Button) verify1Button.click();
            else logDebug("VERIFY1 button not found for F7.");
        } else if (event.key === 'F8') {
            event.preventDefault();
            logDebug("F8 pressed: Triggering VERIFY2 button click");
            const verify2Button = document.querySelector(CONFIG.VERIFY2_BUTTON_SELECTOR);
            if (verify2Button) verify2Button.click();
            else logDebug("VERIFY2 button not found for F8.");
        }
    });

    const toastObserver = new MutationObserver((mutations) => {
        mutations.forEach(mutation => {
            mutation.addedNodes.forEach(node => {
                if (node.nodeType === Node.ELEMENT_NODE && node.matches && node.matches(CONFIG.SUCCESS_TOAST_SELECTOR)) {
                    logDebug('Success toast added. Adding click listener for back navigation.');
                    node.addEventListener('click', () => {
                        logDebug('Success toast clicked.');
                        if (verify1Clicked && verify1Toggle) {
                            logDebug('Verify1 was clicked and toggle is on. Going back.');
                            window.history.back();
                        } else if (verify2Clicked && verify2Toggle) {
                            logDebug('Verify2 was clicked and toggle is on. Going back.');
                            window.history.back();
                        }
                        verify1Clicked = false;
                        verify2Clicked = false;
                    });
                }
            });
        });
    });

    const mainObserver = new MutationObserver(() => {
        if (isCorrectPage()) {
            addButtons();
        } else {
            const buttonDiv = document.getElementById('custom-script-buttons');
            if (buttonDiv) {
                logDebug("Leaving edit page, removing custom buttons.");
                buttonDiv.remove();
            }
        }

        const resultsGridExists = document.querySelector(CONFIG.RESULT_CELL_SELECTOR) || document.querySelector(CONFIG.CRITICAL_FLAG_SELECTOR);
        if (resultsGridExists) {
            if (!isScanningActive) {
                startContinuousScanning();
            }
        } else {
            if (isScanningActive) {
                stopContinuousScanning();
            }
        }
    });

    // --- Initialization ---
    try {
        logDebug("KAAUH Lab Enhancement Suite Initializing (v5.6)...");
        loadFontAwesome();

        setInterval(checkUrlAndTriggerClickForUndefined, CONFIG.UNDEFINED_URL_CHECK_INTERVAL);
        logDebug(`Started URL check interval (${CONFIG.UNDEFINED_URL_CHECK_INTERVAL}ms) for /undefined toasts.`);

        mainObserver.observe(document.body, { childList: true, subtree: true });
        logDebug("Started main MutationObserver.");

        toastObserver.observe(document.body, { childList: true, subtree: true });
        logDebug("Started toast MutationObserver for back-navigation.");

        window.addEventListener('load', () => {
            logDebug("Page fully loaded. Performing initial checks.");
            if (isCorrectPage()) { addButtons(); }
            const resultsGridExists = document.querySelector(CONFIG.RESULT_CELL_SELECTOR) || document.querySelector(CONFIG.CRITICAL_FLAG_SELECTOR);
            if (resultsGridExists && !isScanningActive) {
                startContinuousScanning();
            }
        });

        logDebug("Initialization complete.");

    } catch (error) {
        console.error("[Lab Suite] Critical error during initialization:", error);
        showModal("A critical error occurred in the Lab Enhancement Suite. Please check the browser console (F12) for details.");
    }
})();

QingJ © 2025

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