Merge pull request #26 from openstreetmap-polska/oauth

Oauth
pull/27/head
ttomasz 2021-12-30 00:21:42 +01:00 zatwierdzone przez GitHub
commit a1535f7bf6
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
7 zmienionych plików z 848 dodań i 249 usunięć

Wyświetl plik

@ -1,10 +1,10 @@
<!DOCTYPE html>
<html lang="pl">
<head>
<title>AED - mapa defibrylatorów</title>
<meta charset="utf-8" />
<meta name="title" content="AED - mapa defibrylatorów">
<meta name="description" content="Mapa defibrylatorów AED w Polsce oparta o dane OpenStreetMap">
<title>AED - mapa defibrylatorów</title>
<meta charset="utf-8" />
<meta name="title" content="AED - mapa defibrylatorów">
<meta name="description" content="Mapa defibrylatorów AED w Polsce oparta o dane OpenStreetMap">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<link rel="apple-touch-icon" sizes="180x180" href="src/favicon/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="./src/favicon/favicon-32x32.png">
@ -25,23 +25,31 @@
<meta property="twitter:title" content="AED - mapa defibrylatorów">
<meta property="twitter:description" content="Mapa defibrylatorów AED w Polsce oparta o dane OpenStreetMap">
<meta property="twitter:image" content="https://aed.openstreetmap.org.pl/src/img/meta-image.png">
<script src='./src/osmauth.min.js'></script>
<script src="https://unpkg.com/maplibre-gl@1.15.2/dist/maplibre-gl.js"></script>
<script src="https://openingh.openstreetmap.de/opening_hours.js/opening_hours+deps.min.js" defer></script>
<link href="https://unpkg.com/maplibre-gl@1.15.2/dist/maplibre-gl.css" rel="stylesheet" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css" />
<link rel="stylesheet" href="./src/nasz.css" />
</head>
<body>
<nav class="navbar is-success p-1 has-shadow" role="navigation" aria-label="main navigation">
</head>
<body>
<nav class="navbar has-background-green p-1" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="has-text-weight-light navbar-item has-text-white-ter is-size-4 is-size-5-mobile" href="#">
Mapa <span class="has-text-weight-semibold pl-1 r-1">AED</span>
</a>
<span class="has-text-success-light has-text-weight-light navbar-item is-size-6 is-size-7-touch pl-0">
<span class="has-text-grey-light mr-2">|</span>tworzona z ❤️ przez&nbsp;
<span class="has-text-weight-medium"> <a href="https://openstreetmap.org.pl/" target="_blank" title="Odwiedź stronę polskiej społeczności OSM" rel="noopener" style="color:#effaf5;">OpenStreetMap Polska</a></span>
<span class="has-text-grey-light mr-2">|</span>tworzona z ❤️
przez&nbsp;
<span class="has-text-weight-medium"> <a href="https://openstreetmap.org.pl/" target="_blank"
title="Odwiedź stronę polskiej społeczności OSM"
rel="noopener" style="color:#effaf5;">OpenStreetMap Polska</a>
</span>
</span>
<a role="button" class="navbar-burger has-text-white-ter is-transparent" data-target="navMenu" aria-label="menu" aria-expanded="false">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
@ -50,44 +58,98 @@
</div>
<div id="navMenu" class="navbar-menu">
<div class="navbar-end">
<div class="navbar-item">
<span class="has-text-white has-text-weight-light mr-1">dodaliśmy do mapy już ⚡</span>
<span class="has-text-white-ter is-size-5 has-text-weight-semibold" id="aed-number"></span>
<span class="has-text-white has-text-weight-light ml-1">AED</span>
</div>
<div class="navbar-item pb-0">
<a href="https://github.com/openstreetmap-polska/aed-mapa" target="_blank" rel="noopener">
<img title="Odwiedź nasz Github" class="github" src="./src/img/github-image.png" alt="Github" width="24" height="24"></a>
<div class="navbar-end">
<div class="navbar-item">
<svg class="icon" style="width:24px;height:24px" viewBox="0 0 24 24">
<path fill="#ffc83d" d="M11 15H6L13 1V9H18L11 23V15Z" />
</svg>
<span class="has-text-white has-text-weight-light ">dodaliśmy już&nbsp;</span>
<span class="has-text-white-ter has-text-weight-semibold" id="aed-number">
<button class="button is-loading is-rounded"></button>
</span>
<span class="has-text-white has-text-weight-light ml-1">AED</span>
</div>
<div class="navbar-item" id="span-login"></div>
<div id="navbar-logged" class="navbar-item has-dropdown is-hoverable">
<a id="navbar-username" class="navbar-link has-text-white-ter has-text-weight-light is-arrowless">
</a>
<div class="navbar-dropdown has-background-green">
<a class="navbar-item" id="logout">
<svg class="icon mr-1" style="width:24px;height:24px" viewBox="0 0 24 24">
<path fill="currentColor" d="M16,17V14H9V10H16V7L21,12L16,17M14,2A2,2 0 0,1 16,4V6H14V4H5V20H14V18H16V20A2,2 0 0,1 14,22H5A2,2 0 0,1 3,20V4A2,2 0 0,1 5,2H14Z" />
</svg> Wyloguj
</a>
</div>
</div>
<hr class="navbar-divider">
<div class="navbar-item pb-0">
<a href="https://github.com/openstreetmap-polska/aed-mapa" target="_blank" rel="noopener">
<img title="Odwiedź nasz Github" class="github" src="./src/img/github-image.png" alt="Github" width="24" height="24"></a>
</div>
</div>
</div>
</div>
</nav>
<div class="sidebar is-invisible">
<div id="poi-sidebar" class="card">
<div id="sidebar-div" class="sidebar is-invisible">
<div class="card">
<div id="sidebar-header">
<div class="columns is-vcentered is-flex p-1 mr-0">
<div class="column is-one-quarter is-one-fifth-mobile "><img class="image" src="./src/img/card-image.png" alt="Placeholder image" id="sidebar-card-image" ></div>
<div class="column"><p class="title has-text-white-ter has-text-weight-light py-2" id="sidebar-caption"></p></div>
<button class="delete is-medium is-hidden-touch is-pulled-right close-button mr-2 mt-4" onclick="hideSidebar()" aria-label="Close button"></button>
<button class="delete is-large is-hidden-desktop is-pulled-right close-button mr-2 mt-4" onclick="hideSidebar()" aria-label="Close button"></button>
</div>
</div>
<div class="card-content">
<div class="content">
<div class="column is-one-quarter is-one-fifth-mobile ">
<img class="image" src="./src/img/card-image.png" alt="Placeholder image" id="sidebar-card-image">
</div>
<div class="column">
<p id="sidebar-caption" class="title has-text-white-ter has-text-weight-light py-2"></p>
</div>
<button id="sidebar-button-close-touch" aria-label="Zamknij ekran boczny"
class="delete is-medium is-hidden-touch is-pulled-right close-button mr-2 mt-4"></button>
<button id="sidebar-button-close-desktop" aria-label="Zamknij ekran boczny"
class="delete is-large is-hidden-desktop is-pulled-right close-button mr-2 mt-4"></button>
</div>
</div>
<div class="card-content">
<div id="sidebar-content-div" class="content"></div>
</div>
<footer class="card-footer">
<a href="" class="has-background-success-light card-footer-item has-text-centered is-size-7 has-text-weight-semibold" target="_blank" rel="noopener" >Dodaj brakujące informacje</a>
<a href="https://wiki.openstreetmap.org/wiki/Pl:Przewodnik_dla_pocz%C4%85tkuj%C4%85cych"
class="has-background-success-light card-footer-item has-text-centered is-size-7 has-text-weight-semibold" target="_blank" rel="noopener" >Przewodnik OSM</a>
<div class="has-background-success-light card-footer-item has-text-centered is-size-7 has-text-weight-semibold" id="sidebar-footer-button-left">
<a href="" target="_blank" rel="noopener"
class="has-background-success-light card-footer-item has-text-centered is-size-7 has-text-weight-semibold"></a>
</div>
</footer>
</div>
</div>
<div id="modal-div" class="modal">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<!-- <p class="modal-card-title">Modal title</p>-->
<button class="delete" aria-label="close" onclick="closeModal()"></button>
</header>
<section id="modal-content" class="modal-card-body">
</section>
</div>
<button class="modal-close is-large" aria-label="close" onclick="closeModal()"></button>
</div>
<div id="map"></div>
<div id="map"></div>
<button id="addNode" class="button is-floating is-medium is-success" style="bottom: 8px;left: 16px;" aria-label="Wymaga zalogowania" disabled>
<svg class="icon" viewBox="0 0 24 24">
<path fill="currentColor" d="M19,13H13V19H11V13H5V11H11V5H13V11H19V13Z" />
</svg>
</button>
<script src="./src/other-ui-stuff.js"></script>
<script src="./src/map.js"></script>
<script src="./src/osm-integration.js"></script>
<!-- Cloudflare Web Analytics --><script defer src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon='{"token": "117bf6ce871a40ac9bf5a7330f8538eb"}'></script><!-- End Cloudflare Web Analytics -->
</body>
<!-- Cloudflare Web Analytics -->
<script defer src='https://static.cloudflareinsights.com/beacon.min.js'
data-cf-beacon='{"token": "117bf6ce871a40ac9bf5a7330f8538eb"}'></script>
<!-- End Cloudflare Web Analytics -->
</body>
</html>

