Files
MachielandClaude Opus 5.5 db3e26d258 v0.0.6: massa-acties en CSV-export in de lijsten van contacten, relaties, producten en offertes
Rijen aanvinken (shift-klik voor een reeks, of alles op de pagina) en in de balk onderin een actie kiezen
(templates/_bulk.html, static/bulk.js). Contacten: status wijzigen, toewijzen, omzetten naar klant, exporteren,
verwijderen; relaties: type wijzigen, exporteren, verwijderen; producten: actief/inactief, exporteren, verwijderen
(in offertes gebruikt → inactief); offertes: status wijzigen (met de gevolgen voor het contact), exporteren,
verwijderen. Exporteer CSV neemt de filters van de lijst mee en levert alle velden; bij contacten ook labels,
toegewezen gebruiker, relatie, model, portaaltoegang en de extra formuliervelden als eigen kolom. Nieuwe
leadstatus Vervallen (telt als afgesloten).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 19:12:39 +02:00

58 lines
2.2 KiB
JavaScript

/* Massa-acties in lijsten (templates/_bulk.html): rijen aanvinken, shift-klik voor een reeks,
dan in de balk onderin een actie kiezen. Een klik op het vinkje opent de rij niet. */
(() => {
const form = document.getElementById('bulk');
if (!form) return;
const boxes = Array.from(document.querySelectorAll('input[name="ids"][form="bulk"]'));
const all = document.querySelector('[data-bulk-all]');
const count = form.querySelector('[data-bulk-count]');
const action = form.elements.action;
let last = null;
const update = () => {
const n = boxes.filter(b => b.checked).length;
count.textContent = n;
form.hidden = !n;
document.body.classList.toggle('bulk-open', n > 0);
if (all) {
all.checked = n > 0 && n === boxes.length;
all.indeterminate = n > 0 && n < boxes.length;
}
boxes.forEach(b => b.closest('tr')?.classList.toggle('selected', b.checked));
};
const showFields = () => form.querySelectorAll('[data-show]').forEach(el => {
const on = el.dataset.show === action.value;
el.hidden = !on;
el.disabled = !on;
});
boxes.forEach((box, i) => box.closest('td').addEventListener('click', e => {
e.stopPropagation();
if (e.target !== box) box.checked = !box.checked;
if (e.shiftKey && last !== null) {
boxes.slice(Math.min(last, i), Math.max(last, i) + 1).forEach(b => { b.checked = box.checked; });
}
last = i;
update();
}));
all?.closest('th').addEventListener('click', e => {
if (e.target !== all) all.checked = !all.checked;
boxes.forEach(b => { b.checked = all.checked; });
update();
});
form.querySelector('[data-bulk-clear]').addEventListener('click', () => {
boxes.forEach(b => { b.checked = false; });
update();
});
action.addEventListener('change', showFields);
form.addEventListener('submit', e => {
const ask = action.selectedOptions[0]?.dataset.confirm;
if (ask && !confirm(ask.replace('{n}', count.textContent))) return e.preventDefault();
// een export is een download: de pagina blijft staan, dus de keuze terugzetten
if (action.value === 'export') setTimeout(() => { action.value = ''; showFields(); }, 0);
});
addEventListener('pageshow', update);
showFields();
update();
})();