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>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
3cf53bc248
commit
db3e26d258
@@ -0,0 +1,57 @@
|
||||
/* 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();
|
||||
})();
|
||||
Reference in New Issue
Block a user