Initial public commit

This commit is contained in:
Joost Rijneveld
2024-08-04 10:01:08 +02:00
commit b35de92531
34 changed files with 1432 additions and 0 deletions

View File

@@ -0,0 +1,155 @@
{% extends 'base.html.j2' %}
{% set active_page = "addressbook" %}
{% block content %}
<div class="flex-grow-1 overflow-hidden d-flex pt-3 pb-lg-3" style='flex-basis: 0;'>
<div class="overflow-auto col-12 col-lg-4 {% if profile%}d-none{% endif %} d-lg-block" id="contacts">
{% if contacts %}
<div class="list-group">
{% for user in contacts %}
<button type="button" onclick="handleButtonClick(this)" data-username='{{ user.username }}'
class="profile-button list-group-item list-group-item-action {% if profile.username == user.username %}active{% endif%}">{{
user.display_name }}</button>
{% endfor %}
</div>
{% else %}
<div class="h-100 w-100 d-flex align-items-center">
<div class="w-100 text-center" style="color: lightgrey"><em>Geen contacten om te tonen</em></div>
</div>
{% endif %}
</div>
<div class="col pt-lg-2 ps-lg-4 pe-lg-4">
<div class="container overflow-auto h-100 pb-3 pb-lg-0" id="profile-wrap">
{% if profile %}
{% include 'addressbook_card.html.j2' %}
{% elif contacts %}
<div class="h-100 w-100 d-flex align-items-center">
<div class="w-100 text-center">
<p class="fst-italic" style="color: lightgrey">Niemand geselecteerd</p>
</div>
</div>
{% endif %}
</div>
</div>
</div>
<div class="toast-container position-fixed bottom-0 end-0 p-3">
<div id="toast-loading" class="toast align-items-center text-bg-primary border-0" role="alert" aria-live="assertive"
data-bs-autohide="false" aria-atomic="true">
<div class="d-flex">
<div class="toast-body">
<div class="spinner-border spinner-border-sm me-2" role="status"></div>Het duurt wat langer om te
laden..
</div>
</div>
</div>
</div>
<div class="toast-container position-fixed bottom-0 end-0 p-3">
<div id="toast-error" class="toast align-items-center text-bg-danger border-0" role="alert" aria-live="assertive"
data-bs-autohide="false" aria-atomic="true">
<div class="d-flex">
<div class="toast-body">
<i class="bi bi-exclamation-circle-fill me-1"></i>
<strong>Laden mislukt!</strong><br>
Herlaad de pagina of probeer het later opnieuw.
</div>
</div>
</div>
</div>
{% endblock %}
{% block js %}
<script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"></script>
<script type="text/javascript">
var addressbookURL = {{ url_for('addressbook') | tojson}}
var cardURL = {{ url_for('addressbook_card') | tojson}}
function showContacts() {
document.getElementById('contacts').classList.remove('d-none');
scrollToActive();
}
function handleButtonClick(element) {
var username = element.dataset.username;
history.pushState({ 'username': username }, '', addressbookURL + username);
selectProfile(username);
}
function renderMap() {
var element = document.getElementById('osm-map-small');
if (element) {
var data = element.dataset
var map = L.map(element);
L.tileLayer('https://a.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png').addTo(map);
var marker = L.marker(L.latLng(data['lat'], data['lon'])).addTo(map);
marker.bindTooltip(data['label'], { 'permanent': true })
var target = L.latLng(data['lat'], data['lon']);
map.setView(target, 15);
}
}
function selectProfile(username) {
Array.from(document.getElementsByClassName('profile-button')).forEach(
function (element, idx, array) {
element.classList.remove('active')
if (element.dataset.username == username) {
element.classList.add('active')
}
}
)
var timeoutLoading = setTimeout(() => {
bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-loading')).show()
}, 1000);
var timeoutError = setTimeout(() => {
bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-error')).show()
}, 10000);
fetch(cardURL + username)
.then(function (response) {
if (response.ok) {
return response.text();
}
return Promise.reject(response);
})
.then(
function (html) {
document.getElementById('profile-wrap').innerHTML = html
renderMap();
document.getElementById('contacts').classList.add('d-none');
clearTimeout(timeoutLoading);
clearTimeout(timeoutError);
},
function (html) {
clearTimeout(timeoutLoading);
clearTimeout(timeoutError);
bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-error')).show()
}
)
}
function scrollToActive() {
var active = document.getElementsByClassName('profile-button active');
if (active.length > 0) {
var grandParent = active[0].parentNode.parentNode;
grandParent.scrollTop = active[0].offsetTop - grandParent.offsetTop - grandParent.clientHeight / 2 + active[0].clientHeight / 2
}
}
window.addEventListener('popstate', function () {
var url = window.location.href;
var username = url.split('/').filter((fragment) => fragment.length > 0).at(-1);
if (username == 'addressbook') {
return
}
selectProfile(username)
scrollToActive();
})
window.addEventListener('load', function () {
scrollToActive();
renderMap();
});
</script>
{% endblock %}

