Initial public commit
This commit is contained in:
155
templates/addressbook.html.j2
Normal file
155
templates/addressbook.html.j2
Normal 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 %}
|
||||
85
templates/addressbook_card.html.j2
Normal file
85
templates/addressbook_card.html.j2
Normal 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
69
templates/base.html.j2
Normal 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>
|
||||
52
templates/calendar.html.j2
Normal file
52
templates/calendar.html.j2
Normal 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
127
templates/carddav.html.j2
Normal 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
23
templates/map.html.j2
Normal 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
292
templates/profile.html.j2
Normal 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 %}
|
||||
Reference in New Issue
Block a user