Fix: TomSelect Dropdown-Anzeige (Z-Index, Images) in Rucksack-Bearbeitung
All checks were successful
Docker Build & Push / build-and-push (push) Successful in 16s

This commit is contained in:
Gemini Agent
2025-12-07 07:46:17 +00:00
parent f9df3087a7
commit 967bae965a

View File

@@ -111,10 +111,8 @@ $manufacturers = $stmt_man_load->get_result()->fetch_all(MYSQLI_ASSOC);
$stmt_man_load->close();
// Load Articles for Linked Compartments
// Filter: Show all articles (or maybe only containers/bags? User said "any"). Let's load all.
$hh_ids = [$user_id];
if ($household_id) {
// Get all users in household
$stmt_hhm = $conn->prepare("SELECT id FROM users WHERE household_id = ?");
$stmt_hhm->bind_param("i", $household_id);
$stmt_hhm->execute();
@@ -124,7 +122,7 @@ if ($household_id) {
$placeholders = implode(',', array_fill(0, count($hh_ids), '?'));
$types_hh = str_repeat('i', count($hh_ids));
$stmt_arts = $conn->prepare("SELECT id, name, weight_grams, image_url FROM articles WHERE user_id IN ($placeholders) OR household_id = ? ORDER BY name ASC");
$params_arts = array_merge($hh_ids, [$household_id ?: 0]); // 0 if null
$params_arts = array_merge($hh_ids, [$household_id ?: 0]);
$types_arts = $types_hh . 'i';
$stmt_arts->bind_param($types_arts, ...$params_arts);
$stmt_arts->execute();
@@ -136,7 +134,6 @@ $stmt_arts->close();
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$name = trim($_POST['name']);
// Manufacturer Logic
$manufacturer = '';
if (isset($_POST['manufacturer_select'])) {
if ($_POST['manufacturer_select'] === 'new') {
@@ -173,7 +170,6 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$share_household = isset($_POST['share_household']) ? 1 : 0;
$product_url_input = trim($_POST['product_url'] ?? '');
// Image Handling
$image_url_for_db = $image_url;
$pasted_image = $_POST['pasted_image_data'] ?? '';
$url_image = trim($_POST['image_url_input'] ?? '');
@@ -198,12 +194,10 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$final_household_id = ($share_household && $household_id) ? $household_id : NULL;
if ($backpack_id > 0) {
// Update
$stmt = $conn->prepare("UPDATE backpacks SET name=?, manufacturer=?, model=?, weight_grams=?, volume_liters=?, household_id=?, image_url=?, product_url=? WHERE id=? AND user_id=?");
$stmt->bind_param("sssiisssii", $name, $manufacturer, $model, $weight, $volume, $final_household_id, $image_url_for_db, $product_url_input, $backpack_id, $user_id);
$stmt->execute();
} else {
// Insert
$stmt = $conn->prepare("INSERT INTO backpacks (user_id, household_id, name, manufacturer, model, weight_grams, volume_liters, image_url, product_url) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->bind_param("iisssiiss", $user_id, $final_household_id, $name, $manufacturer, $model, $weight, $volume, $image_url_for_db, $product_url_input);
$stmt->execute();
@@ -211,14 +205,12 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
}
// Handle Compartments
// Arrays: comp_ids, comp_types (text/article), comp_names, comp_articles
if (isset($_POST['comp_types'])) {
$types = $_POST['comp_types'];
$ids = $_POST['comp_ids'] ?? [];
$names = $_POST['comp_names'] ?? [];
$articles = $_POST['comp_articles'] ?? [];
// Get existing IDs
$existing_ids = [];
if($backpack_id > 0){
$stmt_check = $conn->prepare("SELECT id FROM backpack_compartments WHERE backpack_id = ?");
@@ -238,8 +230,7 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if ($c_type === 'article') {
$c_article_id = intval($articles[$i] ?? 0);
if ($c_article_id <= 0) continue; // Skip invalid
// Get name from article for display purposes (fallback)
if ($c_article_id <= 0) continue;
foreach($all_articles as $art) {
if ($art['id'] == $c_article_id) {
$c_name = $art['name'];
@@ -252,20 +243,17 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
}
if ($c_id > 0 && in_array($c_id, $existing_ids)) {
// Update
$stmt_up = $conn->prepare("UPDATE backpack_compartments SET name = ?, sort_order = ?, linked_article_id = ? WHERE id = ?");
$stmt_up->bind_param("siii", $c_name, $i, $c_article_id, $c_id);
$stmt_up->execute();
$kept_ids[] = $c_id;
} else {
// Insert
$stmt_in = $conn->prepare("INSERT INTO backpack_compartments (backpack_id, name, sort_order, linked_article_id) VALUES (?, ?, ?, ?)");
$stmt_in->bind_param("isii", $backpack_id, $c_name, $i, $c_article_id);
$stmt_in->execute();
}
}
// Delete removed
foreach ($existing_ids as $ex_id) {
if (!in_array($ex_id, $kept_ids)) {
$conn->query("DELETE FROM backpack_compartments WHERE id = $ex_id");
@@ -380,15 +368,17 @@ require_once 'header.php';
</select>
<!-- Text Input -->
<input type="text" name="comp_names[]" class="form-control name-input" value="Hauptfach" placeholder="Fachname">
<input type="text" name="comp_names[]" class="form-control name-input" placeholder="Fachname">
<!-- Article Select (Hidden initially) -->
<select name="comp_articles[]" class="form-select article-select" style="display:none;">
<option value="">Artikel wählen...</option>
<?php foreach($all_articles as $art): ?>
<option value="<?php echo $art['id']; ?>"><?php echo htmlspecialchars($art['name']); ?></option>
<?php endforeach; ?>
</select>
<!-- Article Select -->
<div class="flex-grow-1 article-select-wrapper" style="display:none;">
<select name="comp_articles[]" class="form-select article-select tom-select-init">
<option value="">Artikel wählen...</option>
<?php foreach($all_articles as $art): ?>
<option value="<?php echo $art['id']; ?>" data-src="<?php echo !empty($art['image_url']) ? htmlspecialchars($art['image_url']) : ''; ?>"><?php echo htmlspecialchars($art['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
<input type="hidden" name="comp_ids[]" value="0">
<button type="button" class="btn btn-outline-danger btn-remove-comp"><i class="fas fa-times"></i></button>
@@ -416,7 +406,7 @@ require_once 'header.php';
<?php foreach($all_articles as $art):
$sel = ($is_article && $art['id'] == $comp['linked_article_id']) ? 'selected' : '';
?>
<option value="<?php echo $art['id']; ?>" <?php echo $sel; ?>><?php echo htmlspecialchars($art['name']); ?></option>
<option value="<?php echo $art['id']; ?>" <?php echo $sel; ?> data-src="<?php echo !empty($art['image_url']) ? htmlspecialchars($art['image_url']) : ''; ?>"><?php echo htmlspecialchars($art['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
@@ -475,7 +465,6 @@ document.addEventListener('DOMContentLoaded', function() {
});
// Template for new row (with placeholders)
// Note: We use a class 'tom-select-init' to mark selects that need init
const rowTemplate = `
<div class="compartment-row card mb-2">
<div class="card-body p-2">
@@ -492,7 +481,7 @@ document.addEventListener('DOMContentLoaded', function() {
<select name="comp_articles[]" class="form-select article-select tom-select-init">
<option value="">Artikel wählen...</option>
<?php foreach($all_articles as $art): ?>
<option value="<?php echo $art['id']; ?>"><?php echo htmlspecialchars($art['name']); ?></option>
<option value="<?php echo $art['id']; ?>" data-src="<?php echo !empty($art['image_url']) ? htmlspecialchars($art['image_url']) : ''; ?>"><?php echo htmlspecialchars($art['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
@@ -506,26 +495,50 @@ document.addEventListener('DOMContentLoaded', function() {
document.getElementById('add-compartment').addEventListener('click', function() {
container.insertAdjacentHTML('beforeend', rowTemplate);
// Init new elements
const newRow = container.lastElementChild;
initRowLogic(newRow);
});
function initTomSelect(select) {
if (select.tomselect) return;
new TomSelect(select, {
create: false,
sortField: { field: "text", direction: "asc" },
dropdownParent: 'body',
render: {
option: function(data, escape) {
let src = data.src || '';
return `<div>
${src ? `<img src="${src}" style="width:24px;height:24px;object-fit:cover;margin-right:8px;vertical-align:middle;">` : ''}
<span>${escape(data.text)}</span>
</div>`;
},
item: function(data, escape) {
let src = data.src || '';
return `<div>
${src ? `<img src="${src}" style="width:20px;height:20px;object-fit:cover;margin-right:6px;vertical-align:middle;">` : ''}
<span>${escape(data.text)}</span>
</div>`;
}
}
});
}
function initRowLogic(row) {
const typeSelect = row.querySelector('.type-select');
const nameInput = row.querySelector('.name-input');
const artWrapper = row.querySelector('.article-select-wrapper');
const artSelect = row.querySelector('.article-select');
// Type Toggle Logic
typeSelect.addEventListener('change', function() {
if (this.value === 'article') {
nameInput.style.display = 'none';
artWrapper.style.display = 'block';
// Init TomSelect if not yet done
if (artSelect.classList.contains('tom-select-init') && !artSelect.tomselect) {
new TomSelect(artSelect, { create: false, sortField: { field: "text", direction: "asc" } });
initTomSelect(artSelect);
artSelect.classList.remove('tom-select-init');
} else if (artSelect && !artSelect.tomselect) {
initTomSelect(artSelect);
}
} else {
nameInput.style.display = 'block';
@@ -533,9 +546,9 @@ document.addEventListener('DOMContentLoaded', function() {
}
});
// Initialize TomSelect for existing items (if visible) or prepare them
if (artSelect && !artSelect.tomselect) {
new TomSelect(artSelect, { create: false, sortField: { field: "text", direction: "asc" } });
// Init if already visible (editing mode)
if (artSelect && !artSelect.tomselect && artWrapper.style.display !== 'none') {
initTomSelect(artSelect);
}
}
@@ -548,7 +561,7 @@ document.addEventListener('DOMContentLoaded', function() {
}
});
// Image Handling Logic (same as before)
// Image Handling Logic
const imageFileInput = document.getElementById('image_file');
const imagePreview = document.getElementById('imagePreview');
const pasteArea = document.getElementById('pasteArea');
@@ -588,4 +601,4 @@ document.addEventListener('DOMContentLoaded', function() {
});
</script>
<?php require_once 'footer.php'; ?>
<?php require_once 'footer.php'; ?>