Changes from the deprecated qrcode scanning tool, to a more modern option in the library
This commit is contained in:
+61
-26
@@ -205,8 +205,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@ericblade/quagga2/dist/quagga.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/html5-qrcode/minified/html5-qrcode.min.js"></script>
|
|
||||||
<script>
|
<script>
|
||||||
// View mode persistence
|
// View mode persistence
|
||||||
const LIBRARY_VIEW_MODE_KEY = 'inventarLibraryViewMode';
|
const LIBRARY_VIEW_MODE_KEY = 'inventarLibraryViewMode';
|
||||||
@@ -632,43 +631,79 @@ document.getElementById('favoriteToggle').addEventListener('click', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Scanner toggle
|
// Scanner toggle
|
||||||
let scanner = null;
|
l// Scanner state tracking
|
||||||
|
let isScanning = false;
|
||||||
|
|
||||||
document.getElementById('scannerBtn').addEventListener('click', function(e) {
|
document.getElementById('scannerBtn').addEventListener('click', function(e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const container = document.getElementById('qrContainer');
|
const container = document.getElementById('qrContainer');
|
||||||
const isOpen = container.style.display !== 'none';
|
const isOpen = container.style.display !== 'none';
|
||||||
|
const btn = this;
|
||||||
|
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
|
// Close the scanner
|
||||||
container.style.display = 'none';
|
container.style.display = 'none';
|
||||||
if (scanner) scanner.clear();
|
Quagga.stop();
|
||||||
this.classList.remove('open');
|
isScanning = false;
|
||||||
this.setAttribute('aria-expanded', 'false');
|
|
||||||
} else {
|
|
||||||
container.style.display = 'block';
|
|
||||||
this.classList.add('open');
|
|
||||||
this.setAttribute('aria-expanded', 'true');
|
|
||||||
|
|
||||||
if (!scanner) {
|
btn.classList.remove('open');
|
||||||
scanner = new Html5Qrcode('qr-reader');
|
btn.setAttribute('aria-expanded', 'false');
|
||||||
scanner.start(
|
} else {
|
||||||
{ facingMode: "environment" },
|
// Open the scanner
|
||||||
{ fps: 10, qrbox: 250 },
|
container.style.display = 'block';
|
||||||
onScanSuccess,
|
btn.classList.add('open');
|
||||||
onScanError
|
btn.setAttribute('aria-expanded', 'true');
|
||||||
);
|
|
||||||
}
|
Quagga.init({
|
||||||
|
inputStream: {
|
||||||
|
name: "Live",
|
||||||
|
type: "LiveStream",
|
||||||
|
// Targets the element where the video stream will inject
|
||||||
|
target: document.querySelector('#qr-reader'),
|
||||||
|
constraints: {
|
||||||
|
width: 640,
|
||||||
|
height: 480,
|
||||||
|
facingMode: "environment" // Forces back camera
|
||||||
|
},
|
||||||
|
},
|
||||||
|
decoder: {
|
||||||
|
// Optimized for 1D barcodes (e.g., student IDs, member cards)
|
||||||
|
readers: ["code_128_reader", "ean_reader", "code_39_reader", "upc_reader"]
|
||||||
|
}
|
||||||
|
}, function(err) {
|
||||||
|
if (err) {
|
||||||
|
console.error("Initialization error:", err);
|
||||||
|
alert("Kamera konnte nicht gestartet werden.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Quagga.start();
|
||||||
|
isScanning = true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function onScanSuccess(decodedText, decodedResult) {
|
// Single Quagga event listener for successful scans
|
||||||
const studentId = decodedText.trim();
|
Quagga.onDetected(function(data) {
|
||||||
|
const decodedText = data.codeResult.code;
|
||||||
|
const studentId = String(decodedText || '').trim();
|
||||||
|
|
||||||
|
// Stop scanning immediately to prevent multiple triggers
|
||||||
|
Quagga.stop();
|
||||||
|
isScanning = false;
|
||||||
|
|
||||||
|
// Reset UI states to closed
|
||||||
|
const container = document.getElementById('qrContainer');
|
||||||
|
const btn = document.getElementById('scannerBtn');
|
||||||
|
if (container) container.style.display = 'none';
|
||||||
|
if (btn) {
|
||||||
|
btn.classList.remove('open');
|
||||||
|
btn.setAttribute('aria-expanded', 'false');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Route the scanned data to your input
|
||||||
document.getElementById('studentIdInput').value = studentId;
|
document.getElementById('studentIdInput').value = studentId;
|
||||||
alert('Ausweis gescannt: ' + studentId);
|
alert('Ausweis gescannt: ' + studentId);
|
||||||
}
|
});
|
||||||
|
|
||||||
function onScanError(error) {
|
|
||||||
// Silently ignore scan errors
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
+103
-41
@@ -525,8 +525,7 @@
|
|||||||
|
|
||||||
window.isDebug = false; // Set to true only for development environment
|
window.isDebug = false; // Set to true only for development environment
|
||||||
</script>
|
</script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@ericblade/quagga2/dist/quagga.js"></script>
|
||||||
<script src="https://unpkg.com/html5-qrcode@2.0.9/dist/html5-qrcode.min.js"></script>
|
|
||||||
<script>
|
<script>
|
||||||
// Global state
|
// Global state
|
||||||
const highlightItemId = (window.serverVars && window.serverVars.highlightItemId && window.serverVars.highlightItemId !== 'null')
|
const highlightItemId = (window.serverVars && window.serverVars.highlightItemId && window.serverVars.highlightItemId !== 'null')
|
||||||
@@ -535,51 +534,114 @@
|
|||||||
let codeSearchTerm = '';
|
let codeSearchTerm = '';
|
||||||
let descSearchIds = null; // Set of matching IDs or null when disabled
|
let descSearchIds = null; // Set of matching IDs or null when disabled
|
||||||
|
|
||||||
// QR scanner toggle setup
|
// Keep track of the scanner state globally/outer scope
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
let isScanning = false;
|
||||||
const scanButton = document.getElementById('scanButton');
|
let activeScannerCallback = null; // Tracks which function currently owns the scanner output
|
||||||
|
|
||||||
|
function startScanner(targetCallback) {
|
||||||
const qrReader = document.getElementById('qr-reader');
|
const qrReader = document.getElementById('qr-reader');
|
||||||
let html5QrcodeScanner = null;
|
const statusText = document.getElementById('status');
|
||||||
|
|
||||||
if (!scanButton || !qrReader) return;
|
// Store the custom action that should happen when a barcode is found
|
||||||
|
activeScannerCallback = targetCallback;
|
||||||
|
|
||||||
const setScannerUi = (isOpen) => {
|
// Show the container
|
||||||
scanButton.classList.toggle('is-active', isOpen);
|
if (qrReader) qrReader.style.display = 'block';
|
||||||
scanButton.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
|
if (statusText) statusText.innerText = "Initializing camera...";
|
||||||
scanButton.textContent = isOpen ? 'Scanner schliessen' : 'Barcode scannen';
|
|
||||||
};
|
|
||||||
|
|
||||||
scanButton.addEventListener('click', function() {
|
Quagga.init({
|
||||||
if (qrReader.style.display !== 'block') {
|
inputStream: {
|
||||||
qrReader.style.display = 'block';
|
name: "Live",
|
||||||
|
type: "LiveStream",
|
||||||
html5QrcodeScanner = new Html5QrcodeScanner(
|
// Make sure this targets your correct HTML container element
|
||||||
'qr-reader', { fps: 10, qrbox: 250 }
|
target: document.querySelector('#scanner-container'),
|
||||||
);
|
constraints: {
|
||||||
|
width: 640,
|
||||||
html5QrcodeScanner.render((decodedText) => {
|
height: 480,
|
||||||
html5QrcodeScanner.clear();
|
facingMode: "environment" // Force rear camera
|
||||||
qrReader.style.display = 'none';
|
},
|
||||||
|
},
|
||||||
// Put scanned code into the search box and trigger search
|
decoder: {
|
||||||
const searchInput = document.getElementById('code-search');
|
// Your required formats mapped to Quagga2 reader strings
|
||||||
if (searchInput) {
|
readers: ["code_128_reader", "ean_reader", "code_39_reader", "upc_reader"]
|
||||||
searchInput.value = decodedText;
|
}
|
||||||
searchByCode();
|
}, function(err) {
|
||||||
}
|
if (err) {
|
||||||
|
console.error("Initialization error:", err);
|
||||||
setScannerUi(false);
|
if (statusText) statusText.innerText = "Camera Error";
|
||||||
});
|
return;
|
||||||
|
|
||||||
setScannerUi(true);
|
|
||||||
} else {
|
|
||||||
if (html5QrcodeScanner) {
|
|
||||||
html5QrcodeScanner.clear();
|
|
||||||
}
|
|
||||||
qrReader.style.display = 'none';
|
|
||||||
setScannerUi(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Quagga.start();
|
||||||
|
isScanning = true;
|
||||||
|
|
||||||
|
// If we are using the main search button, manage its UI state
|
||||||
|
if (!targetCallback) {
|
||||||
|
setScannerUi(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (statusText) statusText.innerText = "Scanning...";
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopScanner() {
|
||||||
|
Quagga.stop();
|
||||||
|
isScanning = false;
|
||||||
|
activeScannerCallback = null; // Reset the callback routing
|
||||||
|
|
||||||
|
const qrReader = document.getElementById('qr-reader');
|
||||||
|
if (qrReader) qrReader.style.display = 'none';
|
||||||
|
|
||||||
|
setScannerUi(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setScannerUi(isOpen) {
|
||||||
|
const scanBtn = document.getElementById('scanButton');
|
||||||
|
if (!scanBtn) return;
|
||||||
|
|
||||||
|
scanBtn.classList.toggle('is-active', isOpen);
|
||||||
|
scanBtn.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
|
||||||
|
scanBtn.textContent = isOpen ? 'Scanner schliessen' : 'Barcode scannen';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unified global reader callback
|
||||||
|
Quagga.onDetected(function(data) {
|
||||||
|
const barcode = String(data.codeResult.code || '').trim();
|
||||||
|
console.log("Barcode detected:", barcode);
|
||||||
|
|
||||||
|
// Keep a local reference to the active callback before shutting down the engine
|
||||||
|
const currentCallback = activeScannerCallback;
|
||||||
|
|
||||||
|
// Critical: Stop scanning immediately to prevent multiple triggers
|
||||||
|
stopScanner();
|
||||||
|
|
||||||
|
// Route data based on who opened the scanner
|
||||||
|
if (typeof currentCallback === "function") {
|
||||||
|
// Send data directly to the specific edit field's logic
|
||||||
|
currentCallback(barcode);
|
||||||
|
} else {
|
||||||
|
// Fallback Default: Main search box logic
|
||||||
|
const resultText = document.getElementById('barcode-result');
|
||||||
|
if (resultText) resultText.innerText = barcode;
|
||||||
|
|
||||||
|
const searchInput = document.getElementById('code-search');
|
||||||
|
if (searchInput) {
|
||||||
|
searchInput.value = barcode;
|
||||||
|
if (typeof searchByCode === "function") {
|
||||||
|
searchByCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Event Listener for the main standalone search button
|
||||||
|
document.getElementById('scanButton')?.addEventListener('click', function() {
|
||||||
|
if (!isScanning) {
|
||||||
|
// Pass null so it defaults to filling the standard search box
|
||||||
|
startScanner(null);
|
||||||
|
} else {
|
||||||
|
stopScanner();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Return preferred primary and fallback image URLs based on extension
|
// Return preferred primary and fallback image URLs based on extension
|
||||||
|
|||||||
@@ -2436,7 +2436,7 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
|||||||
<div class="qr-container">
|
<div class="qr-container">
|
||||||
<button id="scanButton" class="scan-button" aria-controls="qr-reader" aria-expanded="false">Barcode scannen</button>
|
<button id="scanButton" class="scan-button" aria-controls="qr-reader" aria-expanded="false">Barcode scannen</button>
|
||||||
<div id="qr-reader" style="display: none;">
|
<div id="qr-reader" style="display: none;">
|
||||||
<h3>Status: <span id="status">Ready</span></h3>
|
<h3>Status: <span id="status">Bereit</span></h3>
|
||||||
<div id="scanner-container"></div>
|
<div id="scanner-container"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -2733,7 +2733,6 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
|||||||
window.isDebug = false; // Set to true only for development environment
|
window.isDebug = false; // Set to true only for development environment
|
||||||
</script>
|
</script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/@ericblade/quagga2/dist/quagga.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/@ericblade/quagga2/dist/quagga.js"></script>
|
||||||
<script src="/static/js/scanner.js"></script>
|
|
||||||
<script>
|
<script>
|
||||||
// Function to check if a file is a video
|
// Function to check if a file is a video
|
||||||
function isVideoFile(filename) {
|
function isVideoFile(filename) {
|
||||||
@@ -2771,14 +2770,18 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
|||||||
// No-op in production
|
// No-op in production
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep track of the scanner state globally/outer scope
|
// Keep track of the scanner state globally/outer scope
|
||||||
let isScanning = false;
|
let isScanning = false;
|
||||||
|
let activeScannerCallback = null; // Tracks which function currently owns the scanner output
|
||||||
|
|
||||||
function startScanner() {
|
function startScanner(targetCallback) {
|
||||||
const qrReader = document.getElementById('qr-reader');
|
const qrReader = document.getElementById('qr-reader');
|
||||||
const statusText = document.getElementById('status');
|
const statusText = document.getElementById('status');
|
||||||
|
|
||||||
|
// Store the custom action that should happen when a barcode is found
|
||||||
|
activeScannerCallback = targetCallback;
|
||||||
|
|
||||||
// Show the container
|
// Show the container
|
||||||
if (qrReader) qrReader.style.display = 'block';
|
if (qrReader) qrReader.style.display = 'block';
|
||||||
if (statusText) statusText.innerText = "Initializing camera...";
|
if (statusText) statusText.innerText = "Initializing camera...";
|
||||||
@@ -2808,7 +2811,12 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
|||||||
|
|
||||||
Quagga.start();
|
Quagga.start();
|
||||||
isScanning = true;
|
isScanning = true;
|
||||||
setScannerUi(true);
|
|
||||||
|
// If we are using the main search button, manage its UI state
|
||||||
|
if (!targetCallback) {
|
||||||
|
setScannerUi(true);
|
||||||
|
}
|
||||||
|
|
||||||
if (statusText) statusText.innerText = "Scanning...";
|
if (statusText) statusText.innerText = "Scanning...";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -2816,6 +2824,7 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
|||||||
function stopScanner() {
|
function stopScanner() {
|
||||||
Quagga.stop();
|
Quagga.stop();
|
||||||
isScanning = false;
|
isScanning = false;
|
||||||
|
activeScannerCallback = null; // Reset the callback routing
|
||||||
|
|
||||||
const qrReader = document.getElementById('qr-reader');
|
const qrReader = document.getElementById('qr-reader');
|
||||||
if (qrReader) qrReader.style.display = 'none';
|
if (qrReader) qrReader.style.display = 'none';
|
||||||
@@ -2832,37 +2841,46 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
|||||||
scanBtn.textContent = isOpen ? 'Scanner schliessen' : 'Barcode scannen';
|
scanBtn.textContent = isOpen ? 'Scanner schliessen' : 'Barcode scannen';
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Quagga event listener for successful scans
|
// Unified global reader callback
|
||||||
Quagga.onDetected(function(data) {
|
Quagga.onDetected(function(data) {
|
||||||
const barcode = data.codeResult.code;
|
const barcode = String(data.codeResult.code || '').trim();
|
||||||
console.log("Barcode detected:", barcode);
|
console.log("Barcode detected:", barcode);
|
||||||
|
|
||||||
|
// Keep a local reference to the active callback before shutting down the engine
|
||||||
|
const currentCallback = activeScannerCallback;
|
||||||
|
|
||||||
// Critical: Stop scanning immediately to prevent multiple triggers
|
// Critical: Stop scanning immediately to prevent multiple triggers
|
||||||
stopScanner();
|
stopScanner();
|
||||||
|
|
||||||
// Update your results display if you have them
|
// Route data based on who opened the scanner
|
||||||
const resultText = document.getElementById('barcode-result');
|
if (typeof currentCallback === "function") {
|
||||||
if (resultText) resultText.innerText = barcode;
|
// Send data directly to the specific edit field's logic
|
||||||
|
currentCallback(barcode);
|
||||||
|
} else {
|
||||||
|
// Fallback Default: Main search box logic
|
||||||
|
const resultText = document.getElementById('barcode-result');
|
||||||
|
if (resultText) resultText.innerText = barcode;
|
||||||
|
|
||||||
// Put the scanned code in the search box
|
const searchInput = document.getElementById('code-search');
|
||||||
const searchInput = document.getElementById('code-search');
|
if (searchInput) {
|
||||||
if (searchInput) {
|
searchInput.value = barcode;
|
||||||
searchInput.value = barcode;
|
if (typeof searchByCode === "function") {
|
||||||
// Trigger your automatic search
|
searchByCode();
|
||||||
if (typeof searchByCode === "function") {
|
}
|
||||||
searchByCode();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 5. Wire up your Toggle Button click event
|
// Event Listener for the main standalone search button
|
||||||
document.getElementById('scanButton').addEventListener('click', function() {
|
document.getElementById('scanButton')?.addEventListener('click', function() {
|
||||||
if (!isScanning) {
|
if (!isScanning) {
|
||||||
startScanner();
|
// Pass null so it defaults to filling the standard search box
|
||||||
|
startScanner(null);
|
||||||
} else {
|
} else {
|
||||||
stopScanner();
|
stopScanner();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function scanIntoEditCode() {
|
function scanIntoEditCode() {
|
||||||
const qrReader = document.getElementById('qr-reader');
|
const qrReader = document.getElementById('qr-reader');
|
||||||
const editCodeInput = document.getElementById('edit-code4');
|
const editCodeInput = document.getElementById('edit-code4');
|
||||||
@@ -2871,37 +2889,21 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qrReader.style.display !== 'none') {
|
// Toggle close if it's already running
|
||||||
if (hybridScanner) {
|
if (isScanning && qrReader.style.display !== 'none') {
|
||||||
hybridScanner.stop();
|
stopScanner();
|
||||||
hybridScanner = null;
|
|
||||||
}
|
|
||||||
qrReader.style.display = 'none';
|
|
||||||
scanEditBtn.textContent = 'Barcode scannen';
|
scanEditBtn.textContent = 'Barcode scannen';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qrReader.style.display = 'block';
|
|
||||||
scanEditBtn.textContent = 'Scanner schließen';
|
scanEditBtn.textContent = 'Scanner schließen';
|
||||||
hybridScanner = new HybridScanner({
|
|
||||||
videoId: 'qr-reader-video',
|
// Start scanner with custom logic mapping to the Code input field
|
||||||
canvasId: 'qr-reader-canvas',
|
startScanner(function(decodedText) {
|
||||||
formats: ['CODE_128', 'CODE_39', 'QR_CODE'],
|
editCodeInput.value = decodedText;
|
||||||
fps: 10,
|
validateCodeField(editCodeInput, document.getElementById('edit-item-id')?.value || null);
|
||||||
facingMode: 'environment',
|
scanEditBtn.textContent = 'Barcode scannen';
|
||||||
onSuccess: function(decodedText) {
|
|
||||||
hybridScanner.stop();
|
|
||||||
qrReader.style.display = 'none';
|
|
||||||
editCodeInput.value = String(decodedText || '').trim();
|
|
||||||
validateCodeField(editCodeInput, document.getElementById('edit-item-id')?.value || null);
|
|
||||||
scanEditBtn.textContent = 'Barcode scannen';
|
|
||||||
},
|
|
||||||
onError: function(error) {
|
|
||||||
console.error('Scanner error:', error);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
hybridScanner.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function scanIntoEditIsbn() {
|
function scanIntoEditIsbn() {
|
||||||
@@ -2912,39 +2914,23 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qrReader.style.display !== 'none') {
|
// Toggle close if it's already running
|
||||||
if (hybridScanner) {
|
if (isScanning && qrReader.style.display !== 'none') {
|
||||||
hybridScanner.stop();
|
stopScanner();
|
||||||
hybridScanner = null;
|
|
||||||
}
|
|
||||||
qrReader.style.display = 'none';
|
|
||||||
scanIsbnBtn.textContent = 'ISBN scannen';
|
scanIsbnBtn.textContent = 'ISBN scannen';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qrReader.style.display = 'block';
|
|
||||||
scanIsbnBtn.textContent = 'Scanner schließen';
|
scanIsbnBtn.textContent = 'Scanner schließen';
|
||||||
hybridScanner = new HybridScanner({
|
|
||||||
videoId: 'qr-reader-video',
|
// Start scanner with custom logic mapping to the ISBN input field
|
||||||
canvasId: 'qr-reader-canvas',
|
startScanner(function(decodedText) {
|
||||||
formats: ['ISBN', 'EAN_13', 'EAN_8', 'QR_CODE'],
|
editIsbnInput.value = decodedText;
|
||||||
fps: 10,
|
scanIsbnBtn.textContent = 'ISBN scannen';
|
||||||
facingMode: 'environment',
|
if (typeof fetchBookInfo === 'function') {
|
||||||
onSuccess: function(decodedText) {
|
fetchBookInfo('edit');
|
||||||
hybridScanner.stop();
|
|
||||||
qrReader.style.display = 'none';
|
|
||||||
editIsbnInput.value = String(decodedText || '').trim();
|
|
||||||
scanIsbnBtn.textContent = 'ISBN scannen';
|
|
||||||
if (typeof fetchBookInfo === 'function') {
|
|
||||||
fetchBookInfo('edit');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onError: function(error) {
|
|
||||||
console.error('Scanner error:', error);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
hybridScanner.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function rebuildFilter3Options() {
|
function rebuildFilter3Options() {
|
||||||
|
|||||||
Reference in New Issue
Block a user