From 0114fec928a340624f6be1d6e25ce2cf6679b1c4 Mon Sep 17 00:00:00 2001 From: AIIrondev Date: Tue, 8 Sep 2026 18:19:40 +0200 Subject: [PATCH] changes to the physical scanner processing --- Web/templates/library_table.html | 45 +++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/Web/templates/library_table.html b/Web/templates/library_table.html index 7a45c31..98cbc27 100644 --- a/Web/templates/library_table.html +++ b/Web/templates/library_table.html @@ -843,6 +843,8 @@ let keyboardScanBuffer = ''; let keyboardLastKeyAt = 0; const KEYBOARD_SCAN_INTERCHAR_MS = 100; // max time between keystrokes to consider them one scan + const physicalScanQueue = []; + let keyboardScanProcessing = false; let editLibraryState = { itemId: '', seriesGroupId: '', @@ -1188,38 +1190,49 @@ // Only active when explicitly enabled if (!keyboardScannerEnabled) return; - // Ignore if focus is in an input/textarea/contenteditable to avoid interfering with typing - const active = document.activeElement; - if (active && (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA' || active.isContentEditable)) return; - const now = Date.now(); // If Enter/Return pressed -> finalize buffer if (e.key === 'Enter') { + e.preventDefault(); const code = keyboardScanBuffer.trim(); keyboardScanBuffer = ''; keyboardLastKeyAt = 0; if (!code) return; - // Process exactly like a camera scan - centralized logic handles the rest! - handleScanSuccess(code); + // Scanner keystrokes must not be submitted into the focused form field. + processPhysicalScan(code); return; } - // Only accept common printable characters; ignore modifier keys - if (e.key.length === 1) { + // Physical scanners in this workflow emit numeric codes only. + if (e.key.length === 1 && /\d/.test(e.key)) { // If time gap too big, start new buffer if (keyboardLastKeyAt && (now - keyboardLastKeyAt) > KEYBOARD_SCAN_INTERCHAR_MS) { keyboardScanBuffer = ''; } keyboardScanBuffer += e.key; keyboardLastKeyAt = now; - // Prevent default so scanner input doesn't accidentally move focus or trigger shortcuts + // Prevent default so scanner input is captured even while an input has focus. e.preventDefault(); } } - function handleScanSuccess(decodedText) { + async function processPhysicalScan(code) { + physicalScanQueue.push(code); + if (keyboardScanProcessing) return; + + keyboardScanProcessing = true; + try { + while (physicalScanQueue.length > 0) { + await handleScanSuccess(physicalScanQueue.shift()); + } + } finally { + keyboardScanProcessing = false; + } + } + + async function handleScanSuccess(decodedText) { const scannedCode = typeof normalizeScannedCode === "function" ? normalizeScannedCode(decodedText) : decodedText; if (!scannedCode) return; @@ -1235,26 +1248,27 @@ // 1. Modus: Nur Rückgabe if (mode === 'return_only') { - returnByCode(scannedCode); + await returnByCode(scannedCode); return; } // 2. Modus: Nur Ausweis if (mode === 'card_only') { setActiveStudentCard(scannedCode); - setScanStatus(`Ausweis gesetzt: ${activeStudentCardId}`, 'ok'); + setScanStatus(`Ausweis gesetzt: ${activeStudentCardId}. Bitte den nächsten Ausweis scannen.`, 'ok'); + showSmallConfirm(`Ausweis erkannt: ${activeStudentCardId}. Sie können den nächsten scannen.`, 'ok'); return; } // 3. Modus: Schnellmodus (1x Ausweis, 1x Buch) if (mode === 'quick_toggle') { - processQuickToggleScan(scannedCode); + await processQuickToggleScan(scannedCode); return; } // 4. Modus: Dauermodus (1x Ausweis, Nx Bücher) if (mode === 'continuous') { - processContinuousScan(scannedCode); + await processContinuousScan(scannedCode); return; } } @@ -1341,7 +1355,8 @@ // 2. Wenn kein Ausweis gesetzt ist, wird der Code als Ausweis interpretiert if (!activeStudentCardId) { setActiveStudentCard(scannedCode); - setScanStatus(`Ausweis gesetzt: ${activeStudentCardId}`, 'ok'); + setScanStatus(`Ausweis gesetzt: ${activeStudentCardId}. Bitte den nächsten Mediencode scannen.`, 'ok'); + showSmallConfirm(`Ausweis erkannt: ${activeStudentCardId}. Bitte jetzt den nächsten Mediencode scannen.`, 'ok'); return; }