fix: Layout-Selector für Mehrfach-Übernahme aus Anhänge-Liste
All checks were successful
Deploy bericht / deploy (push) Successful in 1s

Der Layout-Dropdown in der Toolbar bezog sich nur auf die aktuell
angezeigte Seite, nicht auf die Übernahme-Aktion. Ergebnis: User
stellten 2x2 ein, kreuzten 4 Bilder an, klickten 'Übernehmen' — und
bekamen 4 einzelne Seiten statt einer Grid-Seite.

Fix: Neben dem Übernahme-Button eigener Layout-Selector mit Optionen
Einzeln / 2 / 2v / 4 / 6 / Vorher-Nachher. Bei Grid-Layout werden
die ausgewählten Bilder automatisch in Gruppen à slotCount aufgeteilt
und entsprechend viele Seiten angelegt (z.B. 10 Bilder + grid_4 = 3
Seiten mit 4+4+2). Die einzelnen ▭▭/▦/VN-Buttons entfallen damit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
[deploy]
This commit is contained in:
Eduard Wisch 2026-04-09 13:31:26 +02:00
parent f55da13234
commit bf1ad1bafa
2 changed files with 51 additions and 43 deletions

View file

@ -402,14 +402,17 @@ if (!$bericht) {
} }
print '</div>'; print '</div>';
} }
print '<button type="button" id="btn-add-selected" class="butAction" title="Jedes ausgewählte Bild als eigene Seite">'.$langs->trans("BerichtAddSelectedToReport").'</button>'; print '<div class="bericht-add-selected" style="margin-top:6px;">';
print '<div class="bericht-grid-buttons" style="margin-top:6px;">'; print '<label class="opacitymedium small" style="display:block;margin-bottom:4px;">Layout für die Auswahl:</label>';
print '<span class="opacitymedium small">Mehrere Bilder als Grid:</span><br>'; print '<select id="add-selected-layout" style="width:100%;margin-bottom:6px;">';
print '<button type="button" class="btn-add-grid" data-layout="grid_2" title="2 Bilder (oben/unten)">▭▭</button> '; print '<option value="single">Einzeln (1 Bild pro Seite)</option>';
print '<button type="button" class="btn-add-grid" data-layout="grid_2v" title="2 Bilder (links/rechts)">▯▯</button> '; print '<option value="grid_2">2 pro Seite (oben/unten)</option>';
print '<button type="button" class="btn-add-grid" data-layout="grid_4" title="2x2 Grid">▦</button> '; print '<option value="grid_2v">2 pro Seite (links/rechts)</option>';
print '<button type="button" class="btn-add-grid" data-layout="grid_6" title="3x2 Grid">▦▦</button>'; print '<option value="grid_4">4 pro Seite (2x2)</option>';
print ' <button type="button" class="btn-add-grid" data-layout="before_after" title="Vorher / Nachher (2 Bilder)">VN</button>'; print '<option value="grid_6">6 pro Seite (3x2)</option>';
print '<option value="before_after">Vorher / Nachher (2 pro Seite)</option>';
print '</select>';
print '<button type="button" id="btn-add-selected" class="butAction" style="width:100%;" title="Alle ausgewählten Bilder mit dem gewählten Layout in den Bericht übernehmen">'.$langs->trans("BerichtAddSelectedToReport").'</button>';
print '</div>'; print '</div>';
} }
print '<hr>'; print '<hr>';

View file

@ -814,51 +814,56 @@
/* ---------- Anhänge & Thumbs ---------- */ /* ---------- Anhänge & Thumbs ---------- */
function bindAttachments() { function bindAttachments() {
const btn = document.getElementById('btn-add-selected'); const btn = document.getElementById('btn-add-selected');
const layoutSel = document.getElementById('add-selected-layout');
if (btn) { if (btn) {
btn.addEventListener('click', async () => { btn.addEventListener('click', async () => {
const checks = document.querySelectorAll('.att-check:checked');
for (const c of checks) {
const fd = new FormData();
fd.append('token', cfg.token);
fd.append('berichtid', cfg.berichtid);
fd.append('relpath', c.dataset.relpath);
fd.append('mime', c.dataset.mime);
await fetch(cfg.urls.add_attachment, { method: 'POST', body: fd });
c.checked = false;
}
location.reload();
});
}
// Grid-Buttons: ausgewählte Bilder als eine Multi-Image-Seite hinzufügen
document.querySelectorAll('.btn-add-grid').forEach(b => {
b.addEventListener('click', async () => {
const layout = b.dataset.layout;
const checks = document.querySelectorAll('.att-check:checked'); const checks = document.querySelectorAll('.att-check:checked');
if (!checks.length) { if (!checks.length) {
alert('Bitte zuerst Bilder ankreuzen'); alert('Bitte zuerst Bilder ankreuzen');
return; return;
} }
const slotCount = { grid_2: 2, grid_2v: 2, grid_4: 4, grid_6: 6 }[layout] || 4; const layout = layoutSel ? layoutSel.value : 'single';
const relpaths = Array.from(checks)
.filter(c => c.dataset.mime.startsWith('image')) if (layout === 'single') {
.slice(0, slotCount) // Wie bisher: jedes Bild als eigene Seite
.map(c => c.dataset.relpath); for (const c of checks) {
if (!relpaths.length) { const fd = new FormData();
alert('Bitte mindestens ein Bild ankreuzen (PDFs sind in Grids nicht unterstützt)'); fd.append('token', cfg.token);
fd.append('berichtid', cfg.berichtid);
fd.append('relpath', c.dataset.relpath);
fd.append('mime', c.dataset.mime);
await fetch(cfg.urls.add_attachment, { method: 'POST', body: fd });
c.checked = false;
}
location.reload();
return; return;
} }
const fd = new FormData();
fd.append('token', cfg.token); // Grid-Layout: in Gruppen aufteilen
fd.append('berichtid', cfg.berichtid); const slotCount = { grid_2: 2, grid_2v: 2, grid_4: 4, grid_6: 6, before_after: 2 }[layout] || 4;
fd.append('layout', layout); const imageChecks = Array.from(checks).filter(c => c.dataset.mime.startsWith('image'));
fd.append('relpaths', JSON.stringify(relpaths)); if (!imageChecks.length) {
const r = await fetch(cfg.urls.create_grid_page, { method: 'POST', body: fd }); alert('Bitte mindestens ein Bild ankreuzen (PDFs nicht in Grids unterstützt)');
const data = await r.json().catch(() => ({})); return;
if (data.success) location.reload(); }
else alert('Fehler: ' + (data.error || 'unbekannt')); // In Gruppen à slotCount aufteilen
for (let i = 0; i < imageChecks.length; i += slotCount) {
const group = imageChecks.slice(i, i + slotCount).map(c => c.dataset.relpath);
const fd = new FormData();
fd.append('token', cfg.token);
fd.append('berichtid', cfg.berichtid);
fd.append('layout', layout);
fd.append('relpaths', JSON.stringify(group));
const r = await fetch(cfg.urls.create_grid_page, { method: 'POST', body: fd });
const data = await r.json().catch(() => ({}));
if (!data.success) {
alert('Fehler bei Gruppe '+(Math.floor(i/slotCount)+1)+': '+(data.error || 'unbekannt'));
return;
}
}
location.reload();
}); });
}); }
// Lösch-Buttons in der Anhänge-Liste // Lösch-Buttons in der Anhänge-Liste
document.querySelectorAll('.att-delete').forEach(btn => { document.querySelectorAll('.att-delete').forEach(btn => {