Replaced the Browser side pop ups with custom ones from the site itsself
Release Inventarsystem / release-docker (push) Successful in 2m17s
Release Inventarsystem / release-docker (push) Successful in 2m17s
This commit is contained in:
@@ -613,6 +613,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<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>
|
||||||
|
{% endblock %}
|
||||||
<script>
|
<script>
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// 1. GLOBAL STATE DEFINITIONS
|
// 1. GLOBAL STATE DEFINITIONS
|
||||||
@@ -884,7 +885,7 @@
|
|||||||
name: "Live",
|
name: "Live",
|
||||||
type: "LiveStream",
|
type: "LiveStream",
|
||||||
// This MUST match the inner div where the video should appear
|
// This MUST match the inner div where the video should appear
|
||||||
target: document.querySelector('.library-scan-reader'),
|
target: document.querySelector('.library-scan-reader'),
|
||||||
constraints: {
|
constraints: {
|
||||||
width: 640,
|
width: 640,
|
||||||
height: 480,
|
height: 480,
|
||||||
@@ -897,7 +898,7 @@
|
|||||||
},
|
},
|
||||||
decoder: {
|
decoder: {
|
||||||
// Keep only the barcode types you actually use to improve performance
|
// Keep only the barcode types you actually use to improve performance
|
||||||
readers: ["code_128_reader", "ean_reader", "code_39_reader"]
|
readers: ["code_128_reader", "ean_reader", "code_39_reader"]
|
||||||
},
|
},
|
||||||
locate: true
|
locate: true
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
@@ -1241,33 +1242,186 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// 4. UI INTERACTIONS & UTILITIES
|
// CUSTOM MODAL HELPERS (Replaces native alert/prompt)
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
function borrowItem(itemId) {
|
function createModalOverlay() {
|
||||||
|
const overlay = document.createElement('div');
|
||||||
|
overlay.style.position = 'fixed';
|
||||||
|
overlay.style.top = '0';
|
||||||
|
overlay.style.left = '0';
|
||||||
|
overlay.style.width = '100vw';
|
||||||
|
overlay.style.height = '100vh';
|
||||||
|
overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.6)';
|
||||||
|
overlay.style.display = 'flex';
|
||||||
|
overlay.style.alignItems = 'center';
|
||||||
|
overlay.style.justifyContent = 'center';
|
||||||
|
overlay.style.zIndex = '999999';
|
||||||
|
return overlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createModalBox() {
|
||||||
|
const box = document.createElement('div');
|
||||||
|
box.style.backgroundColor = '#fff';
|
||||||
|
box.style.padding = '24px';
|
||||||
|
box.style.borderRadius = '8px';
|
||||||
|
box.style.boxShadow = '0 10px 25px rgba(0,0,0,0.2)';
|
||||||
|
box.style.fontFamily = 'sans-serif';
|
||||||
|
box.style.minWidth = '320px';
|
||||||
|
box.style.maxWidth = '90%';
|
||||||
|
box.style.textAlign = 'left';
|
||||||
|
box.style.color = '#333';
|
||||||
|
return box;
|
||||||
|
}
|
||||||
|
|
||||||
|
function customAlert(message) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const overlay = createModalOverlay();
|
||||||
|
const box = createModalBox();
|
||||||
|
|
||||||
|
const text = document.createElement('p');
|
||||||
|
text.textContent = message;
|
||||||
|
text.style.marginBottom = '20px';
|
||||||
|
text.style.lineHeight = '1.5';
|
||||||
|
text.style.whiteSpace = 'pre-wrap';
|
||||||
|
|
||||||
|
const btnContainer = document.createElement('div');
|
||||||
|
btnContainer.style.display = 'flex';
|
||||||
|
btnContainer.style.justifyContent = 'flex-end';
|
||||||
|
|
||||||
|
const btn = document.createElement('button');
|
||||||
|
btn.textContent = 'OK';
|
||||||
|
btn.style.padding = '8px 16px';
|
||||||
|
btn.style.cursor = 'pointer';
|
||||||
|
btn.style.border = 'none';
|
||||||
|
btn.style.backgroundColor = '#007bff';
|
||||||
|
btn.style.color = '#fff';
|
||||||
|
btn.style.borderRadius = '4px';
|
||||||
|
|
||||||
|
btn.onclick = () => {
|
||||||
|
document.body.removeChild(overlay);
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
|
||||||
|
btnContainer.appendChild(btn);
|
||||||
|
box.appendChild(text);
|
||||||
|
box.appendChild(btnContainer);
|
||||||
|
overlay.appendChild(box);
|
||||||
|
document.body.appendChild(overlay);
|
||||||
|
btn.focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function customPrompt(message, defaultValue = '') {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const overlay = createModalOverlay();
|
||||||
|
const box = createModalBox();
|
||||||
|
|
||||||
|
const text = document.createElement('p');
|
||||||
|
text.textContent = message;
|
||||||
|
text.style.marginBottom = '15px';
|
||||||
|
text.style.lineHeight = '1.5';
|
||||||
|
text.style.whiteSpace = 'pre-wrap';
|
||||||
|
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.type = 'text';
|
||||||
|
input.value = defaultValue;
|
||||||
|
input.style.width = '100%';
|
||||||
|
input.style.marginBottom = '20px';
|
||||||
|
input.style.padding = '10px';
|
||||||
|
input.style.boxSizing = 'border-box';
|
||||||
|
input.style.border = '1px solid #ccc';
|
||||||
|
input.style.borderRadius = '4px';
|
||||||
|
|
||||||
|
const btnContainer = document.createElement('div');
|
||||||
|
btnContainer.style.display = 'flex';
|
||||||
|
btnContainer.style.justifyContent = 'flex-end';
|
||||||
|
btnContainer.style.gap = '10px';
|
||||||
|
|
||||||
|
const cancelBtn = document.createElement('button');
|
||||||
|
cancelBtn.textContent = 'Abbrechen';
|
||||||
|
cancelBtn.style.padding = '8px 16px';
|
||||||
|
cancelBtn.style.cursor = 'pointer';
|
||||||
|
cancelBtn.style.border = '1px solid #ccc';
|
||||||
|
cancelBtn.style.backgroundColor = '#f8f9fa';
|
||||||
|
cancelBtn.style.color = '#333';
|
||||||
|
cancelBtn.style.borderRadius = '4px';
|
||||||
|
|
||||||
|
const okBtn = document.createElement('button');
|
||||||
|
okBtn.textContent = 'OK';
|
||||||
|
okBtn.style.padding = '8px 16px';
|
||||||
|
okBtn.style.cursor = 'pointer';
|
||||||
|
okBtn.style.border = 'none';
|
||||||
|
okBtn.style.backgroundColor = '#007bff';
|
||||||
|
okBtn.style.color = '#fff';
|
||||||
|
okBtn.style.borderRadius = '4px';
|
||||||
|
|
||||||
|
const closeAndResolve = (val) => {
|
||||||
|
document.body.removeChild(overlay);
|
||||||
|
resolve(val);
|
||||||
|
};
|
||||||
|
|
||||||
|
cancelBtn.onclick = () => closeAndResolve(null);
|
||||||
|
okBtn.onclick = () => closeAndResolve(input.value);
|
||||||
|
|
||||||
|
input.onkeydown = (e) => {
|
||||||
|
if (e.key === 'Enter') closeAndResolve(input.value);
|
||||||
|
if (e.key === 'Escape') closeAndResolve(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
btnContainer.appendChild(cancelBtn);
|
||||||
|
btnContainer.appendChild(okBtn);
|
||||||
|
|
||||||
|
box.appendChild(text);
|
||||||
|
box.appendChild(input);
|
||||||
|
box.appendChild(btnContainer);
|
||||||
|
overlay.appendChild(box);
|
||||||
|
document.body.appendChild(overlay);
|
||||||
|
|
||||||
|
input.focus();
|
||||||
|
input.select();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// ORIGINAL SCRIPT (Updated to use custom modals)
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
async function borrowItem(itemId) {
|
||||||
const selectedItem = (libraryItems || []).find(item => item._id === itemId);
|
const selectedItem = (libraryItems || []).find(item => item._id === itemId);
|
||||||
if (selectedItem && selectedItem.LibraryDisplayStatus === 'damaged') {
|
if (selectedItem && selectedItem.LibraryDisplayStatus === 'damaged') {
|
||||||
alert('Dieses Medium ist als defekt/zerstört markiert und kann nicht ausgeliehen werden.');
|
await customAlert('Dieses Medium ist als defekt/zerstört markiert und kann nicht ausgeliehen werden.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultCardId = activeStudentCardId || '';
|
const defaultCardId = activeStudentCardId || '';
|
||||||
const cardId = (window.prompt('Bitte Bibliotheksausweis-ID eingeben:', defaultCardId) || '').trim().toUpperCase();
|
const promptCardResult = await customPrompt('Bitte Bibliotheksausweis-ID eingeben:', defaultCardId);
|
||||||
|
|
||||||
|
// Return early if the user clicked "Cancel" (prompt returns null)
|
||||||
|
if (promptCardResult === null) return;
|
||||||
|
|
||||||
|
const cardId = promptCardResult.trim().toUpperCase();
|
||||||
if (!cardId) {
|
if (!cardId) {
|
||||||
alert('Ausleihe abgebrochen: Für Bibliotheksmedien ist eine gültige Bibliotheksausweis-ID erforderlich.');
|
await customAlert('Ausleihe abgebrochen: Für Bibliotheksmedien ist eine gültige Bibliotheksausweis-ID erforderlich.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setActiveStudentCard(cardId);
|
setActiveStudentCard(cardId);
|
||||||
|
|
||||||
const durationInput = (window.prompt('Ausleihdauer in Tagen (optional):') || '').trim();
|
const promptDurationResult = await customPrompt('Ausleihdauer in Tagen (optional):');
|
||||||
|
if (promptDurationResult === null) return;
|
||||||
|
const durationInput = promptDurationResult.trim();
|
||||||
|
|
||||||
const maxAvailable = Math.max(1, parseInt(selectedItem?.AvailableGroupedCount || selectedItem?.Quantity || 1, 10) || 1);
|
const maxAvailable = Math.max(1, parseInt(selectedItem?.AvailableGroupedCount || selectedItem?.Quantity || 1, 10) || 1);
|
||||||
const countPrompt = (window.prompt(`Anzahl ausleihen? (Standard: 1, verfügbar: ${maxAvailable})`, '1') || '').trim();
|
|
||||||
let borrowCount = parseInt(countPrompt || '1', 10);
|
const countPromptResult = await customPrompt(`Anzahl ausleihen? (Standard: 1, verfügbar: ${maxAvailable})`, '1');
|
||||||
|
if (countPromptResult === null) return;
|
||||||
|
|
||||||
|
let borrowCount = parseInt(countPromptResult.trim() || '1', 10);
|
||||||
if (!Number.isFinite(borrowCount) || borrowCount < 1) {
|
if (!Number.isFinite(borrowCount) || borrowCount < 1) {
|
||||||
borrowCount = 1;
|
borrowCount = 1;
|
||||||
}
|
}
|
||||||
if (borrowCount > maxAvailable) {
|
if (borrowCount > maxAvailable) {
|
||||||
alert(`Es sind nur ${maxAvailable} Exemplar(e) verfügbar.`);
|
await customAlert(`Es sind nur ${maxAvailable} Exemplar(e) verfügbar.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1278,7 +1432,7 @@
|
|||||||
const csrfField = document.createElement('input');
|
const csrfField = document.createElement('input');
|
||||||
csrfField.type = 'hidden';
|
csrfField.type = 'hidden';
|
||||||
csrfField.name = 'csrf_token';
|
csrfField.name = 'csrf_token';
|
||||||
csrfField.value = '{{ csrf_token }}';
|
csrfField.value = '{{ csrf_token }}'; // Note: Template syntax remains intact
|
||||||
form.appendChild(csrfField);
|
form.appendChild(csrfField);
|
||||||
|
|
||||||
const cardField = document.createElement('input');
|
const cardField = document.createElement('input');
|
||||||
@@ -1348,13 +1502,13 @@
|
|||||||
const labels = { 'book': 'Buch', 'cd': 'CD', 'dvd': 'DVD', 'other': 'Sonstige', 'schoolbook': 'Schulbuch' };
|
const labels = { 'book': 'Buch', 'cd': 'CD', 'dvd': 'DVD', 'other': 'Sonstige', 'schoolbook': 'Schulbuch' };
|
||||||
return labels[type] || type;
|
return labels[type] || type;
|
||||||
}
|
}
|
||||||
|
|
||||||
function escapeHtml(text) {
|
function escapeHtml(text) {
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.textContent = text;
|
div.textContent = text;
|
||||||
return div.innerHTML;
|
return div.innerHTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function showItemDetail(itemId) {
|
function showItemDetail(itemId) {
|
||||||
const detailContent = document.getElementById('detailContent');
|
const detailContent = document.getElementById('detailContent');
|
||||||
const detailModal = document.getElementById('detailModal');
|
const detailModal = document.getElementById('detailModal');
|
||||||
@@ -1388,9 +1542,9 @@
|
|||||||
: `/uploads/${image}`;
|
: `/uploads/${image}`;
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="item-image-wrapper" style="width: 100%; height: auto;">
|
<div class="item-image-wrapper" style="width: 100%; height: auto;">
|
||||||
<video src="${videoSrc}" class="item-image ${index === 0 ? 'active-image' : ''}" id="modal-image-${index}" controls preload="metadata" style="width: 100%; height: auto; max-height: 300px;"></video>
|
<video src="${videoSrc}" class="item-image ${index === 0 ? 'active-image' : ''}" id="modal-image-${index}" controls preload="metadata" style="width: 100%; height: auto; max-height: 300px;"></video>
|
||||||
</div>`;
|
</div>`;
|
||||||
} else {
|
} else {
|
||||||
const imageSrc = thumbnailInfo && thumbnailInfo.has_preview
|
const imageSrc = thumbnailInfo && thumbnailInfo.has_preview
|
||||||
? thumbnailInfo.preview_url
|
? thumbnailInfo.preview_url
|
||||||
@@ -1399,15 +1553,15 @@
|
|||||||
: `/uploads/${image}`);
|
: `/uploads/${image}`);
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="item-image-wrapper">
|
<div class="item-image-wrapper">
|
||||||
<img src="${imageSrc}"
|
<img src="${imageSrc}"
|
||||||
alt="Buchcover / Bild"
|
alt="Buchcover / Bild"
|
||||||
class="item-image ${index === 0 ? 'active-image' : ''}"
|
class="item-image ${index === 0 ? 'active-image' : ''}"
|
||||||
id="modal-image-${index}"
|
id="modal-image-${index}"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
onload="console.log('Bild geladen:', '${imageSrc}')"
|
onload="console.log('Bild geladen:', '${imageSrc}')"
|
||||||
onerror="console.error('FEHLER beim Laden des Bildes im DOM:', '${imageSrc}')">
|
onerror="console.error('FEHLER beim Laden des Bildes im DOM:', '${imageSrc}')">
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
}).join('');
|
}).join('');
|
||||||
|
|
||||||
@@ -1592,4 +1746,3 @@
|
|||||||
window.location.href = `/item_edit/${itemId}`;
|
window.location.href = `/item_edit/${itemId}`;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
|
||||||
Reference in New Issue
Block a user