9
land.html 100644
Wyświetl plik

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html><head></head>
<body>
<script>
opener.authComplete(window.location.href);
window.close();
</script>
</body>
</html>

Wyświetl plik

@ -1,22 +1,7 @@
let aedSource = './aed_poland.geojson';
let aedMetadata = './aed_poland_metadata.json';
const aedSource = './aed_poland.geojson';
const aedMetadata = './aed_poland_metadata.json';
let aedNumber = document.getElementById('aed-number');
fetch(aedMetadata)
.then(response => response.json())
.then(data => {
aedNumber.innerHTML = data.number_of_elements;
let refreshTimeValue = new Date(data.data_download_ts_utc);
let refreshTimeValueLocale = new Date(data.data_download_ts_utc).toLocaleString('pl-PL');
let currentDate = new Date();
let dateDiff = Math.abs(currentDate - refreshTimeValue);
let dateDiffMinutes = Math.round(dateDiff / 60000);
let refreshTime = document.getElementById('refresh-time');
refreshTime.innerHTML = `Synchronizacja z bazą OSM: <span class="has-text-grey-dark" title="${refreshTimeValueLocale}">${dateDiffMinutes} minut temu</span> | `;
}
);
var map = new maplibregl.Map({
'container': 'map', // container id
'center': [20, 52], // starting position [lng, lat]
@ -43,7 +28,7 @@ var map = new maplibregl.Map({
'type': 'geojson',
'data': aedSource,
'cluster': true,
'clusterRadius': 30,
'clusterRadius': 32,
'maxzoom': 14
},
},
@ -68,146 +53,24 @@ let geolocate = new maplibregl.GeolocateControl({
});
map.addControl(geolocate, 'bottom-right');
function defineColor(access) {
accessValues = {
'yes': 'has-background-green',
'no': 'has-background-grey',
'private': 'has-background-grey',
'permissive': 'has-background-link-dark',
'default': 'has-background-grey'
};
accessClass = accessValues[access] || accessValues['default'];
return accessClass;
}
function defineAccessDescription(access) {
accessValues = {
'yes': 'ogólnodostępny',
'no': 'prywatny',
'private': 'prywatny',
'permissive': 'o ograniczonym dostępie',
'permit': 'o ograniczonym dostępie',
'default': ''
};
accessClass = accessValues[access] || accessValues['default'];
return accessClass;
}
function parseOpeningHours(openingHours) {
if (openingHours) {
if (openingHours.includes('24/7')) {
return 'całodobowo';
} else {
let hoursPrettified;
try {
let hours = openingHours.toString();
let oh = new opening_hours(hours, undefined, 2);
isOpen = oh.getState();
hoursPrettified = oh.prettifyValue({
conf: {
locale: 'pl'
},
});
} catch (error) {
console.log('Error when parsing opening hours');
return undefined;
}
return hoursPrettified;
}
} else {
return undefined;
}
}
function isCurrentlyOpen(openingHours) {
if (openingHours) {
if (openingHours.includes('24/7')) {
return true;
} else {
let hours = openingHours.toString();
let oh = new opening_hours(hours, undefined, 2);
isOpen = oh.getState();
return isOpen;
}
}
}
function defineIndoor(indoor) {
if (indoor == 'yes') {
return 'tak';
} else if (indoor == 'no') {
return 'nie';
} else {
return undefined;
}
}
function showSidebar(properties) {
// SIDEBAR - UI
let sidebar = document.getElementsByClassName('sidebar')[0];
if (sidebar) {
sidebar.classList.remove('is-invisible');
createSidebar(properties);
} else {
console.log('Sidebar not found.');
}
}
function hideSidebar() {
let sidebar = document.getElementsByClassName('sidebar')[0];
if (sidebar) {
sidebar.classList.add('is-invisible');
} else {
console.log('Sidebar not found.');
}
}
function getOsmEditLink(id) {
return `https://www.openstreetmap.org/edit?editor=id&node=${id}`;
}
function createSidebar(properties) {
let sidebarHeader = document.getElementById('sidebar-header');
let sidebarCaption = document.getElementById('sidebar-caption');
let sidebarContent = document.getElementsByClassName('content')[0];
let sidebarLink = document.getElementsByClassName('card-footer-item')[0];
var isCurrOpen = '';
sidebarHeader.classList = [];
sidebarHeader.classList.add(defineColor(properties.access));
sidebarCaption.innerHTML = `defibrylator AED ${defineAccessDescription(properties.access)}`;
if (isCurrentlyOpen(properties.opening_hours)) {
isCurrOpen = '<sup><span class="tag is-success is-light">Dostępny</span></sup>';
} else if (isCurrentlyOpen(properties.opening_hours) == false) {
isCurrOpen = '<sup><span class="tag is-danger is-light">Niedostępny</span></sup>';
}
sidebarContent.innerHTML = '';
sidebarContent.innerHTML = `
<p class="has-text-weight-light">Wewnątrz budynku?: <span class="add-new has-text-weight-medium">${defineIndoor(properties.indoor) || `<span class="has-text-grey-light is-italic has-text-weight-light">brak informacji</span>`}</span></p>
<p class="has-text-weight-light">Dokładna lokalizacja: <span class="add-new has-text-weight-medium">${properties['defibrillator:location:pl'] || properties['defibrillator:location'] || `<span class="has-text-grey-light is-italic has-text-weight-light">brak informacji</span>`}</span></p>
<p class="has-text-weight-light">Dostępny w godzinach: <span class="add-new has-text-weight-medium">${parseOpeningHours(properties.opening_hours) || `<span class="has-text-grey-light is-italic has-text-weight-light">brak informacji</span>`} ${isCurrOpen || '' }</span></p>
<p class="has-text-weight-light">Opis: <span class="add-new has-text-weight-medium">${properties['description:pl'] || properties.description || `<span class="has-text-grey-light is-italic has-text-weight-light">brak informacji</span>`}</span></p>
<p class="has-text-weight-light">Numer kontaktowy: <span class="add-new has-text-weight-medium">${properties.phone || `<span class="has-text-grey-light is-italic has-text-weight-light">brak informacji</span>`}</span></p>
`;
if (properties.note || properties['note:pl']) {
sidebarContent.innerHTML += `<p class="has-text-weight-light">Uwagi: <span class="add-new has-text-weight-medium">${properties['note:pl'] || properties.note || 'brak uwag'}</span></p>`;
}
sidebarLink.setAttribute("href", getOsmEditLink(properties.osm_id));
}
map.on('load', () => {
// get metadata and fill page with info about number of defibrillators and last refresh time
fetch(aedMetadata)
.then(response => response.json())
.then(data => {
// number of defibrillators
aedNumber.innerHTML = data.number_of_elements;
// last refresh time
let refreshTimeValue = new Date(data.data_download_ts_utc);
let refreshTimeValueLocale = new Date(data.data_download_ts_utc).toLocaleString('pl-PL');
let currentDate = new Date();
let dateDiff = Math.abs(currentDate - refreshTimeValue);
let dateDiffMinutes = Math.round(dateDiff / 60000);
let refreshTime = document.getElementById('refresh-time');
refreshTime.innerHTML = `Ostatnia aktualizacja danych OSM: <span class="has-text-grey-dark" title="${refreshTimeValueLocale}">${dateDiffMinutes} minut temu </span>`;
});
console.log('Loading icon...');
map.loadImage('./src/img/marker-image_50.png', (error, image) => {
@ -253,9 +116,14 @@ map.on('load', () => {
},
'filter': ['has', 'point_count'],
});
map.on('click', 'unclustered', function (e) {
if (e.features[0].properties !== undefined) {
showSidebar(e.features[0].properties);
let properties = {
action: "showDetails",
data: e.features[0].properties,
};
showSidebar(properties);
}
});
@ -293,33 +161,6 @@ map.on('load', () => {
);
});
console.log('Ready.');
console.log('Map ready.');
});
});
// Bulma controls
document.addEventListener('DOMContentLoaded', () => {
// Get all "navbar-burger" elements
const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);
// Check if there are any navbar burgers
if ($navbarBurgers.length > 0) {
// Add a click event on each of them
$navbarBurgers.forEach( el => {
el.addEventListener('click', () => {
// Get the target from the "data-target" attribute
const target = el.dataset.target;
const $target = document.getElementById(target);
// Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
el.classList.toggle('is-active');
$target.classList.toggle('is-active');
});
});
}
});

