Feature: Modulare Rucksäcke (Zusatztaschen)
All checks were successful
Docker Build & Push / build-and-push (push) Successful in 26s
All checks were successful
Docker Build & Push / build-and-push (push) Successful in 26s
- DB-Erweiterung für linked_article_id in backpack_compartments. - UI in edit_backpack.php zum Verknüpfen von Artikeln als Fächer. - Sync-Logik in backpack_utils.php übernimmt Artikel-Daten. - Gewichts-Kalkulation in backpacks.php berücksichtigt Zusatztaschen. - Changelog aktualisiert.
This commit is contained in:
@@ -48,7 +48,11 @@ $backpacks = [];
|
||||
$check_col = $conn->query("SHOW COLUMNS FROM backpacks LIKE 'product_url'");
|
||||
$has_product_url = ($check_col && $check_col->num_rows > 0);
|
||||
|
||||
$sql = "SELECT b.*, u.username as owner_name
|
||||
$sql = "SELECT b.*, u.username as owner_name,
|
||||
(SELECT SUM(a.weight_grams)
|
||||
FROM backpack_compartments bc
|
||||
JOIN articles a ON bc.linked_article_id = a.id
|
||||
WHERE bc.backpack_id = b.id) as extra_weight
|
||||
FROM backpacks b
|
||||
JOIN users u ON b.user_id = u.id
|
||||
WHERE b.user_id = ?";
|
||||
@@ -85,7 +89,9 @@ while ($row = $result->fetch_assoc()) {
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="row g-4">
|
||||
<?php foreach ($backpacks as $bp): ?>
|
||||
<?php foreach ($backpacks as $bp):
|
||||
$total_bp_weight = $bp['weight_grams'] + ($bp['extra_weight'] ?? 0);
|
||||
?>
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<div class="card-body">
|
||||
@@ -109,7 +115,13 @@ while ($row = $result->fetch_assoc()) {
|
||||
</p>
|
||||
|
||||
<div class="d-flex justify-content-between mb-3">
|
||||
<span><i class="fas fa-weight-hanging text-muted me-1"></i> <?php echo $bp['weight_grams']; ?> g</span>
|
||||
<span>
|
||||
<i class="fas fa-weight-hanging text-muted me-1"></i>
|
||||
<?php echo $total_bp_weight; ?> g
|
||||
<?php if(($bp['extra_weight'] ?? 0) > 0): ?>
|
||||
<small class="text-muted" title="Basis: <?php echo $bp['weight_grams']; ?>g + Taschen: <?php echo $bp['extra_weight']; ?>g">(+<?php echo $bp['extra_weight']; ?>)</small>
|
||||
<?php endif; ?>
|
||||
</span>
|
||||
<span><i class="fas fa-box-open text-muted me-1"></i> <?php echo $bp['volume_liters']; ?> L</span>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -25,11 +25,16 @@ $message = '';
|
||||
$image_url = '';
|
||||
$product_url = '';
|
||||
|
||||
// AUTO-MIGRATION: Check if product_url column exists, if not add it
|
||||
// AUTO-MIGRATION: Check columns
|
||||
$check_col = $conn->query("SHOW COLUMNS FROM backpacks LIKE 'product_url'");
|
||||
if ($check_col && $check_col->num_rows == 0) {
|
||||
$conn->query("ALTER TABLE backpacks ADD COLUMN product_url VARCHAR(255) DEFAULT NULL AFTER image_url");
|
||||
}
|
||||
$check_col_c = $conn->query("SHOW COLUMNS FROM backpack_compartments LIKE 'linked_article_id'");
|
||||
if ($check_col_c && $check_col_c->num_rows == 0) {
|
||||
$conn->query("ALTER TABLE backpack_compartments ADD COLUMN linked_article_id INT DEFAULT NULL");
|
||||
$conn->query("ALTER TABLE backpack_compartments ADD CONSTRAINT fk_bc_article FOREIGN KEY (linked_article_id) REFERENCES articles(id) ON DELETE SET NULL");
|
||||
}
|
||||
|
||||
// Check Household
|
||||
$household_id = null;
|
||||
@@ -105,7 +110,29 @@ $stmt_man_load->execute();
|
||||
$manufacturers = $stmt_man_load->get_result()->fetch_all(MYSQLI_ASSOC);
|
||||
$stmt_man_load->close();
|
||||
|
||||
// Handle Form Submission BEFORE loading header
|
||||
// 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();
|
||||
$res_hhm = $stmt_hhm->get_result();
|
||||
while($r = $res_hhm->fetch_assoc()) $hh_ids[] = $r['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
|
||||
$types_arts = $types_hh . 'i';
|
||||
$stmt_arts->bind_param($types_arts, ...$params_arts);
|
||||
$stmt_arts->execute();
|
||||
$all_articles = $stmt_arts->get_result()->fetch_all(MYSQLI_ASSOC);
|
||||
$stmt_arts->close();
|
||||
|
||||
|
||||
// Handle Form Submission
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$name = trim($_POST['name']);
|
||||
|
||||
@@ -115,7 +142,6 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
if ($_POST['manufacturer_select'] === 'new') {
|
||||
$new_man = trim($_POST['new_manufacturer_name']);
|
||||
if (!empty($new_man)) {
|
||||
// Check if exists first
|
||||
$stmt_check_man = $conn->prepare("SELECT id, name FROM manufacturers WHERE user_id = ? AND name = ?");
|
||||
$stmt_check_man->bind_param("is", $user_id, $new_man);
|
||||
$stmt_check_man->execute();
|
||||
@@ -124,7 +150,6 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
if ($res_check->num_rows > 0) {
|
||||
$manufacturer = $res_check->fetch_assoc()['name'];
|
||||
} else {
|
||||
// Save to manufacturers table
|
||||
$stmt_new_man = $conn->prepare("INSERT INTO manufacturers (name, user_id) VALUES (?, ?)");
|
||||
$stmt_new_man->bind_param("si", $new_man, $user_id);
|
||||
$stmt_new_man->execute();
|
||||
@@ -132,7 +157,6 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Look up name from ID
|
||||
$man_id = intval($_POST['manufacturer_select']);
|
||||
foreach ($manufacturers as $m) {
|
||||
if ($m['id'] == $man_id) {
|
||||
@@ -150,52 +174,25 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$product_url_input = trim($_POST['product_url'] ?? '');
|
||||
|
||||
// Image Handling
|
||||
$image_url_for_db = $image_url; // Keep existing by default
|
||||
$image_url_for_db = $image_url;
|
||||
$pasted_image = $_POST['pasted_image_data'] ?? '';
|
||||
$url_image = trim($_POST['image_url_input'] ?? '');
|
||||
|
||||
if (!empty($pasted_image)) {
|
||||
list($ok, $res) = save_image_from_base64($pasted_image, $upload_dir);
|
||||
if ($ok) {
|
||||
$image_url_for_db = $res;
|
||||
} else {
|
||||
$message .= '<div class="alert alert-warning">Fehler beim Speichern des eingefügten Bildes: ' . htmlspecialchars($res) . '</div>';
|
||||
}
|
||||
} elseif (isset($_FILES['image_file']) && $_FILES['image_file']['error'] != UPLOAD_ERR_NO_FILE) {
|
||||
// User attempted to upload a file
|
||||
if ($_FILES['image_file']['error'] == UPLOAD_ERR_OK) {
|
||||
$ext = strtolower(pathinfo($_FILES['image_file']['name'], PATHINFO_EXTENSION));
|
||||
$allowed_exts = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
||||
if (in_array($ext, $allowed_exts)) {
|
||||
$name_file = uniqid('bp_img_', true) . '.' . $ext;
|
||||
if (move_uploaded_file($_FILES['image_file']['tmp_name'], $upload_dir . $name_file)) {
|
||||
$image_url_for_db = $upload_dir . $name_file;
|
||||
} else {
|
||||
$message .= '<div class="alert alert-danger">Fehler beim Verschieben der Datei. Schreibrechte prüfen.</div>';
|
||||
}
|
||||
} else {
|
||||
$message .= '<div class="alert alert-warning">Ungültiges Dateiformat. Erlaubt: JPG, PNG, GIF, WEBP.</div>';
|
||||
if ($ok) $image_url_for_db = $res;
|
||||
} elseif (isset($_FILES['image_file']) && $_FILES['image_file']['error'] == UPLOAD_ERR_OK) {
|
||||
$ext = strtolower(pathinfo($_FILES['image_file']['name'], PATHINFO_EXTENSION));
|
||||
$allowed_exts = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
||||
if (in_array($ext, $allowed_exts)) {
|
||||
$name_file = uniqid('bp_img_', true) . '.' . $ext;
|
||||
if (move_uploaded_file($_FILES['image_file']['tmp_name'], $upload_dir . $name_file)) {
|
||||
$image_url_for_db = $upload_dir . $name_file;
|
||||
}
|
||||
} else {
|
||||
// Handle upload errors
|
||||
$err_code = $_FILES['image_file']['error'];
|
||||
$err_msg = 'Unbekannter Fehler';
|
||||
switch ($err_code) {
|
||||
case UPLOAD_ERR_INI_SIZE: $err_msg = 'Datei ist zu groß (php.ini limit).'; break;
|
||||
case UPLOAD_ERR_FORM_SIZE: $err_msg = 'Datei ist zu groß (HTML form limit).'; break;
|
||||
case UPLOAD_ERR_PARTIAL: $err_msg = 'Datei wurde nur teilweise hochgeladen.'; break;
|
||||
case UPLOAD_ERR_NO_TMP_DIR: $err_msg = 'Kein temporärer Ordner gefunden.'; break;
|
||||
case UPLOAD_ERR_CANT_WRITE: $err_msg = 'Fehler beim Schreiben auf die Festplatte.'; break;
|
||||
}
|
||||
$message .= '<div class="alert alert-danger">Upload-Fehler: ' . $err_msg . '</div>';
|
||||
}
|
||||
} elseif (!empty($url_image)) {
|
||||
list($ok, $res) = save_image_from_url($url_image, $upload_dir);
|
||||
if ($ok) {
|
||||
$image_url_for_db = $res;
|
||||
} else {
|
||||
$message .= '<div class="alert alert-warning">Fehler beim Laden von URL: ' . htmlspecialchars($res) . '</div>';
|
||||
}
|
||||
if ($ok) $image_url_for_db = $res;
|
||||
}
|
||||
|
||||
$final_household_id = ($share_household && $household_id) ? $household_id : NULL;
|
||||
@@ -214,11 +211,14 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
}
|
||||
|
||||
// Handle Compartments
|
||||
if (isset($_POST['compartment_names'])) {
|
||||
$comp_names = $_POST['compartment_names'];
|
||||
$comp_ids = $_POST['compartment_ids'] ?? [];
|
||||
// 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 to know what to delete
|
||||
// Get existing IDs
|
||||
$existing_ids = [];
|
||||
if($backpack_id > 0){
|
||||
$stmt_check = $conn->prepare("SELECT id FROM backpack_compartments WHERE backpack_id = ?");
|
||||
@@ -230,22 +230,37 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
|
||||
$kept_ids = [];
|
||||
|
||||
for ($i = 0; $i < count($comp_names); $i++) {
|
||||
$c_name = trim($comp_names[$i]);
|
||||
$c_id = intval($comp_ids[$i] ?? 0);
|
||||
|
||||
if (empty($c_name)) continue;
|
||||
for ($i = 0; $i < count($types); $i++) {
|
||||
$c_id = intval($ids[$i] ?? 0);
|
||||
$c_type = $types[$i];
|
||||
$c_name = '';
|
||||
$c_article_id = NULL;
|
||||
|
||||
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)
|
||||
foreach($all_articles as $art) {
|
||||
if ($art['id'] == $c_article_id) {
|
||||
$c_name = $art['name'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$c_name = trim($names[$i] ?? '');
|
||||
if (empty($c_name)) continue;
|
||||
}
|
||||
|
||||
if ($c_id > 0 && in_array($c_id, $existing_ids)) {
|
||||
// Update
|
||||
$stmt_up = $conn->prepare("UPDATE backpack_compartments SET name = ?, sort_order = ? WHERE id = ?");
|
||||
$stmt_up->bind_param("sii", $c_name, $i, $c_id);
|
||||
$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) VALUES (?, ?, ?)");
|
||||
$stmt_in->bind_param("isi", $backpack_id, $c_name, $i);
|
||||
$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();
|
||||
}
|
||||
}
|
||||
@@ -311,8 +326,9 @@ require_once 'header.php';
|
||||
<input type="text" name="model" class="form-control" value="<?php echo htmlspecialchars($backpack['model'] ?? ''); ?>">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Leergewicht (g)</label>
|
||||
<input type="number" name="weight_grams" class="form-control" value="<?php echo htmlspecialchars($backpack['weight_grams'] ?? 0); ?>">
|
||||
<label class="form-label">Basis-Leergewicht (g)</label>
|
||||
<input type="number" name="weight_grams" class="form-control" value="<?php echo htmlspecialchars($backpack['weight_grams'] ?? 0); ?>" required>
|
||||
<div class="form-text small">Ohne Zusatztaschen.</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Volumen (Liter)</label>
|
||||
@@ -346,43 +362,75 @@ require_once 'header.php';
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5 class="border-bottom pb-2 mb-3">Fächeraufteilung</h5>
|
||||
<h5 class="border-bottom pb-2 mb-3">Fächer & Zusatztaschen</h5>
|
||||
<div class="alert alert-light small">
|
||||
Definiere hier die Bereiche deines Rucksacks (z.B. Deckelfach, Bodenfach). Diese erscheinen später in der Packliste als Container.
|
||||
Definiere hier die Bereiche deines Rucksacks. Du kannst einfache Text-Fächer (z.B. "Deckelfach") oder echte Artikel als Zusatztaschen (z.B. "Hüftgurttasche") hinzufügen. Das Gewicht von Zusatztaschen wird zum Rucksackgewicht addiert.
|
||||
</div>
|
||||
|
||||
<div id="compartments-container">
|
||||
<?php if (empty($compartments)): ?>
|
||||
<!-- Default Compartments for new backpack -->
|
||||
<div class="input-group mb-2 compartment-row">
|
||||
<span class="input-group-text"><i class="fas fa-grip-lines text-muted"></i></span>
|
||||
<input type="text" name="compartment_names[]" class="form-control" value="Hauptfach" placeholder="Fachname">
|
||||
<input type="hidden" name="compartment_ids[]" value="0">
|
||||
<button type="button" class="btn btn-outline-danger btn-remove-comp"><i class="fas fa-times"></i></button>
|
||||
</div>
|
||||
<div class="input-group mb-2 compartment-row">
|
||||
<span class="input-group-text"><i class="fas fa-grip-lines text-muted"></i></span>
|
||||
<input type="text" name="compartment_names[]" class="form-control" value="Deckelfach" placeholder="Fachname">
|
||||
<input type="hidden" name="compartment_ids[]" value="0">
|
||||
<button type="button" class="btn btn-outline-danger btn-remove-comp"><i class="fas fa-times"></i></button>
|
||||
<!-- Defaults -->
|
||||
<div class="compartment-row card mb-2">
|
||||
<div class="card-body p-2">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text handle cursor-grab"><i class="fas fa-grip-lines text-muted"></i></span>
|
||||
<select class="form-select type-select" name="comp_types[]" style="max-width: 130px;">
|
||||
<option value="text">Standardfach</option>
|
||||
<option value="article">Zusatztasche</option>
|
||||
</select>
|
||||
|
||||
<!-- Text Input -->
|
||||
<input type="text" name="comp_names[]" class="form-control name-input" value="Hauptfach" 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>
|
||||
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php foreach ($compartments as $comp):
|
||||
// Ensure proper escaping for HTML attributes
|
||||
$comp_name_escaped = htmlspecialchars($comp['name']);
|
||||
$comp_id_escaped = htmlspecialchars($comp['id']);
|
||||
$is_article = !empty($comp['linked_article_id']);
|
||||
?>
|
||||
<div class="input-group mb-2 compartment-row">
|
||||
<span class="input-group-text"><i class="fas fa-grip-lines text-muted"></i></span>
|
||||
<input type="text" name="compartment_names[]" class="form-control" value="<?php echo $comp_name_escaped; ?>">
|
||||
<input type="hidden" name="compartment_ids[]" value="<?php echo $comp_id_escaped; ?>">
|
||||
<button type="button" class="btn btn-outline-danger btn-remove-comp"><i class="fas fa-times"></i></button>
|
||||
<div class="compartment-row card mb-2">
|
||||
<div class="card-body p-2">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text handle cursor-grab"><i class="fas fa-grip-lines text-muted"></i></span>
|
||||
<select class="form-select type-select" name="comp_types[]" style="max-width: 130px;">
|
||||
<option value="text" <?php echo !$is_article ? 'selected' : ''; ?>>Standardfach</option>
|
||||
<option value="article" <?php echo $is_article ? 'selected' : ''; ?>>Zusatztasche</option>
|
||||
</select>
|
||||
|
||||
<input type="text" name="comp_names[]" class="form-control name-input" value="<?php echo htmlspecialchars($comp['name']); ?>" style="<?php echo $is_article ? 'display:none;' : ''; ?>">
|
||||
|
||||
<div class="flex-grow-1 article-select-wrapper" style="<?php echo !$is_article ? 'display:none;' : ''; ?>">
|
||||
<select name="comp_articles[]" class="form-select article-select">
|
||||
<option value="">Artikel wählen...</option>
|
||||
<?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>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="comp_ids[]" value="<?php echo $comp['id']; ?>">
|
||||
<button type="button" class="btn btn-outline-danger btn-remove-comp"><i class="fas fa-times"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-sm btn-outline-primary mb-4" id="add-compartment"><i class="fas fa-plus"></i> Fach hinzufügen</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-success mb-4" id="add-compartment"><i class="fas fa-plus"></i> Fach / Tasche hinzufügen</button>
|
||||
|
||||
<div class="d-flex justify-content-between border-top pt-3">
|
||||
<a href="backpacks.php" class="btn btn-secondary">Abbrechen</a>
|
||||
@@ -414,53 +462,93 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
}
|
||||
|
||||
if (manSelect) {
|
||||
// Initial check
|
||||
toggleManContainer(manSelect.value);
|
||||
|
||||
// Vanilla Listener (Backup)
|
||||
manSelect.addEventListener('change', function() {
|
||||
toggleManContainer(this.value);
|
||||
});
|
||||
}
|
||||
|
||||
// Tom Select Init
|
||||
if(manSelect) {
|
||||
new TomSelect(manSelect, {
|
||||
create: false,
|
||||
sortField: { field: "text", direction: "asc" },
|
||||
onChange: function(value) {
|
||||
toggleManContainer(value);
|
||||
}
|
||||
});
|
||||
manSelect.addEventListener('change', function() { toggleManContainer(this.value); });
|
||||
new TomSelect(manSelect, { create: false, sortField: { field: "text", direction: "asc" }, onChange: function(value) { toggleManContainer(value); } });
|
||||
}
|
||||
|
||||
const container = document.getElementById('compartments-container');
|
||||
|
||||
// Sortable for Compartments
|
||||
new Sortable(container, {
|
||||
handle: '.input-group-text',
|
||||
handle: '.handle',
|
||||
animation: 150
|
||||
});
|
||||
|
||||
// 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">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text handle cursor-grab"><i class="fas fa-grip-lines text-muted"></i></span>
|
||||
<select class="form-select type-select" name="comp_types[]" style="max-width: 130px;">
|
||||
<option value="text">Standardfach</option>
|
||||
<option value="article">Zusatztasche</option>
|
||||
</select>
|
||||
|
||||
<input type="text" name="comp_names[]" class="form-control name-input" placeholder="Fachname">
|
||||
|
||||
<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']; ?>"><?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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.getElementById('add-compartment').addEventListener('click', function() {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'input-group mb-2 compartment-row';
|
||||
div.innerHTML =
|
||||
`<span class="input-group-text"><i class="fas fa-grip-lines text-muted"></i></span>
|
||||
<input type="text" name="compartment_names[]" class="form-control" placeholder="Fachname">
|
||||
<input type="hidden" name="compartment_ids[]" value="0">
|
||||
<button type="button" class="btn btn-outline-danger btn-remove-comp"><i class="fas fa-times"></i></button>
|
||||
`;
|
||||
container.appendChild(div);
|
||||
container.insertAdjacentHTML('beforeend', rowTemplate);
|
||||
// Init new elements
|
||||
const newRow = container.lastElementChild;
|
||||
initRowLogic(newRow);
|
||||
});
|
||||
|
||||
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" } });
|
||||
artSelect.classList.remove('tom-select-init');
|
||||
}
|
||||
} else {
|
||||
nameInput.style.display = 'block';
|
||||
artWrapper.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
// 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 existing rows
|
||||
container.querySelectorAll('.compartment-row').forEach(initRowLogic);
|
||||
|
||||
container.addEventListener('click', function(e) {
|
||||
if (e.target.closest('.btn-remove-comp')) {
|
||||
e.target.closest('.compartment-row').remove();
|
||||
}
|
||||
});
|
||||
|
||||
// Image Handling Logic
|
||||
// Image Handling Logic (same as before)
|
||||
const imageFileInput = document.getElementById('image_file');
|
||||
const imagePreview = document.getElementById('imagePreview');
|
||||
const pasteArea = document.getElementById('pasteArea');
|
||||
@@ -500,4 +588,4 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php require_once 'footer.php'; ?>
|
||||
<?php require_once 'footer.php'; ?>
|
||||
Reference in New Issue
Block a user