PIVOT 1.1.0
This commit is contained in:
commit
8a53234eb6
161 files changed
+31109
No files matched your search
@@ -0,0 +1,352 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Contacten{% endblock %}
|
||||
{% block page_title %}Contacten{% endblock %}
|
||||
{% block main_class %}wide{% endblock %}
|
||||
{% block loader_text %}Bezig met Google...{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
[hidden] { display: none !important; }
|
||||
.tabs { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
|
||||
.tabs a { padding: 8px 16px; border-radius: 999px; border: 1px solid var(--border); background: var(--surface, #fff);
|
||||
text-decoration: none; color: var(--text, #1e293b); font-weight: 600; font-size: .93em; }
|
||||
.tabs a.actief { border-color: var(--primary-color); color: var(--primary-color); background: var(--primary-light); }
|
||||
.balk { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin: 12px 0; }
|
||||
.balk input[type=search] { flex: 0 1 320px; margin: 0; }
|
||||
.balk select { width: auto; min-width: 220px; margin: 0; }
|
||||
.balk .rechts { margin-left: auto; display: flex; flex-wrap: wrap; gap: 8px; }
|
||||
td.nowrap { white-space: nowrap; }
|
||||
td.acties { white-space: nowrap; text-align: right; }
|
||||
td.acties form, td.acties button { display: inline; margin: 0 0 0 4px; }
|
||||
.tabel-voet { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 10px; margin-top: 12px; }
|
||||
.paginering { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
|
||||
.velden2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 12px; }
|
||||
.velden2 .vol { grid-column: 1 / -1; }
|
||||
.lijst-kaarten { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 12px; }
|
||||
.lijst-kaart { border: 1px solid var(--border); border-radius: var(--radius); padding: 14px; text-decoration: none; color: inherit;
|
||||
display: block; background: var(--surface, #fff); }
|
||||
.lijst-kaart:hover, .lijst-kaart.actief { border-color: var(--primary-color); background: var(--primary-light); }
|
||||
.lijst-kaart strong { display: block; font-size: 1.02em; }
|
||||
.lijst-kaart .muted { font-size: .85em; }
|
||||
.lijst-kaart.nieuw { display: grid; place-items: center; border-style: dashed; color: var(--primary-color); font-weight: 600; min-height: 90px; }
|
||||
.ou-kader { border: 1px solid var(--border); border-radius: var(--radius); max-height: 200px; overflow: auto; padding: 6px 10px; }
|
||||
.ou-kader label { display: flex; gap: 8px; align-items: center; margin: 0; padding: 3px 0; font-weight: 400; cursor: pointer; }
|
||||
.ou-kader input, .klein-vink input { width: auto; margin: 0; }
|
||||
.klein-vink { display: flex; gap: 8px; align-items: center; font-weight: 400; margin-top: 8px; }
|
||||
.lijst-raster { display: grid; grid-template-columns: minmax(240px, 1fr) minmax(260px, 1fr); gap: 16px; }
|
||||
@media (max-width: 900px) { .lijst-raster, .velden2 { grid-template-columns: 1fr; } }
|
||||
#items td { padding: 4px 6px; }
|
||||
#items input { margin: 0; padding: 5px 8px; font-size: 13px; min-width: 110px; }
|
||||
.voortgang { height: 8px; border-radius: 999px; background: var(--surface-muted); overflow: hidden; margin: 8px 0; }
|
||||
.voortgang div { height: 100%; width: 0; background: var(--primary-color); transition: width .4s; }
|
||||
.zicht { display: inline-block; padding: 2px 10px; border-radius: 999px; font-size: .85em; font-weight: 600; }
|
||||
.zicht.ja { background: #dcfce7; color: #15803d; } .zicht.nee { background: #fee2e2; color: #b91c1c; }
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<nav class="tabs" aria-label="Soort contacten">
|
||||
<a href="{{ url_for('contacten.overzicht', tab='lijsten') }}" class="{{ 'actief' if tab == 'lijsten' }}">📇 Contactlijsten in mailboxen</a>
|
||||
<a href="{{ url_for('contacten.overzicht', tab='adresboek') }}" class="{{ 'actief' if tab == 'adresboek' }}">👥 Adresboek van de organisatie</a>
|
||||
</nav>
|
||||
|
||||
{% if fout %}<div class="alert alert-danger">{{ fout }}</div>{% endif %}
|
||||
|
||||
{# ======================= 1. Contactlijsten ======================= #}
|
||||
{% if tab == 'lijsten' %}
|
||||
<div class="card">
|
||||
<h2 class="card-title">📇 Contactlijsten in de mailboxen</h2>
|
||||
<p class="field-hint" style="margin-top:-6px">Een lijst is een label in Google Contacten (bv. "School - Directie") met vaste contacten.
|
||||
PIVOT zet die contacten in de persoonlijke contacten van iedereen in de gekozen OU's en houdt ze bij: aanpassen of verwijderen
|
||||
in de lijst doet PIVOT ook in de mailboxen. Andere contacten van de gebruikers blijven onaangeroerd.</p>
|
||||
|
||||
<div id="voortgangKaart" {{ '' if status.bezig or status.resultaat or status.fout else 'hidden' }} style="margin-bottom:14px">
|
||||
<div class="small"><strong id="sLijst">{{ status.lijst or '' }}</strong> · <b id="tVoortgang">{{ status.voortgang }}</b> / <b id="tTotaal">{{ status.totaal }}</b> mailboxen{% if status.fouten %} · ⚠️ {{ status.fouten }}{% endif %}</div>
|
||||
<div class="voortgang"><div id="balk"></div></div>
|
||||
<div class="alert alert-success" id="resultaat" style="margin:6px 0 0" {{ '' if status.resultaat and not status.bezig else 'hidden' }}>{{ status.resultaat or '' }}</div>
|
||||
<div class="alert alert-danger" id="foutmelding" style="margin:6px 0 0" {{ '' if status.fout else 'hidden' }}>{{ status.fout or '' }}</div>
|
||||
<ul class="muted small" id="foutvoorbeelden">{% for f in status.foutvoorbeelden %}<li>{{ f }}</li>{% endfor %}</ul>
|
||||
</div>
|
||||
|
||||
{% if lijsten is defined %}
|
||||
<div class="lijst-kaarten">
|
||||
{% for l in lijsten %}
|
||||
<a class="lijst-kaart {{ 'actief' if gekozen and gekozen.ID == l.ID }}" href="{{ url_for('contacten.overzicht', tab='lijsten', lijst=l.ID) }}">
|
||||
<strong>📇 {{ l.Naam }}</strong>
|
||||
<span class="muted">{{ l.aantal }} contact(en) · {{ l.ous|join(', ') or 'geen OU' }}</span><br>
|
||||
<span class="muted">{% if l.Laatste_sync %}In de mailboxen sinds {{ l.Laatste_sync.strftime('%d-%m-%Y %H:%M') }}{% else %}Nog niet naar de mailboxen gestuurd{% endif %}</span>
|
||||
</a>
|
||||
{% endfor %}
|
||||
<a class="lijst-kaart nieuw" href="{{ url_for('contacten.overzicht', tab='lijsten', nieuw=1) }}">➕ Nieuwe lijst</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if gekozen or nieuw %}
|
||||
{% set l = gekozen or {} %}
|
||||
<div class="card" id="lijstKaart">
|
||||
<div class="page-head" style="margin-bottom:8px">
|
||||
<h2>{{ '✏️ ' ~ l.Naam if gekozen else '➕ Nieuwe contactlijst' }}</h2>
|
||||
<div class="actions">
|
||||
{% if gekozen %}
|
||||
<button type="button" class="btn-danger btn-sm" id="lijstWeg">🗑️ Lijst verwijderen</button>
|
||||
<button type="button" class="btn-light btn-sm" id="lijstSync" title="Nu (opnieuw) in alle mailboxen zetten">▶ Naar de mailboxen</button>
|
||||
{% endif %}
|
||||
<button type="button" class="btn-success btn-sm" id="lijstBewaar">💾 Bewaren</button>
|
||||
</div>
|
||||
</div>
|
||||
{% if gekozen and gekozen.Resultaat %}<p class="muted small" style="margin-top:0">Laatste keer: {{ gekozen.Resultaat }}</p>{% endif %}
|
||||
<div class="lijst-raster">
|
||||
<div>
|
||||
<div class="field"><label for="lNaam">Naam van de lijst (label in Google Contacten)</label>
|
||||
<input type="text" id="lNaam" value="{{ l.Naam or '' }}" maxlength="100" placeholder="bv. School - Directie en secretariaat"></div>
|
||||
{% if gekozen and gekozen.Laatste_sync %}<p class="field-hint">Wijzig je de naam of de OU's, dan past PIVOT dat na het bewaren ook in de mailboxen aan.</p>{% endif %}
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Voor wie (OU's)</label>
|
||||
<div class="ou-kader" id="ouKader">
|
||||
{% for ou in ous %}<label><input type="checkbox" value="{{ ou }}" {{ 'checked' if ou in (l.ous or []) }}> {{ ou }}</label>{% endfor %}
|
||||
</div>
|
||||
<label class="klein-vink"><input type="checkbox" id="lSub" {{ 'checked' if (l.Met_sub_ous if gekozen else 1) }}> Ook de onderliggende OU's</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 style="margin:18px 0 8px">Contacten in deze lijst</h3>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Voornaam</th><th>Achternaam</th><th>Organisatie</th><th>Functie</th><th>E-mail</th><th>Telefoon</th><th>Notitie</th><th></th></tr></thead>
|
||||
<tbody id="items"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="balk">
|
||||
<button type="button" class="btn-light btn-sm" id="rijErbij">➕ Contact toevoegen</button>
|
||||
<span class="muted small">Tip: plak meerdere regels uit Excel (voornaam, achternaam, organisatie, functie, e-mail, telefoon) in het eerste veld.</span>
|
||||
</div>
|
||||
<p class="field-hint">Vereist in de domeinbrede delegatie: <code>https://www.googleapis.com/auth/contacts</code>, en de
|
||||
<strong>People API</strong> moet aanstaan in het Google Cloud-project van het serviceaccount.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{# ======================= 2. Adresboek ======================= #}
|
||||
{% if tab == 'adresboek' %}
|
||||
<div class="card">
|
||||
<h2 class="card-title">👥 Adresboek van de organisatie</h2>
|
||||
<p class="field-hint" style="margin-top:-6px">Wie verborgen is, verschijnt niet meer in het adresboek van de school en niet bij het
|
||||
aanvullen van e-mailadressen in Gmail (bv. leerlingen verbergen voor elkaar). De mailbox zelf blijft gewoon werken.</p>
|
||||
<form class="balk" method="GET" action="{{ url_for('contacten.overzicht') }}" onchange="showLoader(); this.submit()">
|
||||
<input type="hidden" name="tab" value="adresboek">
|
||||
<select name="ou" aria-label="OU">
|
||||
<option value="">— kies een OU —</option>
|
||||
{% for o in ous or [] %}<option value="{{ o }}" {{ 'selected' if o == ou }}>{{ o }}</option>{% endfor %}
|
||||
</select>
|
||||
<input type="hidden" name="sub" value="0">
|
||||
<label class="klein-vink" style="margin:0"><input type="checkbox" name="sub" value="1" {{ 'checked' if met_sub }}> met onderliggende OU's</label>
|
||||
</form>
|
||||
|
||||
{% if ou and gebruikers is defined %}
|
||||
{% if gebruikers %}
|
||||
{% set verborgen = gebruikers|rejectattr('zichtbaar')|list|length %}
|
||||
<div class="balk">
|
||||
<input type="search" class="zoek" data-doel="adresBody" placeholder="Zoek op naam of e-mail..." aria-label="Zoeken">
|
||||
<span class="muted small">{{ gebruikers|length }} gebruiker(s) · <b id="aantalVerborgen">{{ verborgen }}</b> verborgen</span>
|
||||
<div class="rechts">
|
||||
<button type="button" class="btn-sm btn-light" data-zet="0" data-wie="gekozen" disabled>🙈 Geselecteerden verbergen</button>
|
||||
<button type="button" class="btn-sm btn-light" data-zet="1" data-wie="gekozen" disabled>👁 Geselecteerden tonen</button>
|
||||
<button type="button" class="btn-sm btn-danger" data-zet="0" data-wie="alle">🙈 Iedereen verbergen</button>
|
||||
<button type="button" class="btn-sm btn-success" data-zet="1" data-wie="alle">👁 Iedereen tonen</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th style="width:28px"><input type="checkbox" id="allesKiezen" style="width:auto;margin:0"></th>
|
||||
<th>Naam</th><th>E-mail</th><th>OU</th><th>In het adresboek</th><th></th></tr></thead>
|
||||
<tbody id="adresBody">
|
||||
{% for u in gebruikers %}
|
||||
<tr data-email="{{ u.email }}">
|
||||
<td><input type="checkbox" class="kies" style="width:auto;margin:0"></td>
|
||||
<td><strong>{{ u.naam }}</strong>{% if u.geschorst %} <span class="badge badge-warning">geschorst</span>{% endif %}</td>
|
||||
<td class="small">{{ u.email }}</td>
|
||||
<td class="small muted">{{ u.ou }}</td>
|
||||
<td class="zichtcel">{% if u.zichtbaar %}<span class="zicht ja">zichtbaar</span>{% else %}<span class="zicht nee">verborgen</span>{% endif %}</td>
|
||||
<td class="acties"><button type="button" class="btn-sm btn-light wissel">{{ '🙈 Verbergen' if u.zichtbaar else '👁 Tonen' }}</button></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}<p class="muted">Geen gebruikers in deze OU.</p>{% endif %}
|
||||
{% elif not fout %}<p class="muted">Kies een OU.</p>{% endif %}
|
||||
<p class="field-hint" style="margin-top:14px">Of het adresboek voor iedereen zichtbaar is, stel je in de Admin-console in
|
||||
(Directory › Instellingen voor directory › Zichtbaarheid); dat kan niet via de API.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
const post = (url, data) => fetch(url, { method: 'POST', credentials: 'same-origin',
|
||||
headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data || {}) }).then(r => r.json());
|
||||
window.addEventListener('click', e => { if (e.target.classList && e.target.classList.contains('modal')) e.target.style.display = 'none'; });
|
||||
|
||||
// Zoeken + paginering (generiek voor de tabellen met een zoekveld)
|
||||
document.querySelectorAll('input.zoek').forEach(veld => {
|
||||
const body = document.getElementById(veld.dataset.doel);
|
||||
if (!body) return;
|
||||
const kaart = body.closest('.card'), voet = document.createElement('div');
|
||||
voet.className = 'tabel-voet';
|
||||
voet.innerHTML = '<div class="muted small teller"></div><nav class="paginering"></nav>';
|
||||
body.closest('.table-wrap').after(voet);
|
||||
const kiezer = document.createElement('span');
|
||||
veld.after(kiezer);
|
||||
const rijen = Array.from(body.rows);
|
||||
let PER = perPagina('contacten-' + veld.dataset.doel, 25), pagina = 1, z = '';
|
||||
function toon() {
|
||||
const lijst = rijen.filter(tr => !z || tr.textContent.toLowerCase().includes(z));
|
||||
const grootte = PER || Infinity, paginas = Math.max(1, Math.ceil(lijst.length / grootte));
|
||||
pagina = Math.min(Math.max(1, pagina), paginas);
|
||||
const van = PER ? (pagina - 1) * PER : 0, tot = van + grootte;
|
||||
rijen.forEach(tr => tr.style.display = 'none');
|
||||
lijst.forEach((tr, i) => tr.style.display = i >= van && i < tot ? '' : 'none');
|
||||
voet.querySelector('.teller').textContent = lijst.length ? `${van + 1}–${Math.min(tot, lijst.length)} van ${lijst.length}` : 'Niets gevonden';
|
||||
const nav = voet.querySelector('nav'); nav.innerHTML = '';
|
||||
if (paginas > 1) {
|
||||
const knop = (t, p, a) => { const b = document.createElement('button'); b.type = 'button'; b.textContent = t;
|
||||
b.className = 'btn-sm ' + (a ? 'btn-secondary' : 'btn-light'); b.onclick = () => { pagina = p; toon(); }; nav.appendChild(b); };
|
||||
if (pagina > 1) { knop('«', 1); knop('‹', pagina - 1); }
|
||||
for (let p = Math.max(1, pagina - 2); p <= Math.min(paginas, pagina + 2); p++) knop(String(p), p, p === pagina);
|
||||
if (pagina < paginas) { knop('›', pagina + 1); knop('»', paginas); }
|
||||
}
|
||||
}
|
||||
veld.addEventListener('input', () => { z = veld.value.trim().toLowerCase(); pagina = 1; toon(); });
|
||||
perPaginaKiezer(kiezer, 'contacten-' + veld.dataset.doel, n => { PER = n; pagina = 1; toon(); }, 25);
|
||||
toon();
|
||||
});
|
||||
|
||||
{% if tab == 'adresboek' %}
|
||||
(function () {
|
||||
const body = document.getElementById('adresBody');
|
||||
if (!body) return;
|
||||
const rijen = Array.from(body.rows);
|
||||
const gekozen = () => rijen.filter(tr => tr.querySelector('.kies').checked);
|
||||
const tel = () => document.querySelectorAll('[data-wie="gekozen"]').forEach(b => b.disabled = !gekozen().length);
|
||||
body.addEventListener('change', tel);
|
||||
document.getElementById('allesKiezen').addEventListener('change', e => {
|
||||
rijen.filter(tr => tr.style.display !== 'none').forEach(tr => tr.querySelector('.kies').checked = e.target.checked); tel();
|
||||
});
|
||||
function zet(trs, zichtbaar) {
|
||||
if (!trs.length) return;
|
||||
const tekst = `${trs.length} gebruiker(s) ${zichtbaar ? 'tonen in' : 'verbergen uit'} het adresboek van de organisatie?`;
|
||||
if (trs.length > 1 && !confirm(tekst)) return;
|
||||
showLoader('Bezig met Google...');
|
||||
post({{ url_for('contacten.adresboek')|tojson }}, { emails: trs.map(tr => tr.dataset.email), zichtbaar }).then(r => {
|
||||
hideLoader();
|
||||
const fout = new Set((r.fouten || []).map(f => f.split(':')[0]));
|
||||
trs.forEach(tr => {
|
||||
if (fout.has(tr.dataset.email)) return;
|
||||
tr.querySelector('.zichtcel').innerHTML = zichtbaar ? '<span class="zicht ja">zichtbaar</span>' : '<span class="zicht nee">verborgen</span>';
|
||||
tr.querySelector('.wissel').textContent = zichtbaar ? '🙈 Verbergen' : '👁 Tonen';
|
||||
tr.querySelector('.kies').checked = false;
|
||||
});
|
||||
document.getElementById('aantalVerborgen').textContent = rijen.filter(tr => tr.querySelector('.zicht.nee')).length;
|
||||
tel();
|
||||
if (r.fout || (r.fouten || []).length) alert(r.fout || ('Mislukt:\n' + r.fouten.slice(0, 5).join('\n')));
|
||||
}).catch(() => { hideLoader(); alert('Er ging iets mis.'); });
|
||||
}
|
||||
body.addEventListener('click', e => {
|
||||
const b = e.target.closest('.wissel'); if (!b) return;
|
||||
const tr = b.closest('tr'); zet([tr], !tr.querySelector('.zicht.ja'));
|
||||
});
|
||||
document.querySelectorAll('[data-zet]').forEach(b => b.addEventListener('click', () =>
|
||||
zet(b.dataset.wie === 'alle' ? rijen : gekozen(), b.dataset.zet === '1')));
|
||||
})();
|
||||
{% endif %}
|
||||
|
||||
{% if tab == 'lijsten' %}
|
||||
const URL_STATUS = {{ url_for('contacten.status')|tojson }};
|
||||
function kijk() {
|
||||
fetch(URL_STATUS, { credentials: 'same-origin' }).then(r => r.json()).then(s => {
|
||||
const k = document.getElementById('voortgangKaart'); k.hidden = false;
|
||||
document.getElementById('sLijst').textContent = s.lijst || '';
|
||||
document.getElementById('tVoortgang').textContent = s.voortgang; document.getElementById('tTotaal').textContent = s.totaal;
|
||||
document.getElementById('balk').style.width = (s.totaal ? Math.round(100 * s.voortgang / s.totaal) : (s.bezig ? 3 : 100)) + '%';
|
||||
const res = document.getElementById('resultaat'), fout = document.getElementById('foutmelding');
|
||||
res.hidden = !(s.resultaat && !s.bezig); res.textContent = s.resultaat || '';
|
||||
fout.hidden = !s.fout; fout.textContent = s.fout || '';
|
||||
document.getElementById('foutvoorbeelden').innerHTML = (s.foutvoorbeelden || []).map(f => `<li>${f.replace(/</g, '<')}</li>`).join('');
|
||||
if (s.bezig) setTimeout(kijk, 1500);
|
||||
}).catch(() => setTimeout(kijk, 4000));
|
||||
}
|
||||
{% if status.bezig %}kijk();{% endif %}
|
||||
|
||||
{% if gekozen or nieuw %}
|
||||
(function () {
|
||||
const ITEMS = {{ (gekozen['items'] if gekozen else [])|tojson }};
|
||||
const LIJST_ID = {{ (gekozen.ID if gekozen else none)|tojson }};
|
||||
const VELDEN = ['Voornaam', 'Achternaam', 'Organisatie', 'Functie', 'Email', 'Telefoon', 'Notitie'];
|
||||
const SLEUTELS = ['voornaam', 'achternaam', 'organisatie', 'functie', 'email', 'telefoon', 'notitie'];
|
||||
const body = document.getElementById('items');
|
||||
const esc = t => String(t ?? '').replace(/[&<>"]/g, c => ({ '&': '&', '<': '<', '>': '>', '"': '"' })[c]);
|
||||
function rij(i) {
|
||||
const tr = document.createElement('tr');
|
||||
tr.dataset.id = i.ID || '';
|
||||
tr.innerHTML = VELDEN.map((v, n) => `<td><input type="${v === 'Email' ? 'email' : 'text'}" data-k="${SLEUTELS[n]}" value="${esc(i[v])}"></td>`).join('')
|
||||
+ '<td class="acties"><button type="button" class="btn-sm btn-ghost weg" title="Weghalen">🗑️</button></td>';
|
||||
body.appendChild(tr);
|
||||
return tr;
|
||||
}
|
||||
ITEMS.forEach(rij);
|
||||
if (!ITEMS.length) rij({});
|
||||
document.getElementById('rijErbij').onclick = () => rij({}).querySelector('input').focus();
|
||||
body.addEventListener('click', e => { if (e.target.closest('.weg')) e.target.closest('tr').remove(); });
|
||||
// Plakken uit Excel: meerdere regels met tabs → meerdere rijen
|
||||
body.addEventListener('paste', e => {
|
||||
const tekst = (e.clipboardData || window.clipboardData).getData('text');
|
||||
if (!tekst.includes('\t') && !tekst.includes('\n')) return;
|
||||
e.preventDefault();
|
||||
const startTr = e.target.closest('tr');
|
||||
tekst.replace(/\r/g, '').split('\n').filter(r => r.trim()).forEach((regel, n) => {
|
||||
const tr = n === 0 && startTr && !Array.from(startTr.querySelectorAll('input')).some(i => i.value) ? startTr : rij({});
|
||||
regel.split('\t').slice(0, VELDEN.length).forEach((w, k) => tr.querySelectorAll('input')[k].value = w.trim());
|
||||
});
|
||||
});
|
||||
const verzamel = () => ({
|
||||
id: LIJST_ID, naam: document.getElementById('lNaam').value,
|
||||
ous: Array.from(document.querySelectorAll('#ouKader input:checked')).map(x => x.value),
|
||||
met_sub: document.getElementById('lSub').checked,
|
||||
items: Array.from(body.rows).map(tr => Object.assign({ id: tr.dataset.id },
|
||||
Object.fromEntries(Array.from(tr.querySelectorAll('input')).map(i => [i.dataset.k, i.value]))))
|
||||
});
|
||||
document.getElementById('lijstBewaar').onclick = () => {
|
||||
const d = verzamel();
|
||||
if (!d.ous.length && !confirm('Er is nog geen OU gekozen: de lijst gaat dan naar niemand. Toch bewaren?')) return;
|
||||
showLoader('Bewaren...');
|
||||
post({{ url_for('contacten.lijst_bewaren')|tojson }}, d).then(r => {
|
||||
if (!r.ok) { hideLoader(); alert(r.fout || 'Bewaren mislukt.'); return; }
|
||||
location.href = {{ url_for('contacten.overzicht', tab='lijsten')|tojson }} + '&lijst=' + r.id;
|
||||
}).catch(() => { hideLoader(); alert('Bewaren mislukt.'); });
|
||||
};
|
||||
{% if gekozen %}
|
||||
document.getElementById('lijstSync').onclick = () => {
|
||||
if (!confirm('De contacten van deze lijst nu in alle mailboxen van de gekozen OU\'s zetten (of bijwerken)?\nBewaar eerst je wijzigingen.')) return;
|
||||
post({{ url_for('contacten.lijst_sync', lijst_id=gekozen.ID)|tojson }}).then(r => {
|
||||
if (!r.ok) { alert(r.fout || 'Starten mislukt.'); return; }
|
||||
kijk(); window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
});
|
||||
};
|
||||
document.getElementById('lijstWeg').onclick = () => {
|
||||
if (!confirm('Deze lijst verwijderen?' + ({{ (gekozen.Laatste_sync is not none)|tojson }}
|
||||
? '\n\nPIVOT haalt de contacten en het label dan ook uit alle mailboxen.' : ''))) return;
|
||||
post({{ url_for('contacten.lijst_verwijderen', lijst_id=gekozen.ID)|tojson }}).then(r => {
|
||||
if (!r.ok) { alert(r.fout || 'Verwijderen mislukt.'); return; }
|
||||
if (r.gestart) { kijk(); document.getElementById('lijstKaart').remove(); }
|
||||
else location.href = {{ url_for('contacten.overzicht', tab='lijsten')|tojson }};
|
||||
});
|
||||
};
|
||||
{% endif %}
|
||||
})();
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in new issue
Block a user