Wyświetl plik

@ -29,33 +29,28 @@
@media (min-width: 500px) {
.sidebar {
position: absolute;
z-index: 1;
margin: 0.5rem !important;
width: 408px;
border-radius: 10px;
box-shadow: 0 .5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.02);
max-height: 90vh;
overflow-y: auto !important;
max-height: 90vh;
overflow: auto !important;
z-index: 10 !important;
}
}
@media (max-width: 500px) {
.sidebar {
position: absolute;
margin: 0 !important;
width: 100vw;
display: block !important;
overflow-wrap: break-word;
max-height: 90vh;
z-index: 2 !important;
overflow-y: auto !important;
}
}
@media (max-width: 500px) {
.navbar {
height: 1vh;
padding: 0 !important;
z-index: 10 !important;
overflow: auto !important;
}
}
@ -87,29 +82,67 @@
}
}
.navbar
{
box-shadow: inset 0 0 1em #0000000c;
.navbar.is-success {
background-color: #008954eb !important;
}
.card-content {
border-left: 5px solid hsl(0, 0%, 96%);
border-right: 5px solid hsl(0, 0%, 96%);
}
.has-background-green {
background-color: #008954eb !important;
}
.navbar-menu.is-active
{
.navbar-menu.is-active {
background-color: #008954eb !important;
}
.mapboxgl-ctrl-attrib-inner {
font-size: 0.6rem !important;
font-weight: 100 !important;
}
.mapboxgl-ctrl.mapboxgl-ctrl-attrib
{
border-top-left-radius: 10px;
.button.is-floating {
position: fixed;
width: 60px;
height: 60px;
bottom: 40px;
right: 40px;
border-radius: 100px;
text-align: center;
font-size: 1.6rem;
box-shadow: 0 .0625em .125em rgba(10, 10, 10, .05);
z-index: 3;
}
.menu-item
{
padding-right: 7px !important;
}
.button.is-floating.is-large {
width: 90px;
height: 90px;
font-size: 2.6rem
}
.button.is-floating.is-medium {
width: 75px;
height: 75px;
font-size: 2.2rem
}
.button.is-floating.is-small {
width: 45px;
height: 45px;
font-size: 1.2rem;
border-radius: 50px
}
[class*=" icon"], [class^=icon] {
display: inline-block;
width: 1em;
height: 1em;
stroke-width: 0;
stroke: currentColor;
fill: currentColor;
line-height: 1;
position: relative;
vertical-align: middle;
}
.navbar-item, .navbar-link {
color: #ffffff;
}

Wyświetl plik

@ -0,0 +1,295 @@
// osm integration stuff
var auth = osmAuth({
oauth_consumer_key: 'SVN3D2Q8ciaIbHCdHbhuiG7mEwvOGbnSDcy1ZgnV',
oauth_secret: 'alqjD88o2qtdN9ZwtOfanqqu5Rbp2lhIxbGFukTD',
url: "https://master.apis.dev.openstreetmap.org",
landing: 'land.html',
});
var openChangesetId = null;
var marker = null;
function getOpenChangesetId() {
return new Promise((resolve, reject) => {
if (openChangesetId !== null) {
resolve(openChangesetId);
} else {
let data = '<osm><changeset>' +
'<tag k="comment" v="Defibrillator added via https://aed.openstreetmap.org.pl #aed"/>' +
'<tag k="created_by" v="https://aed.openstreetmap.org.pl"/>' +
'<tag k="locale" v="pl"/>' +
'<tag k="hashtags" v="#aed"/>' +
'</changeset></osm>';
auth.xhr({
method: 'PUT',
path: '/api/0.6/changeset/create',
content: data,
options: {
header: {
"Content-Type": "text/xml"
}
},
}, (err, res) => {
if (err) {
reject(err);
} else {
openChangesetId = res;
console.log('Api returned changeset id: ' + res);
resolve(res);
}
})
}
})
}
function getNodeUrl(nodeId) {
return `${auth.options().url}/node/${nodeId}`;
}
function renderModalMessage(newNodeUrl) {
return `
<p>AED dodany z powodzeniem:
<a target="_blank" rel="noopener" href="${newNodeUrl}">${newNodeUrl}</a>
</p>`;
}
function renderModalErrorMessage(message) {
return `<p>Wystąpił błąd: ${message}</p>`;
}
function renderModalNeedLoginMessage() {
return `<p>Żeby dodawać obiekty za pomocą długiego dotknięcia/prawego przycisku myszy musisz się zalogować.</p>`;
}
function renderModalNeedMoreZoomMessage() {
return `<p>Żeby dodawać obiekty za pomocą długiego dotknięcia/prawego przycisku myszy musisz bardziej przybliżyć mapę, żeby podana lokalizacja była możliwie dokładna.</p>`;
}
function showNeedMoreZoomModal() {
let modalContent = document.getElementById('modal-content');
modalContent.innerHTML = renderModalNeedMoreZoomMessage();
openModal();
}
function showSuccessModal(newNodeId) {
let modalContent = document.getElementById('modal-content');
modalContent.innerHTML = renderModalMessage(getNodeUrl(newNodeId));
openModal();
}
function showFailureModal(message) {
let modalContent = document.getElementById('modal-content');
modalContent.innerHTML = renderModalErrorMessage(message);
openModal();
}
function openModal() {
let modal = document.getElementById('modal-div');
modal.classList.add('is-clipped');
modal.classList.add('is-active');
}
function closeModal() {
// close modal
let modal = document.getElementById('modal-div');
modal.classList.remove('is-clipped');
modal.classList.remove('is-active');
// remove marker and close sidebar too
let sidebar = document.getElementById('sidebar-div');
if (sidebar) {
sidebar.classList.add('is-invisible');
if (marker !== null) {
marker.remove();
marker = null;
}
} else {
console.log('sidebar not found.');
}
}
function addDefibrillatorToOSM(changesetId, data) {
return new Promise((resolve, reject) => {
console.log('sending request to create node in changeset: ' + changesetId);
var xml = `<osm><node changeset="${changesetId}" lat="${data.lat}" lon="${data.lng}">`;
xml += `<tag k="emergency" v="defibrillator"/>`;
xml += Object.entries(data.tags).map(arr => `<tag k="${arr[0]}" v="${arr[1]}"/>`).join('');
xml += `</node></osm>`;
console.log('payload: ' + xml);
auth.xhr({
method: 'PUT',
path: '/api/0.6/node/create',
content: xml,
options: {
header: {
"Content-Type": "text/xml"
}
},
}, (err, res) => {
if (err) reject(err);
else {
resolve(res);
console.log(`response: ${res}`);
}
});
})
}
function startSaveButtonAnimation() {
let saveButton = document.getElementById('sidebar-save-button');
saveButton.classList.add('is-loading');
saveButton.disabled = true;
}
function stopSaveButtonAnimation() {
let saveButton = document.getElementById('sidebar-save-button');
saveButton.classList.remove('is-loading');
saveButton.disabled = false;
}
function saveNode(data) {
startSaveButtonAnimation();
getOpenChangesetId()
.then(changesetId => {
return addDefibrillatorToOSM(changesetId, data);
})
.then(newNodeId => {
stopSaveButtonAnimation();
showSuccessModal(newNodeId);
})
.catch(err => {
stopSaveButtonAnimation();
console.log(err);
showFailureModal(err);
});
}
document.getElementById('addNode').onclick = function () {
// add marker
const mapCenter = map.getCenter();
const initialCoordinates = [mapCenter.lng, mapCenter.lat];
if (marker !== null) marker.remove();
marker = new maplibregl.Marker({
draggable: true,
color: "#e81224",
})
.setLngLat(initialCoordinates);
marker.addTo(map);
// show sidebar
let properties = {
action: "addNode",
data: {},
};
showSidebar(properties);
};
map.on('contextmenu', function(e) {
// only trigger when logged in
if (auth.authenticated()) {
if (map.getZoom() < 15) {
showNeedMoreZoomModal();
} else {
// add marker
const clickLocation = e.lngLat;
const initialCoordinates = [clickLocation.lng, clickLocation.lat];
if (marker !== null) marker.remove();
marker = new maplibregl.Marker({
draggable: true,
color: "#e81224",
})
.setLngLat(initialCoordinates);
marker.addTo(map);
// show sidebar
let properties = {
action: "addNode",
data: {},
};
showSidebar(properties);
}
} else {
console.log('You need to be logged in to add new nodes.');
showNeedLoginModal();
}
});
function updateNavbarLoggedUserState() {
let navbar = document.getElementById('navbar-logged');
if (!auth.authenticated()) {
navbar.classList.add('is-hidden');
}
else {
navbar.classList.remove('is-hidden');
}
}
document.getElementById('logout').onclick = function () {
auth.logout();
update();
};
function authenticateAction() {
if (!auth.bringPopupWindowToFront()) {
auth.authenticate(function() {
update();
});
}
}
function renderLoginButton() {
return '<button class="button is-success has-text-weight-light is-outlined" id="authenticate" onclick="authenticateAction()">Zaloguj kontem OSM</button>';
}
function renderUserLoggedIn(username) {
return `<svg class="icon mr-1" style="width:24px;height:24px" viewBox="0 0 24 24">
<path fill="currentColor" d="M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z" />
</svg> ${username}`;
}
function renderErrorLoggingIn() {
return '<p>Problem podczas logowania. Spróbuj wyczyścić cache (ctrl+f5).</p>';
}
function updateAddNodeButtonState() {
let addNodeButton = document.getElementById('addNode');
addNodeButton.disabled = false;
addNodeButton.title = "";
if (!auth.authenticated()) {
addNodeButton.disabled = true;
addNodeButton.title = "Zaloguj się aby móc dodawać obiekty";
}
if (map.getZoom() < 15) {
addNodeButton.disabled = true;
addNodeButton.title = "Zbyt duże oddalenie mapy";
}
}
map.on('zoomend', updateAddNodeButtonState);
function update() {
if (auth.authenticated()) {
auth.xhr({
method: 'GET',
path: '/api/0.6/user/details'
}, (err, res) => {
if (err) {
updateAddNodeButtonState();
showFailureModal(err);
} else {
const u = res.getElementsByTagName('user')[0];
const user_name = u.getAttribute('display_name');
const user_with_id = `${user_name}`;
document.getElementById('span-login').innerHTML = '';
document.getElementById('span-login').classList.add('is-hidden');
document.getElementById('navbar-username').innerHTML = renderUserLoggedIn(user_with_id);
updateAddNodeButtonState();
updateNavbarLoggedUserState();
}
});
} else {
document.getElementById('span-login').innerHTML = renderLoginButton();
updateAddNodeButtonState();
updateNavbarLoggedUserState();
}
}
update();

1
src/osmauth.min.js vendored 100644

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -0,0 +1,358 @@
const sidebarDivId = 'sidebar-div';
const sidebarHeaderId = 'sidebar-header';
const sidebarCaptionId = 'sidebar-caption';
const sidebarContentDivId = 'sidebar-content-div';
const sidebarFooterButtonLeftId = 'sidebar-footer-button-left';
const sidebarButtonCloseIds = ['sidebar-button-close-touch', 'sidebar-button-close-desktop'];
const formPhoneFieldId = 'form-phone';
const formAccessFieldId = 'form-access';
const formLocationFieldId = 'form-location';
const formLocationEnFieldId = 'form-location-en';
const formIndoorFieldId = 'form-indoor';
const formEmergencyPhoneFieldId = 'form-emergency-phone';
let sidebarHeader = document.getElementById(sidebarHeaderId);
let sidebarCaption = document.getElementById(sidebarCaptionId);
let sidebarContent = document.getElementById(sidebarContentDivId);
let sidebarLink = document.getElementById(sidebarFooterButtonLeftId);
const accessToColourMapping = {
'yes': 'has-background-green',
'no': 'has-background-grey',
'private': 'has-background-grey',
'permissive': 'has-background-link-dark',
'default': 'has-background-grey',
};
const accessToDescriptionMapping = {
'yes': 'ogólnodostępny',
'no': 'prywatny',
'private': 'prywatny',
'permissive': 'o ograniczonym dostępie',
'default': '',
};
const indoorMapping = {
'yes': 'tak',
'no': 'nie',
'default': '',
};
// --------------------------------------------------------------------------------------
function defineColor(access) {
return accessToColourMapping[access] || accessToColourMapping['default'];
}
function defineAccessDescription(access) {
return accessToDescriptionMapping[access] || accessToDescriptionMapping['default'];
}
function defineIndoor(indoor) {
return indoorMapping[indoor] || indoorMapping['default'];
}
function getOsmEditLink(id) {
return `https://www.openstreetmap.org/edit?editor=id&node=${id}`;
}
function parseOpeningHours(openingHours) {
if (openingHours) {
if (openingHours.includes('24/7')) {
return 'całodobowo';
} else {
let hoursPrettified;
try {
let hours = openingHours.toString();
let oh = new opening_hours(hours, undefined, 2);
isOpen = oh.getState();
hoursPrettified = oh.prettifyValue({
conf: {
locale: 'pl'
},
});
} catch (error) {
console.log('Error when parsing opening hours');
return undefined;
}
return hoursPrettified;
}
} else {
return undefined;
}
}
function isCurrentlyOpen(openingHours) {
if (openingHours) {
if (openingHours.includes('24/7')) {
return true;
} else {
let hours = openingHours.toString();
let oh = new opening_hours(hours, undefined, 2);
isOpen = oh.getState();
return isOpen;
}
}
}
function renderCurrentlyOpenStatus(openingHours) {
if (isCurrentlyOpen(openingHours)) {
return '<sup><span class="tag is-success is-light">Dostępny</span></sup>';
} else {
return '<sup><span class="tag is-danger is-light">Niedostępny</span></sup>';
}
}
function renderIfIndoor(indoor) {
let beginning = '<p class="has-text-weight-light">Wewnątrz budynku?: <span class="add-new has-text-weight-medium">';
let middle = defineIndoor(indoor) || '<span class="has-text-grey-light is-italic has-text-weight-light">brak informacji</span>';
let end = '</span></p>';
return beginning + middle + end;
}
function renderLocation(properties) {
let beginning = '<p class="has-text-weight-light">Dokładna lokalizacja: <span class="add-new has-text-weight-medium">';
let middle = properties['defibrillator:location:pl'] || properties['defibrillator:location'] || '<span class="has-text-grey-light is-italic has-text-weight-light">brak informacji</span>';
let end = '</span></p>';
return beginning + middle + end;
}
function renderDescription(properties) {
let beginning = '<p class="has-text-weight-light">Opis: <span class="add-new has-text-weight-medium">';
let middle = properties['description:pl'] || properties.description || '<span class="has-text-grey-light is-italic has-text-weight-light">brak informacji</span>';
let end = '</span></p>';
return beginning + middle + end;
}
function renderContactNumber(phone) {
let beginning = '<p class="has-text-weight-light">Numer kontaktowy: <span class="add-new has-text-weight-medium">';
let middle = phone || '<span class="has-text-grey-light is-italic has-text-weight-light">brak informacji</span>';
let end = '</span></p>';
return beginning + middle + end;
}
function renderAccessibleTime(openingHours) {
if (openingHours) {
let beginning = '<p class="has-text-weight-light">Dostępny w godzinach: <span class="add-new has-text-weight-medium">';
let middle = parseOpeningHours(openingHours) || '<span class="has-text-grey-light is-italic has-text-weight-light">brak informacji </span>';
let end = (renderCurrentlyOpenStatus(openingHours) || '') + '</span></p>';
return beginning + middle + end;
} else {
return '';
}
}
function renderNotes(properties) {
if (properties.note || properties['note:pl']) {
let beginning = '<p class="has-text-weight-light">Uwagi: <span class="add-new has-text-weight-medium">';
let middle = properties['note:pl'] || properties.note || 'brak uwag';
let end = '</span></p>';
return beginning + middle + end;
} else {
return ''
}
}
function renderSidebarContent(properties) {
let content = '';
content += renderIfIndoor(properties.indoor);
content += renderLocation(properties);
content += renderAccessibleTime(properties.opening_hours);
content += renderDescription(properties);
content += renderContactNumber(properties.phone);
content += renderNotes(properties);
return content
}
function renderSidebarForm() {
let content = `
<form>
<div class="field">
<label class="label has-text-weight-semibold">Rodzaj dostępu</label>
<div class="control">
<div class="select is-success">
<select id="${formAccessFieldId}" tag="access">
<option val="">Wybierz z listy</option>
<option val="yes">Publicznie dostępny</option>
<option val="private">Dostępny za zgodą właściciela</option>
<option val="customers">Dostępny tylko w godzinach pracy</option>
</select>
</div>
</div>
</div>
<div class="field">
<label class="label has-text-weight-semibold">Czy wewnątrz budynku?</label>
<div class="control">
<div class="select is-success">
<select id="${formIndoorFieldId}" tag="location">
<option val="">Wybierz z listy</option>
<option val="outdoor">Na zewnątrz</option>
<option val="indoor">W budynku</option>
</select>
</div>
</div>
</div>
<div class="field">
<label class="label has-text-weight-semibold">Opis lokalizacji defibrylatora</label>
<div class="control">
<textarea id="${formLocationFieldId}" tag="defibrillator:location" class="textarea is-success" rows="2"
placeholder="Na przykład: Na ścianie przy wejściu"></textarea>
</div>
</div>
<div class="field">
<label class="label has-text-weight-semibold">Telefon kontaktowy operatora</label>
<div class="control">
<input id="${formPhoneFieldId}" tag="phone" class="input is-success" type="text" placeholder="+48 123 456 789"
pattern="^[+][0-9]{2}[ ]?((?:[0-9]{9})|(?:[0-9]{3} [0-9]{3} [0-9]{3})|(?:[0-9]{2} [0-9]{3} [0-9]{2} [0-9]{2}))$">
</div>
<p class="help has-text-weight-light">Pole opcjonalne</p>
</div>
<div class="field">
<label class="label has-text-weight-semibold">Numer ratunkowy danego obszaru</label>
<div class="control">
<input id="${formEmergencyPhoneFieldId}" tag="emergency:phone" class="input is-success" type="text" placeholder="+48 123 456 789"
pattern="^[+][0-9]{2}[ ]?((?:[0-9]{9})|(?:[0-9]{3} [0-9]{3} [0-9]{3})|(?:[0-9]{2} [0-9]{3} [0-9]{2} [0-9]{2}))$">
</div>
<p class="help has-text-weight-light">Pole opcjonalne. Wypełnij tylko, jeżeli jest inny niż 112/999.</p>
</div>
<div class="field">
<label class="label has-text-weight-semibold">Opis lokalizacji defibrylatora po angielsku</label>
<div class="control">
<textarea id="${formLocationEnFieldId}" tag="defibrillator:location:en" class="textarea is-success" rows="2"
placeholder="For example: On the wall near entrance"></textarea>
</div>
<p class="help has-text-weight-light">Pole opcjonalne</p>
</div>
<form>
`;
return content;
}
function renderEditButton(osm_id) {
return `<a href="${getOsmEditLink(osm_id)}" target="_blank" rel="noopener"
class="has-background-success-light card-footer-item has-text-centered is-size-7 has-text-weight-semibold"
>Dodaj brakujące informacje w OSM</a>`;
}
function renderSaveButton() {
return `<button id="sidebar-save-button" class="button is-success is-fullwidth" onclick="saveNode(prepareNodeData())">Dodaj AED</button>`;
}
// --------------------------------------------------------------
function prepareNodeData() {
let data = {};
// get coordinates
let markerPosition = marker.getLngLat();
data.lng = markerPosition.lng;
data.lat = markerPosition.lat;
// get additional tags
data.tags = {};
let formPhoneField = document.getElementById(formPhoneFieldId);
let formLocationField = document.getElementById(formLocationFieldId);
let formEmergencyPhoneField = document.getElementById(formEmergencyPhoneFieldId);
let formLocationEnField = document.getElementById(formLocationEnFieldId);
let formAccessField = document.getElementById(formAccessFieldId);
let formIndoorField = document.getElementById(formIndoorFieldId);
if (formIndoorField.selectedOptions[0].getAttribute('val'))
data.tags[formIndoorField.getAttribute('tag')] = formIndoorField.selectedOptions[0].getAttribute('val');
if (formPhoneField.value) data.tags[formPhoneField.getAttribute('tag')] = formPhoneField.value;
if (formLocationField.value) data.tags[formLocationField.getAttribute('tag')] = formLocationField.value;
if (formEmergencyPhoneField.value) data.tags[formEmergencyPhoneField.getAttribute('tag')] = formEmergencyPhoneField.value;
if (formLocationEnField.value) data.tags[formLocationEnField.getAttribute('tag')] = formLocationEnField.value;
if (formAccessField.selectedOptions[0].getAttribute('val'))
data.tags[formAccessField.getAttribute('tag')] = formAccessField.selectedOptions[0].getAttribute('val');
return data
}
function removeMarkerIfExists() {
if (marker !== null) {
marker.remove();
marker = null;
}
}
function showSidebar(properties) {
let sidebar = document.getElementById(sidebarDivId);
if (sidebar) {
sidebar.classList.remove('is-invisible');
if (properties.action === "showDetails") {
prepareSidebarShowingObjectInfo(properties.data);
removeMarkerIfExists();
} else if (properties.action === "addNode") {
prepareSidebarAddingNode(properties.data);
} else
console.log(`Unknown action: ${properties.action}.`);
} else
console.log('Sidebar not found.');
}
function hideSidebar() {
let sidebar = document.getElementById(sidebarDivId);
if (sidebar) {
sidebar.classList.add('is-invisible');
removeMarkerIfExists();
} else {
console.log('Sidebar not found.');
}
}
function prepareSidebarShowingObjectInfo(properties) {
sidebarHeader.classList = [];
sidebarHeader.classList.add(defineColor(properties.access));
sidebarCaption.innerHTML = `defibrylator AED ${defineAccessDescription(properties.access)}`;
sidebarContent.innerHTML = renderSidebarContent(properties);
sidebarLink.innerHTML = renderEditButton(properties.osm_id);
}
function prepareSidebarAddingNode(properties) {
sidebarHeader.classList = [];
sidebarHeader.classList.add(defineColor('default'));
sidebarCaption.innerHTML = 'Dodaj defibrylator';
sidebarContent.innerHTML = renderSidebarForm();
sidebarLink.innerHTML = renderSaveButton();
}
// --------------------------------------------------------------------------------------
// Bulma controls
document.addEventListener('DOMContentLoaded', () => {
// Get all "navbar-burger" elements
const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);
// Check if there are any navbar burgers
if ($navbarBurgers.length > 0) {
// Add a click event on each of them
$navbarBurgers.forEach(el => {
el.addEventListener('click', () => {
// Get the target from the "data-target" attribute
const target = el.dataset.target;
const $target = document.getElementById(target);
// Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
el.classList.toggle('is-active');
$target.classList.toggle('is-active');
});
});
}
});
// button listeners
sidebarButtonCloseIds.forEach(id => {
document.getElementById(id).addEventListener('click', hideSidebar);
});