PIVOT 1.1.0
This commit is contained in:
commit
8a53234eb6
161 files changed
+31109
No files matched your search
@@ -0,0 +1,143 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Toegestane IP-adressen{% endblock %}
|
||||
{% block page_title %}Toegestane IP-adressen{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
.ip-form { display: flex; flex-wrap: wrap; gap: 10px; align-items: end; }
|
||||
.ip-form .field { margin: 0; flex: 0 1 340px; }
|
||||
.mijn-ip { display: inline-flex; gap: 8px; align-items: center; padding: 6px 12px; border-radius: 999px;
|
||||
background: var(--surface-muted); border: 1px solid var(--border); font-size: .92em; }
|
||||
.mijn-ip button { all: unset; cursor: pointer; color: var(--primary-color); font-size: .9em; }
|
||||
.mono, td.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
|
||||
.tabel-zoek { margin-bottom: 10px; max-width: 360px; }
|
||||
th.sorteer { cursor: pointer; user-select: none; white-space: nowrap; }
|
||||
th.sorteer:hover { color: var(--primary-color); }
|
||||
th.sorteer .pijl::after { content: "↕"; opacity: .35; margin-left: 2px; }
|
||||
th.sorteer.op .pijl::after { content: "▲"; opacity: 1; }
|
||||
th.sorteer.af .pijl::after { content: "▼"; opacity: 1; }
|
||||
.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; }
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card">
|
||||
<div class="page-head">
|
||||
<h2>✅ Toegestane IP-adressen · {{ school_naam }}</h2>
|
||||
<span class="mijn-ip">Jouw IP-adres: <strong class="mono">{{ mijn_ip }}</strong>
|
||||
{% if not lokaal %}<button type="button" id="gebruikMijnIp" title="Invullen in het veld hieronder">invullen</button>{% endif %}</span>
|
||||
</div>
|
||||
<p class="field-hint" style="margin-top:-6px">Een adres in deze lijst mag PIVOT altijd openen. Je voegt het toe voor
|
||||
{{ school_naam }}, met jouw naam ({{ naam }}) als opmerking. Je kan enkel de adressen verwijderen die je zelf toegevoegd hebt.</p>
|
||||
|
||||
<form method="POST" action="{{ url_for('ipblokkade.toevoegen') }}" class="ip-form">
|
||||
<div class="field">
|
||||
<label for="reeks">IP-adres</label>
|
||||
<input type="text" id="reeks" name="reeks" required class="mono" placeholder="bv. 85.12.3.4" autocomplete="off">
|
||||
</div>
|
||||
<button type="submit">➕ Toevoegen</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="card ip-tabel" data-sleutel="school">
|
||||
<h2 class="card-title">Lijst <span class="muted small">({{ rijen|length }})</span></h2>
|
||||
{% if rijen|length > 10 %}<input type="search" class="tabel-zoek" placeholder="Zoek een adres of naam..." aria-label="Zoeken">{% endif %}
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sorteer" data-tekst>IP-adres <span class="pijl"></span></th>
|
||||
<th class="sorteer" data-tekst>Opmerking <span class="pijl"></span></th>
|
||||
<th class="sorteer">Toegevoegd <span class="pijl"></span></th>
|
||||
<th class="actions"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for r in rijen %}
|
||||
<tr>
|
||||
<td class="mono" data-sort="{{ r.Sorteer }}"><strong>{{ r.Reeks }}</strong></td>
|
||||
<td data-sort="{{ r.Opmerking or '' }}">{{ r.Opmerking or '' }}</td>
|
||||
<td class="muted small" data-sort="{{ r.Aangemaakt.isoformat() }}">{{ r.Aangemaakt.strftime('%d-%m-%Y %H:%M') }}</td>
|
||||
<td class="actions">
|
||||
{% if r.Eigen %}
|
||||
<form method="POST" action="{{ url_for('ipblokkade.verwijderen', regel_id=r.ID) }}" style="margin:0"
|
||||
onsubmit="return confirm({{ (r.Reeks ~ ' uit de lijst verwijderen?')|tojson|forceescape }})">
|
||||
<button type="submit" class="btn-sm btn-ghost">🗑️ Verwijderen</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr class="empty-row"><td colspan="4">Er zijn nog geen toegestane adressen voor {{ school_naam }}.</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% if rijen %}
|
||||
<div class="tabel-voet">
|
||||
<div style="display:flex;align-items:center;gap:14px;flex-wrap:wrap">
|
||||
<div class="muted small teller"></div>
|
||||
<span class="per-pagina-plek"></span>
|
||||
</div>
|
||||
<nav class="paginering" aria-label="Pagina's"></nav>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
document.getElementById('gebruikMijnIp')?.addEventListener('click', () => {
|
||||
const v = document.getElementById('reeks'); v.value = {{ mijn_ip|tojson }}; v.focus();
|
||||
});
|
||||
document.querySelectorAll('.ip-tabel').forEach(kaart => {
|
||||
const body = kaart.querySelector('tbody');
|
||||
if (!body || body.querySelector('.empty-row')) return;
|
||||
const sleutel = 'ip-' + kaart.dataset.sleutel;
|
||||
let PER_PAGINA = perPagina(sleutel), pagina = 1, zoek = '';
|
||||
const zoekveld = kaart.querySelector('.tabel-zoek');
|
||||
function toon() {
|
||||
const rijen = Array.from(body.rows).filter(tr => !zoek || tr.textContent.toLowerCase().includes(zoek));
|
||||
const grootte = PER_PAGINA || Infinity, paginas = Math.max(1, Math.ceil(rijen.length / grootte));
|
||||
pagina = Math.min(Math.max(1, pagina), paginas);
|
||||
const van = PER_PAGINA ? (pagina - 1) * PER_PAGINA : 0, tot = van + grootte;
|
||||
Array.from(body.rows).forEach(tr => tr.style.display = 'none');
|
||||
rijen.forEach((tr, i) => tr.style.display = (i >= van && i < tot) ? '' : 'none');
|
||||
kaart.querySelector('.teller').textContent = rijen.length
|
||||
? `${van + 1}–${Math.min(tot, rijen.length)} van ${rijen.length}` : 'Niets gevonden';
|
||||
const nav = kaart.querySelector('.paginering');
|
||||
nav.innerHTML = '';
|
||||
if (paginas <= 1) return;
|
||||
const knop = (label, p, actief) => {
|
||||
const b = document.createElement('button');
|
||||
b.type = 'button'; b.textContent = label; b.className = 'btn-sm ' + (actief ? 'btn-secondary' : 'btn-light');
|
||||
b.onclick = () => { pagina = p; toon(); };
|
||||
nav.appendChild(b);
|
||||
};
|
||||
if (pagina > 1) { knop('«', 1); knop('‹ Vorige', 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('Volgende ›', pagina + 1); knop('»', paginas); }
|
||||
}
|
||||
if (zoekveld) zoekveld.addEventListener('input', () => { zoek = zoekveld.value.trim().toLowerCase(); pagina = 1; toon(); });
|
||||
let kol = null, op = true;
|
||||
kaart.querySelectorAll('th.sorteer').forEach(th => th.addEventListener('click', () => {
|
||||
const k = th.cellIndex;
|
||||
op = kol === k ? !op : 'tekst' in th.dataset;
|
||||
kol = k;
|
||||
kaart.querySelectorAll('th.sorteer').forEach(x => x.classList.remove('op', 'af'));
|
||||
th.classList.add(op ? 'op' : 'af');
|
||||
Array.from(body.rows).sort((a, b) => {
|
||||
const x = a.cells[k].dataset.sort || '', y = b.cells[k].dataset.sort || '';
|
||||
if (!x !== !y) return x ? -1 : 1;
|
||||
const c = x.localeCompare(y, 'nl', { numeric: true, sensitivity: 'base' });
|
||||
return op ? c : -c;
|
||||
}).forEach(tr => body.appendChild(tr));
|
||||
pagina = 1; toon();
|
||||
}));
|
||||
perPaginaKiezer(kaart.querySelector('.per-pagina-plek'), sleutel, n => { PER_PAGINA = n; pagina = 1; toon(); });
|
||||
toon();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in new issue
Block a user