View File

@@ -0,0 +1,85 @@
<div class="row">
<div class="col">
<h4 class="display-4 d-flex"><span class='flex-fill'>{{ profile.display_name }}</span>
<button class="d-lg-none btn btn-primary align-self-center" type="button" onclick="showContacts()"><i
class="bi bi-people-fill"></i></button>
</h4>
</div>
</div>
<div class="row">
<div class="col-4 fst-italic">Voornaam:
</div>
<div class="col">{{ profile.first_name }}
</div>
</div>
<div class="row">
<div class="col-4 fst-italic">Achternaam:
</div>
<div class="col">{{ profile.last_name }}
</div>
</div>
<hr>
<div class="row">
<div class="col-4 fst-italic">E-mailadres:
</div>
<div class="col">{{ profile.email }}
</div>
</div>
<div class="row">
<div class="col-4 fst-italic">Telefoonnummer:
</div>
<div class="col">{{ profile.phone }}
</div>
</div>
<hr>
<div class="row">
<div class="col-4 fst-italic">Straatnaam:
</div>
<div class="col">{{ profile.street }}
</div>
</div>
<div class="row">
<div class="col-4 fst-italic">Huisnummer:
</div>
<div class="col">{{ profile.number }}
</div>
</div>
<div class="row">
<div class="col-4 fst-italic">Postcode:
</div>
<div class="col">{{ profile.postal }}
</div>
</div>
<div class="row">
<div class="col-4 fst-italic">Stad:
</div>
<div class="col">{{ profile.city }}
</div>
</div>
<div class="row">
<div class="col-4 fst-italic">Land:
</div>
<div class="col">{{ profile.country }}
</div>
</div>
{% if profile.lat and profile.lon %}
<div class="row mt-3">
<div class="col">
<div id="osm-map-small" data-lat="{{ profile.marker.lat }}" data-lon="{{ profile.marker.lon }}"
data-label="{{ profile.marker.label }}"></div>
</div>
</div>
{% endif %}
<hr>
<div class="row">
<div class="col-4 fst-italic">Verjaardag:
</div>
<div class="col">{% if profile.birthdate %}{{ profile.birthdate | date_format }}{% endif %}
</div>
</div>
<hr>
<div class="row">
<div class="col text-center"><em>Laatst bijgewerkt: {{ profile.last_updated | datetime_format }}</em>
</div>
</div>

69
templates/base.html.j2 Normal file
View File

@@ -0,0 +1,69 @@
<!doctype html>
<html lang="nl">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>adRUsboek</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
<link href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" rel="stylesheet" />
<link href="{{ url_for('static', filename='css/bootstrap-flatly.min.css') }}" rel="stylesheet" />
<link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
{% block header %}
{% endblock %}
</head>
<body>
<div class="container h-100 d-flex flex-column p-0">
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
<a class="navbar-brand" href="#">
<img id='logo' src="{{ url_for('static', filename='img/logo.png') }}" />adRUsboek
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link {% if active_page == 'map' %}active{% endif %}"
href="{{ url_for('overview_map') }}">Kaartje</a>
</li>
<li class="nav-item">
<a class="nav-link {% if active_page == 'calendar' %}active{% endif %}"
href="{{ url_for('calendar') }}">Verjaardagskalender</a>
</li>
<li class="nav-item">
<a class="nav-link {% if active_page == 'addressbook' %}active{% endif %}"
href="{{ url_for('addressbook') }}">Adresboek</a>
</li>
<li class="nav-item">
<a class="nav-link {% if active_page == 'carddav' %}active{% endif %}"
href="{{ url_for('carddav') }}">CardDAV</a>
</li>
</ul>
<ul class="navbar-nav ms-auto">
<li>
<a class="nav-link {% if active_page == 'profile' %}active{% endif %}"
href="{{ url_for('profile')}}">Mijn profiel ({{user.username }})</a>
</li>
</ul>
</div>
</div>
</nav>
{% block content %}{% endblock %}
</div>
{% block toplevel %}{% endblock %}
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"
integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js"
integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy"
crossorigin="anonymous"></script>
{% block js %}{% endblock %}
</body>
</html>

