您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a rapid barcode entry popup for AG Grid filters. With persistent button injection logic.
// ==UserScript== // @name Samples Check with Barcode Popup // @namespace http://tampermonkey.net/ // @version 3.2 // @description Adds a rapid barcode entry popup for AG Grid filters. With persistent button injection logic. // @author Gemini & You // @match *://his.kaauh.org/lab/* // @grant none // ==/UserScript== (function() { 'use strict'; // --- Configuration --- const TARGET_SEARCH_PLACEHOLDER = 'Search by MRN / NationalId & IqamaId'; const TARGET_BARCODE_COLUMN_HEADER = 'Barcode'; // <--- IMPORTANT: This should match the column title exactly. // --- Core Functions --- function clearAllFilters() { console.log("Clearing all filters."); const clearAndNotify = (inputElement) => { if (inputElement && inputElement.value !== '') { inputElement.value = ''; const updateEvent = new Event('input', { bubbles: true }); inputElement.dispatchEvent(updateEvent); } }; const mainSearchInput = document.querySelector(`input[placeholder="${TARGET_SEARCH_PLACEHOLDER}"]`); clearAndNotify(mainSearchInput); const agGridFilters = document.querySelectorAll('input.ag-floating-filter-input'); agGridFilters.forEach(clearAndNotify); } // --- Manual 'Delete' key listener --- document.addEventListener('keydown', (event) => { // Do not trigger if user is typing in the popup if (document.activeElement.id === 'barcode-popup-input') return; if (event.key === 'Delete') { console.log("Manual clear triggered by 'Delete' key."); clearAllFilters(); } }); // --- Barcode Popup Functionality --- function findBarcodeFilterInput() { // 1. Find the header cell containing the title "Barcode" const allTitleSpans = document.querySelectorAll('.ag-header-row[aria-rowindex="1"] .ag-header-cell-text'); let titleHeaderCell = null; allTitleSpans.forEach(span => { if (span.textContent.trim() === TARGET_BARCODE_COLUMN_HEADER) { titleHeaderCell = span.closest('.ag-header-cell'); } }); if (!titleHeaderCell) { console.error(`Could not find a column header with the text: "${TARGET_BARCODE_COLUMN_HEADER}"`); return null; } // 2. Get the horizontal position (left style) of that header cell const targetLeftPosition = titleHeaderCell.style.left; if (!targetLeftPosition) { console.error('Found the barcode header, but it has no "left" style property to match with.'); return null; } // 3. Find the corresponding filter cell in the second header row that has the same horizontal position const allFilterCells = document.querySelectorAll('.ag-header-row[aria-rowindex="2"] .ag-header-cell'); let filterCell = null; allFilterCells.forEach(cell => { if (cell.style.left === targetLeftPosition) { filterCell = cell; } }); if (!filterCell) { console.error(`Found barcode header at left=${targetLeftPosition}, but could not find a filter cell at the same position.`); return null; } // 4. Find the input field within that specific filter cell const filterInput = filterCell.querySelector('input.ag-floating-filter-input'); if (!filterInput) { console.error('Found the correct filter cell, but no input field was inside it.'); return null; } console.log(`Successfully found barcode filter input at left: ${targetLeftPosition}`); return filterInput; } function createBarcodePopup() { // Check if popup already exists and return it if it does let popupContainer = document.getElementById('barcode-popup-container'); if (popupContainer) return popupContainer; popupContainer = document.createElement('div'); popupContainer.id = 'barcode-popup-container'; Object.assign(popupContainer.style, { position: 'fixed', top: '0', left: '0', width: '100%', height: '100%', backgroundColor: 'rgba(0, 0, 0, 0.5)', display: 'none', justifyContent: 'center', alignItems: 'center', zIndex: '10000' }); const popupBox = document.createElement('div'); Object.assign(popupBox.style, { background: '#fff', padding: '25px', borderRadius: '8px', boxShadow: '0 5px 15px rgba(0,0,0,0.3)', textAlign: 'center', width: '350px' }); const popupTitle = document.createElement('h3'); popupTitle.textContent = 'Rapid Barcode Entry'; Object.assign(popupTitle.style, { margin: '0 0 15px 0', color: '#333' }); const popupInput = document.createElement('input'); popupInput.id = 'barcode-popup-input'; popupInput.type = 'text'; popupInput.placeholder = 'Scan or type barcode and press Enter'; Object.assign(popupInput.style, { width: '100%', padding: '10px', fontSize: '16px', border: '2px solid #ccc', borderRadius: '4px' }); popupBox.appendChild(popupTitle); popupBox.appendChild(popupInput); popupContainer.appendChild(popupBox); document.body.appendChild(popupContainer); popupContainer.addEventListener('click', (e) => { if (e.target === popupContainer) { popupContainer.style.display = 'none'; } }); popupInput.addEventListener('keydown', (event) => { if (event.key === 'Enter') { event.preventDefault(); const barcodeValue = popupInput.value.trim(); if (!barcodeValue) return; const barcodeFilterInput = findBarcodeFilterInput(); if (barcodeFilterInput) { barcodeFilterInput.value = barcodeValue; barcodeFilterInput.dispatchEvent(new Event('input', { bubbles: true })); popupInput.value = ''; // Clear for next scan } else { console.error(`Critical Error: Could not find the barcode filter on the page. Make sure a column is named "${TARGET_BARCODE_COLUMN_HEADER}".`); popupInput.style.borderColor = 'red'; setTimeout(() => { popupInput.style.borderColor = '#ccc'; }, 2000); } } }); return popupContainer; } // --- UI Setup --- function addControls(container) { // Create the popup on first run, but don't show it. const popup = createBarcodePopup(); // Add the Barcode Entry Button if it doesn't exist if (!document.getElementById('barcode-entry-btn')) { const barcodeButton = document.createElement('button'); barcodeButton.id = 'barcode-entry-btn'; barcodeButton.textContent = 'Barcode Entry'; Object.assign(barcodeButton.style, { backgroundColor: '#5bc0de', transition: 'background-color 0.3s', padding: '6px 12px', fontSize: '13px', fontWeight: 'bold', borderRadius: '6px', color: '#ffffff', border: '1px solid #285e79', cursor: 'pointer', marginLeft: '8px' }); barcodeButton.addEventListener('click', () => { popup.style.display = 'flex'; document.getElementById('barcode-popup-input').focus(); }); container.appendChild(barcodeButton); console.log('Barcode Entry button added.'); } } // --- Persistent Injection Logic --- function placeButton() { const buttonContainer = document.querySelector('.reset-button-container'); if (buttonContainer) { addControls(buttonContainer); } } // Use a MutationObserver as the primary, efficient method. const observer = new MutationObserver(placeButton); observer.observe(document.body, { childList: true, subtree: true }); // *** NEW: Use a setInterval as a persistent backup *** // This will repeatedly check and ensure the button is present, // catching cases the observer might miss on complex web apps. setInterval(placeButton, 1000); // Check every 1 second })();