From 6bb3927ca3a6e53abe63d9f3b6be4055123a109f Mon Sep 17 00:00:00 2001 From: data Date: Tue, 17 Feb 2026 11:22:23 +0100 Subject: [PATCH] Fix: Allow scanner to attempt camera access without HTTPS In test environments without HTTPS, the camera may still work depending on browser settings. Now shows warning instead of blocking completely. Co-Authored-By: Claude Opus 4.5 --- js/scanner.js | 85 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 79 insertions(+), 6 deletions(-) diff --git a/js/scanner.js b/js/scanner.js index 7274781..1462209 100644 --- a/js/scanner.js +++ b/js/scanner.js @@ -27,6 +27,7 @@ let currentProduct = null; let selectedSupplier = null; let allSuppliers = []; + let quaggaInitialized = false; // DOM Elements (will be set on init) let elements = {}; @@ -48,10 +49,54 @@ return; } + // Check for camera support + checkCameraSupport(); + bindEvents(); loadAllSuppliers(); } + // Check camera support and show appropriate messages + function checkCameraSupport() { + // Check HTTPS (required for camera access except on localhost) + // Note: In test environments without HTTPS, camera may not work but we still allow trying + const isSecure = location.protocol === 'https:' || location.hostname === 'localhost' || location.hostname === '127.0.0.1'; + + if (!isSecure) { + // Show warning but don't disable - some browsers/configs may still work + console.warn('HandyBarcodeScanner: HTTPS empfohlen für Kamerazugriff'); + } + + // Check if getUserMedia is supported + if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { + showCameraError('Kamera wird von diesem Browser nicht unterstützt'); + elements.startBtn.disabled = true; + elements.startBtn.classList.add('butActionRefused'); + elements.startBtn.classList.remove('butAction'); + return; + } + + // Check if Quagga is loaded + if (typeof Quagga === 'undefined') { + showCameraError('Scanner-Bibliothek nicht geladen'); + elements.startBtn.disabled = true; + elements.startBtn.classList.add('butActionRefused'); + elements.startBtn.classList.remove('butAction'); + return; + } + + // All checks passed - enable button + elements.startBtn.disabled = false; + } + + function showCameraError(message) { + const errorDiv = document.createElement('div'); + errorDiv.className = 'error-message'; + errorDiv.style.cssText = 'position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: #fff; text-align: center; padding: 20px;'; + errorDiv.innerHTML = '
⚠️
' + message + '
'; + elements.videoContainer.appendChild(errorDiv); + } + // Event Bindings function bindEvents() { elements.startBtn.addEventListener('click', startScanner); @@ -73,6 +118,7 @@ // Scanner Functions function startScanner() { if (isScanning) return; + if (elements.startBtn.disabled) return; // Check if Quagga is available if (typeof Quagga === 'undefined') { @@ -80,6 +126,10 @@ return; } + // Disable button while initializing + elements.startBtn.disabled = true; + elements.startBtn.textContent = 'Initialisiere...'; + Quagga.init({ inputStream: { name: "Live", @@ -87,8 +137,8 @@ target: elements.videoContainer, constraints: { facingMode: "environment", - width: { ideal: 1280 }, - height: { ideal: 720 } + width: { min: 640, ideal: 1280, max: 1920 }, + height: { min: 480, ideal: 720, max: 1080 } } }, decoder: { @@ -104,25 +154,48 @@ }, function(err) { if (err) { console.error('Quagga init error:', err); - showToast(CONFIG.lang.cameraError, 'error'); + elements.startBtn.disabled = false; + elements.startBtn.textContent = CONFIG.lang.startScan || 'Scan starten'; + + // Show specific error message + let errorMsg = CONFIG.lang.cameraError || 'Kamerafehler'; + if (err.name === 'NotAllowedError') { + errorMsg = 'Kamerazugriff verweigert. Bitte Berechtigung erteilen.'; + } else if (err.name === 'NotFoundError') { + errorMsg = 'Keine Kamera gefunden.'; + } else if (err.name === 'NotReadableError') { + errorMsg = 'Kamera wird bereits verwendet.'; + } + showToast(errorMsg, 'error'); return; } + + // Success - start scanning Quagga.start(); + quaggaInitialized = true; isScanning = true; elements.startBtn.classList.add('hidden'); elements.stopBtn.classList.remove('hidden'); elements.videoContainer.classList.add('scanning'); - }); - Quagga.onDetected(onBarcodeDetected); + // Register detection handler + Quagga.onDetected(onBarcodeDetected); + }); } function stopScanner() { if (!isScanning) return; - Quagga.stop(); + if (quaggaInitialized) { + Quagga.offDetected(onBarcodeDetected); + Quagga.stop(); + } + isScanning = false; + quaggaInitialized = false; elements.startBtn.classList.remove('hidden'); + elements.startBtn.disabled = false; + elements.startBtn.textContent = CONFIG.lang.startScan || 'Scan starten'; elements.stopBtn.classList.add('hidden'); elements.videoContainer.classList.remove('scanning'); }