View File

@@ -0,0 +1,52 @@
{% extends 'base.html.j2' %}
{% set active_page = "calendar" %}
{% block content %}
<div class="container mt-3">
<div class="row mb-3">
<div class="col p-0">
<div class="ratio" style="--bs-aspect-ratio: 50%;">
<img class='img-fluid' src="{{ img_src }}" id="calendar_img" />
</div>
{#<div class="text-end pt-1 small fst-italic">
<small id="img_credits">{% if img_credits %}Foto: {{ img_credits }}{% endif %}</small>
</div>#}
</div>
</div>
<div class="row mb-3 d-flex align-items-center">
<div class="col text-start">
{% set prevmonth = ((month - 1 + 12 - 1) % 12) + 1 %}
{% set nextmonth = ((month + 1 - 1) % 12) + 1 %}
<a class="monthlink" href="{{ url_for('calendar')}}?month={{ prevmonth }}"><i
class="bi bi-caret-left-fill"></i>
</a>
</div>
<div class="col">
<h1 class="display-5 text-center">{{ month | to_month | capitalize }}</h1>
</div>
<div class="col text-end">
<a class="monthlink" href="{{ url_for('calendar')}}?month={{ nextmonth }}"><i
class="bi bi-caret-right-fill"></i></a>
</div>
</div>
<div class="row">
{% for col in columns %}
<div class="col-md-4">
{% for birthdate in col %}
<p style="display: block; border-bottom:1px solid black;">
<span class='me-1'>{{ birthdate.day }}.</span> {{
birthdate.bucket | join(",
") }}
{% if birthdate.day == today and birthdate.bucket %}<span class='ms-1'>🎉</span>{% endif %}
</p>
{% endfor %}
</div>
{% endfor %}
</div>
</div>
{% endblock %}

127
templates/carddav.html.j2 Normal file
View File

@@ -0,0 +1,127 @@
{% extends 'base.html.j2' %}
{% set active_page = "carddav" %}
{% block content %}
<div class="container mt-3">
<div class="row">
<div class="col">
<h1 class="display-6">CardDAV</h1>
<p class="lead">
Zodat je adRUsboek altijd dichtbij is.
</p>
<p>
De gegevens van 't adRUsboek zijn via CardDAV te importeren in je favoriete contacten-applicatie. Hoe je
dat precies configureert verschilt een beetje per applicatie. Voor een aantal veelgebruikte applicaties
verzamelen we hieronder instructies. Ontbreekt er een applicatie of kom je er niet uit? Laat het vooral
even weten aan Joost!
</p>
<p>
In het algemeen geldt dat je de volgende gegevens kunt proberen:
</p>
<div class="container mb-3">
<div class="row">
<div class="col-md-3 col-lg-2 text-md-end">
Gebruikersnaam:
</div>
<div class="col-md-9 col-lg-10">
<code>{{ user.username }}</code>
</div>
</div>
<div class="row">
<div class="col-md-3 col-lg-2 text-md-end">
Wachtwoord:
</div>
<div class="col-md-9 col-lg-10">
<code>{{ user.carddav_key }}</code>
</div>
</div>
<div class="row">
<div class="col-md-3 col-lg-2 text-md-end">
Serveradres:
</div>
<div class="col-md-9 col-lg-10">
<code>{{ carddav_url }}</code>
</div>
</div>
</div>
<p>Let op! Je wachtwoord is persoonlijk, en specifiek voor CardDAV-toegang. Opnieuw genereren?
<a href="#" data-bs-toggle="modal" data-bs-target="#cardDAVModal">Klik hier</a>.
</p>
{% with successes = get_flashed_messages(category_filter=["carddav"]) %}
{% if successes %}
{% for msg in successes %}
<div class="alert alert-success" role="alert">
{{ msg }}
</div>
{% endfor %}
{% endif %}
{% endwith %}
<hr>
<h4>Contacts.app op iOS</h4>
Om het adRUsboek toe te voegen:
<ol>
<li>Ga naar <strong>Settings > Contacts > Accounts</strong>.</li>
<li>Ga naar <strong>Accounts</strong>.</li>
<li>Kies <strong>Add Account</strong>.</li>
<li>Kies <strong>Other</strong>.</li>
<li>Kies <strong>Add CardDAV account</strong>.</li>
<li>Vul de hierboven genoemde gegevens in.</li>
<li>Vul eventueel een <em>Description</em> in (bijvoorbeeld 'adRUsboek').</li>
<li>Kies <strong>Next</strong>. Als je gegevens kloppen verschijnen er vinkjes.</li>
</ol>
Om het adRUsboek te bekijken:
<ol>
<li>Open de contacten-app en klik op <strong>List</strong>.</li>
<li>Kies de lijst die overeenkomt met je gekozen <em>Description</em>.</li>
</ol>
<hr>
<h4>Contacts.app op macOS</h4>
<p><em>TODO: om voor mij onduidelijke redenen werkt het onderstaande niet :(</em></p>
Om het adRUsboek toe te voegen:
<ol>
<li>Start <strong>Contacts</strong>.</li>
<li>Ga naar <strong>Settings > Accounts</strong>.</li>
<li>Klik op de <strong>+</strong> onderaan de lijst.</li>
<li>Kies <strong>'Other Contacts account..'</strong> en klik op <strong>Continue</strong>.</li>
<li>Kies bij <em>Account type</em> voor <strong>Manual</strong>.</li>
<li>Vul de hierboven genoemde gegevens in.</li>
<li>Klik op <strong>Sign in</strong>. Het account verschijnt nu in de lijst.</li>
</ol>
Om het adRUsboek te bekijken:
<ol>
<li>Open de contacten-app en klik op <strong>idm.hashru.nl</strong>.</li>
<li>.. zie een lege lijst? :(</li>
</ol>
</div>
</div>
</div>
{% endblock %}
{% block toplevel %}
<div class="modal fade" id="cardDAVModal" tabindex="-1" aria-labelledby="cardDAVModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="cardDAVModalLabel">Wachtwoord resetten</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
Weet je zeker dat je je CardDAV-wachtwoord opnieuw wil genereren? Het oude wachtwoord wordt daarmee
ongeldig.
</div>
<div class="modal-footer">
<form method="post" action="{{ url_for('generate_carddav_password') }}">
<input type="hidden" name="_csrf_token" value="{{ csrf_token() }}">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuleren</button>
<button type="submit" class="btn btn-primary">Wachtwoord resetten</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}

23
templates/map.html.j2 Normal file
View File

@@ -0,0 +1,23 @@
{% extends 'base.html.j2' %}
{% set active_page = "map" %}
{% block content %}
<div class="flex-fill mt-3 mb-sm-3" id="osm-map"></div>
{% endblock %}
{% block js %}
<script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"></script>
<script type="text/javascript">
var markerdata = {{ markers | tojson }};
var map = L.map(document.getElementById('osm-map'));
L.tileLayer('https://a.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png').addTo(map);
markerdata.forEach(data => {
marker = L.marker(L.latLng(data['lat'], data['lon'])).addTo(map);
marker.bindTooltip(data['label'])
});
var target = L.latLng('51.8449', '5.8428'); // Nijmegen
map.setView(target, 13);
</script>
{% endblock %}

292
templates/profile.html.j2 Normal file
View File

@@ -0,0 +1,292 @@
{% extends 'base.html.j2' %}
{% set active_page = "profile" %}
{% block content %}
<div class="container mt-3">
<div class="row">
<div class="col">
<h1 class="display-6">Mijn profiel</h1>
<p>
Op je profiel kun je je gegevens invullen. Alle velden zijn optioneel.
{# Je kunt ook aangeven dat je je gegevens alleen met bepaalde gebruikers wilt
delen; voor niet-geselecteerde gebruikers zal het lijken alsof je de niet-gedeelde gegevens niet hebt
ingevuld. #}
</p>
{% with successes = get_flashed_messages(category_filter=["success"]) %}
{% if successes %}
{% for msg in successes %}
<div class="alert alert-success" role="alert">
{{ msg }}
</div>
{% endfor %}
{% endif %}
{% endwith %}
<form method="post" action="{{ url_for('profile') }}">
<input type="hidden" name="_csrf_token" value="{{ csrf_token() }}">
<div class="row">
<label for="input-firstname" class="col-md-2 col-sm-4 col-form-label text-sm-end">Voornaam</label>
<div class="col-md-4 col-sm-8 mb-sm-3">
<input type="text" class="form-control" id="input-firstname" name="first_name"
value="{{ user.first_name }}">
</div>
<label for="input-lastname" class="col-md-2 col-sm-4 col-form-label text-sm-end">Achternaam</label>
<div class="col-md-4 col-sm-8 mb-sm-3">
<input type="text" class="form-control" id="input-lastname" name="last_name"
value="{{ user.last_name }}">
</div>
</div>
<div class="row mb-3">
<label for="input-displayname" class="col-md-2 col-sm-4 col-form-label text-sm-end">
<span class='d-none d-md-inline d-lg-none'>Weergave</span>
<span class='d-inline d-md-none d-lg-inline'>Weergavenaam</span>
</label>
<div class="col-md-4 col-sm-8">
<input type="text" class="form-control" id="input-displayname" disabled
value="{{ user.display_name }}">
<small class="text-muted">Afkomstig van idm.hashru.nl</small>
</div>
</div>
<hr class="mb-2 mb-sm-3">
<div class="row">
<label for="input-email" class="col-md-2 col-sm-4 col-form-label text-sm-end">E-mailadres</label>
<div class="col-md-4 col-sm-8 mb-md-0 mb-sm-3">
<input type="text" class="form-control" id="input-email" name="email" value="{{ user.email }}">
</div>
<label id="label-phone" for="input-phone" class="col-md-2 col-sm-4 col-form-label text-sm-end">
<span class='d-none d-md-inline d-lg-none'>Telefoonnr.</span>
<span class='d-inline d-md-none d-lg-inline'>Telefoonnummer</span>
</label>
<div class="col-md-4 col-sm-8">
<input type="text" class="form-control" id="input-phone" name="phone" value="{{ user.phone }}">
</div>
</div>
{# <div class="row mb-3">
<div class="col-sm-10 offset-sm-2">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="contact-whitelist-check">
<label class="form-check-label" for="contact-whitelist-check">
Contactgegevens alleen tonen aan geselecteerde gebruikers.
</label>
</div>
</div>
</div> #}
<hr class="mb-2 mb-sm-3">
<div class="row mb-3">
<div class="col-md-6">
<div class="row mb-sm-3">
<label for="input-street" class="col-sm-4 col-form-label text-sm-end">Straatnaam</label>
<div class="col-sm-8">
<input type="text" class="form-control update-latlon" id="input-street" name="street"
value="{{ user.street }}">
</div>
</div>
<div class="row mb-sm-3">
<label for="input-number" class="col-sm-4 col-form-label text-sm-end">Huisnummer</label>
<div class="col-sm-8">
<input type="text" class="form-control update-latlon" id="input-number" name="number"
value="{{ user.number }}">
</div>
</div>
<div class="row mb-sm-3">
<label for="input-postal" class="col-sm-4 col-form-label text-sm-end">Postcode</label>
<div class="col-sm-8">
<input type="text" class="form-control update-latlon" id="input-postal" name="postal"
value="{{ user.postal }}">
</div>
</div>
<div class="row mb-sm-3">
<label for="input-city" class="col-sm-4 col-form-label text-sm-end">Woonplaats</label>
<div class="col-sm-8">
<input type="text" class="form-control update-latlon" id="input-city" name="city"
value="{{ user.city }}">
</div>
</div>
<div class="row">
<label for="input-country" class="col-sm-4 col-form-label text-sm-end">Land</label>
<div class="col-sm-8">
<input type="text" class="form-control update-latlon" id="input-country" name="country"
value="{{ user.country }}">
</div>
</div>
<div class="row">
<!-- <label for="input-lat" class="col-sm-4 col-form-label text-sm-end">Latitude</label> -->
<div class="col-sm-3">
<input type="hidden" class="form-control" id="input-lat" name="lat"
value="{{ user.lat }}">
</div>
<!-- <label for="input-lon" class="col-sm-2 col-form-label text-sm-end">Longitude</label> -->
<div class="col-sm-3">
<input type="hidden" class="form-control" id="input-lon" name="lon"
value="{{ user.lon }}">
</div>
</div>
<div class="row">
<div class="offset-sm-4">
<!-- <small class="text-muted">Coördinaten zijn alleen voor weergave op de kaart.</small> -->
</div>
</div>
</div>
<div class="col-md-6 pt-3 pt-md-0">
<div class='h-100' id="osm-map" style="min-height:18em;"></div>
</div>
</div>
{# <div class="row mb-3">
<div class="col-sm-10 offset-sm-2">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="address-whitelist-check">
<label class="form-check-label" for="address-whitelist-check">
Adresgegevens alleen tonen aan geselecteerde gebruikers.
</label>
</div>
</div>
</div> #}
<hr class="mb-2 mb-sm-3">
<div class="row mb-3">
<label for="input-birthdate" class="col-md-2 col-sm-4 col-form-label text-sm-end">Verjaardag</label>
<div class="col-md-4 col-sm-4">
<input id="input-birthdate" class="form-control" name="birthdate" type="date"
value="{{ user.birthdate }}" />
</div>
</div>
{# <div class="row mb-3">
<div class="col-sm-10 offset-sm-2">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="birthdate-whitelist-check">
<label class="form-check-label" for="birthdate-whitelist-check">
Verjaardag alleen tonen aan geselecteerde gebruikers
</label>
</div>
</div>
</div> #}
{#
<hr>
<div class="row mb-3">
<div class="col-sm-10 offset-sm-2">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="include-check" name="include_in_views"
{% if user.include_in_views or user.include_in_views is none %}checked{% endif %}>
<label class="form-check-label" for="include-check">
Toon mij op de kaart, in 't adresboek en op de verjaardagskalender.
</label>
</div>
</div>
</div> #}
<div class="row mb-3">
<div class="col-sm-10 offset-sm-2">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="gdpr-check" required checked>
<label class="form-check-label" for="gdpr-check">
Ik geef toestemming mijn gegevens op te slaan en te delen binnen de context van
adRUsboek.
</label>
<div class="invalid-feedback">
Je moet toestemming geven om je gegevens te verwerken voordat je ze op kunt slaan.
</div>
</div>
</div>
</div>
<div class="row col-sm-12 mb-3">
<div class="col text-center">
{% if user.include_in_views %}
<p>
Je profiel is voor het laatst bijgewerkt op {{ user.last_updated | datetime_format }}.
</p>
{% endif %}
<button type="submit" class="btn btn-primary">Opslaan</button>
</div>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
{% block js %}
<script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"></script>
<script type="text/javascript">
(function () {
'use strict'
const tileserver_osm = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png';
const tileserver_humanitarian = "https://tile.openstreetmap.fr/hot/{z}/{x}/{y}.png"
var map = L.map(document.getElementById('osm-map'));
L.tileLayer(tileserver_humanitarian).addTo(map);
function init_map() {
var target = L.latLng('51.8449', '5.8428'); // Nijmegen
map.setView(target, 12);
}
function place_marker(lat, lon) {
var target = L.latLng(lat, lon);
map.setView(target, 15);
if (marker) {
marker.remove();
}
marker = L.marker(target, { 'draggable': true, 'autoPan': true }).addTo(map);
var name = document.getElementById('input-displayname').value
if (name) {
marker.bindTooltip(name, { permanent: true });
}
marker.addEventListener('move', (event) => {
document.getElementById('input-lat').value = event.latlng['lat'].toFixed(7);
document.getElementById('input-lon').value = event.latlng['lng'].toFixed(7);
})
}
function debounce(func, delay) {
let debounceTimer
return function () {
clearTimeout(debounceTimer)
debounceTimer = setTimeout(() => func.apply(this, arguments), delay)
}
}
var marker = null;
var lat = document.getElementById('input-lat').value;
var lon = document.getElementById('input-lon').value;
if (lat != '' && lon != '') {
place_marker(lat, lon);
}
else {
init_map();
}
var latlon_fields = document.querySelectorAll('.update-latlon');
const geocoding_url = "{{ url_for('geocoding') }}";
Array.from(latlon_fields).forEach(element => {
element.addEventListener("input", debounce((event) => {
fetch(geocoding_url + '?' + new URLSearchParams({
'street': `${document.getElementById('input-street').value} ${document.getElementById('input-number').value}`,
'postalcode': document.getElementById('input-postal').value,
'city': document.getElementById('input-city').value,
'country': document.getElementById('input-country').value,
}).toString())
.then(function (response) {
if (response.ok) {
return response.json();
}
return Promise.reject(response);
})
.then(function (json) {
if (json['lat'] && json['lon']) {
document.getElementById('input-lat').value = json['lat'];
document.getElementById('input-lon').value = json['lon'];
place_marker(json['lat'], json['lon']);
}
})
.catch(function (response) {
document.getElementById('input-lat').value = '';
document.getElementById('input-lon').value = '';
if (marker) {
marker.remove();
}
init_map();
});
}, 1000));
});
})()
</script>
{% endblock %}