add offline functionality by making this a PWA
- added favicons - added manifest - split javascript into main.js and elevators.js
34
elevators.js
|
@ -6,11 +6,6 @@ let geolocationPermission = false;
|
||||||
let geolocation = null;
|
let geolocation = null;
|
||||||
const openStations = new Set();
|
const openStations = new Set();
|
||||||
let sortByDistance = false;
|
let sortByDistance = false;
|
||||||
const version = '0.5.2'
|
|
||||||
const minorVersion = version.split('.').splice(0, 2).join('.');
|
|
||||||
const numberFormat = new Intl.NumberFormat('de-DE', {
|
|
||||||
maximumFractionDigits: 1
|
|
||||||
});
|
|
||||||
|
|
||||||
const substituteData = [
|
const substituteData = [
|
||||||
{
|
{
|
||||||
|
@ -87,14 +82,6 @@ const substituteData = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
Object.defineProperty(String.prototype, 'capitalize', {
|
|
||||||
value: function () {
|
|
||||||
return this.charAt(0).toUpperCase() + this.toLowerCase().slice(1);
|
|
||||||
},
|
|
||||||
enumerable: false
|
|
||||||
});
|
|
||||||
|
|
||||||
async function loadElevators() {
|
async function loadElevators() {
|
||||||
document.querySelector('#errorMessage').classList.add('hidden');
|
document.querySelector('#errorMessage').classList.add('hidden');
|
||||||
const res = await fetch('https://www.hvv.de/elevators', {
|
const res = await fetch('https://www.hvv.de/elevators', {
|
||||||
|
@ -203,12 +190,6 @@ async function loadElevators() {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const dateTimeStyle = new Intl.DateTimeFormat('de-DE', {
|
|
||||||
dateStyle: 'medium',
|
|
||||||
timeStyle: 'medium',
|
|
||||||
timeZone: 'Europe/Berlin',
|
|
||||||
})
|
|
||||||
|
|
||||||
async function loadOsmData() {
|
async function loadOsmData() {
|
||||||
const nodeIdList = [];
|
const nodeIdList = [];
|
||||||
for (const station of internalData.stations) {
|
for (const station of internalData.stations) {
|
||||||
|
@ -726,21 +707,6 @@ document.querySelectorAll('button.typeChip').forEach(e => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
function openDialog(selector) {
|
|
||||||
document.querySelector('body').classList.add('has-dialog')
|
|
||||||
document.querySelector('#dialog_layer').classList.add('active')
|
|
||||||
document.querySelector(selector).classList.remove('hidden')
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeDialog(selector) {
|
|
||||||
document.querySelector('body').classList.remove('has-dialog')
|
|
||||||
document.querySelector('#dialog_layer').classList.remove('active')
|
|
||||||
document.querySelector(selector).classList.add('hidden')
|
|
||||||
}
|
|
||||||
|
|
||||||
// set version
|
|
||||||
document.querySelector('#version').innerHTML = `v${version}`;
|
|
||||||
|
|
||||||
// data api version check
|
// data api version check
|
||||||
const check_internal = JSON.parse(localStorage.getItem("internal_data"));
|
const check_internal = JSON.parse(localStorage.getItem("internal_data"));
|
||||||
const check_osm = JSON.parse(localStorage.getItem("osm_data"));
|
const check_osm = JSON.parse(localStorage.getItem("osm_data"));
|
||||||
|
|
BIN
icons/192.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
icons/512-maskable.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
icons/512-transparent.png
Normal file
After Width: | Height: | Size: 7.7 KiB |
BIN
icons/512.png
Normal file
After Width: | Height: | Size: 9.6 KiB |
24
icons/favicon-maskable.svg
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="100mm"
|
||||||
|
height="100mm"
|
||||||
|
viewBox="0 0 100 100"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
xml:space="preserve"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||||
|
id="defs1" /><g
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-104.49603,0.25552651)"><rect
|
||||||
|
style="fill:#65a30d;fill-opacity:1;stroke:none;stroke-width:0.499507;stroke-linejoin:round;paint-order:markers stroke fill"
|
||||||
|
id="rect1-1"
|
||||||
|
width="100"
|
||||||
|
height="100.00012"
|
||||||
|
x="104.49603"
|
||||||
|
y="-0.25558716" /><path
|
||||||
|
d="m 142.75747,64.972903 h 7.61422 V 54.820616 h 2.53804 V 48.47544 q 0,-2.093907 -1.49109,-3.585027 -1.49109,-1.49111 -3.58499,-1.49111 h -2.53813 q -2.0939,0 -3.58499,1.49111 -1.49109,1.49112 -1.49109,3.585027 v 6.345176 h 2.53803 z m 3.80716,-24.111679 q 1.33243,0 2.25246,-0.920037 0.91995,-0.920037 0.91995,-2.252542 0,-1.332485 -0.91995,-2.252532 -0.91993,-0.920036 -2.25246,-0.920036 -1.33252,0 -2.25256,0.920036 -0.91994,0.920037 -0.91994,2.252532 0,1.332495 0.91994,2.252542 0.91994,0.920037 2.25256,0.920037 z m 9.96184,6.345176 h 12.6904 l -6.3452,-10.152274 z m 6.3452,15.228432 6.3452,-10.152284 h -12.6904 z m -25.38069,12.309636 q -3.36291,0 -5.67889,-2.315986 -2.31606,-2.315986 -2.31606,-5.678936 V 32.7394 q 0,-3.362945 2.31606,-5.678933 2.31598,-2.315988 5.67889,-2.315988 h 34.01019 q 3.36292,0 5.67889,2.315988 2.31597,2.315988 2.31597,5.678933 v 34.010146 q 0,3.36295 -2.31597,5.678936 -2.31597,2.315986 -5.67889,2.315986 z"
|
||||||
|
id="path1-3-2"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke-width:0.0634518" /></g></svg>
|
After Width: | Height: | Size: 1.7 KiB |
18
icons/favicon-transparent.svg
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="100mm"
|
||||||
|
height="100mm"
|
||||||
|
viewBox="0 0 100 100"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
xml:space="preserve"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||||
|
id="defs1" /><g
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-214.49603)"><path
|
||||||
|
d="m 248.06205,71.319802 h 10.65991 V 57.1066 h 3.55325 v -8.883247 q 0,-2.931469 -2.08753,-5.019037 -2.08752,-2.087555 -5.01898,-2.087555 h -3.55339 q -2.93146,0 -5.01898,2.087555 -2.08753,2.087568 -2.08753,5.019037 V 57.1066 h 3.55325 z m 5.33002,-33.756351 q 1.8654,0 3.15345,-1.288052 1.28792,-1.288051 1.28792,-3.153558 0,-1.865479 -1.28792,-3.153545 -1.28791,-1.288051 -3.15345,-1.288051 -1.86553,0 -3.15358,1.288051 -1.28792,1.288052 -1.28792,3.153545 0,1.865493 1.28792,3.153558 1.28791,1.288052 3.15358,1.288052 z m 13.94658,8.883247 h 17.76655 l -8.88328,-14.213184 z m 8.88327,21.319804 8.88328,-14.213198 h -17.76655 z m -35.53296,17.23349 q -4.70808,0 -7.95044,-3.24238 -3.24249,-3.24238 -3.24249,-7.95051 V 26.192898 q 0,-4.708124 3.24249,-7.950507 3.24236,-3.242383 7.95044,-3.242383 h 47.61427 q 4.70809,0 7.95044,3.242383 3.24236,3.242383 3.24236,7.950507 v 47.614204 q 0,4.70813 -3.24236,7.95051 -3.24235,3.24238 -7.95044,3.24238 z"
|
||||||
|
id="path1-3"
|
||||||
|
style="fill:#000000;fill-opacity:1;stroke-width:0.0888325" /></g></svg>
|
After Width: | Height: | Size: 1.4 KiB |
BIN
icons/favicon.ico
Normal file
After Width: | Height: | Size: 2.7 KiB |
23
icons/favicon.svg
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="100mm"
|
||||||
|
height="100mm"
|
||||||
|
viewBox="0 0 100 100"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
xml:space="preserve"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||||
|
id="defs1" /><g
|
||||||
|
id="layer1"><rect
|
||||||
|
style="opacity:1;fill:#65a30d;fill-opacity:1;stroke:none;stroke-width:0.499507;stroke-linejoin:round;paint-order:markers stroke fill"
|
||||||
|
id="rect1"
|
||||||
|
width="100"
|
||||||
|
height="100.00012"
|
||||||
|
x="-3.3306691e-15"
|
||||||
|
y="-6.1035156e-05" /><path
|
||||||
|
d="M 33.56602,71.319802 H 44.22593 V 57.1066 h 3.55325 v -8.883247 q 0,-2.931469 -2.08753,-5.019037 -2.08752,-2.087555 -5.01898,-2.087555 h -3.55339 q -2.93146,0 -5.01898,2.087555 -2.08753,2.087568 -2.08753,5.019037 V 57.1066 h 3.55325 z m 5.33002,-33.756351 q 1.8654,0 3.15345,-1.288052 1.28792,-1.288051 1.28792,-3.153558 0,-1.865479 -1.28792,-3.153545 -1.28791,-1.288051 -3.15345,-1.288051 -1.86553,0 -3.15358,1.288051 -1.28792,1.288052 -1.28792,3.153545 0,1.865493 1.28792,3.153558 1.28791,1.288052 3.15358,1.288052 z m 13.94658,8.883247 H 70.60917 L 61.72589,32.233514 Z m 8.88327,21.319804 8.88328,-14.213198 H 52.84262 Z m -35.53296,17.23349 q -4.70808,0 -7.95044,-3.24238 Q 15,78.515232 15,73.807102 V 26.192898 q 0,-4.708124 3.24249,-7.950507 3.24236,-3.242383 7.95044,-3.242383 H 73.8072 q 4.70809,0 7.95044,3.242383 Q 85,21.484774 85,26.192898 v 47.614204 q 0,4.70813 -3.24236,7.95051 -3.24235,3.24238 -7.95044,3.24238 z"
|
||||||
|
id="path1-3-7"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke-width:0.0888325" /></g></svg>
|
After Width: | Height: | Size: 1.6 KiB |
BIN
images/screenshot-desktop.png
Normal file
After Width: | Height: | Size: 101 KiB |
BIN
images/screenshot-mobile.png
Normal file
After Width: | Height: | Size: 78 KiB |
|
@ -6,6 +6,11 @@
|
||||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
<link href="style.css" rel="stylesheet">
|
<link href="style.css" rel="stylesheet">
|
||||||
|
<link rel="icon" type="image/png" sizes="512" href="/icons/512.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="192" href="/icons/192.png">
|
||||||
|
<link rel="shortcut icon" href="/icons/favicon.svg">
|
||||||
|
<link rel="manifest" href="/manifest.json">
|
||||||
|
<link rel="mask-icon" href="/icons/favicon-transparent.svg" color="#047857">
|
||||||
<title>Barrierefreie Aufzugs-Liste</title>
|
<title>Barrierefreie Aufzugs-Liste</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -88,6 +93,7 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<script type="text/javascript" src="main.js"></script>
|
||||||
<script type="text/javascript" src="elevators.js"></script>
|
<script type="text/javascript" src="elevators.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
41
main.js
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
const version = '0.6.0'
|
||||||
|
const minorVersion = version.split('.').splice(0, 2).join('.');
|
||||||
|
const numberFormat = new Intl.NumberFormat('de-DE', {
|
||||||
|
maximumFractionDigits: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(String.prototype, 'capitalize', {
|
||||||
|
value: function () {
|
||||||
|
return this.charAt(0).toUpperCase() + this.toLowerCase().slice(1);
|
||||||
|
},
|
||||||
|
enumerable: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const dateTimeStyle = new Intl.DateTimeFormat('de-DE', {
|
||||||
|
dateStyle: 'medium',
|
||||||
|
timeStyle: 'medium',
|
||||||
|
timeZone: 'Europe/Berlin',
|
||||||
|
})
|
||||||
|
|
||||||
|
// set version
|
||||||
|
document.querySelector('#version').innerHTML = `v${version}`;
|
||||||
|
|
||||||
|
|
||||||
|
function openDialog(selector) {
|
||||||
|
document.querySelector('body').classList.add('has-dialog')
|
||||||
|
document.querySelector('#dialog_layer').classList.add('active')
|
||||||
|
document.querySelector(selector).classList.remove('hidden')
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeDialog(selector) {
|
||||||
|
document.querySelector('body').classList.remove('has-dialog')
|
||||||
|
document.querySelector('#dialog_layer').classList.remove('active')
|
||||||
|
document.querySelector(selector).classList.add('hidden')
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("serviceWorker" in navigator) {
|
||||||
|
console.log('installing sw');
|
||||||
|
navigator.serviceWorker.register("/sw.js").then((registration) => {
|
||||||
|
console.log('done installing sw');
|
||||||
|
});
|
||||||
|
}
|
49
manifest.json
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
{
|
||||||
|
"name": "hvvstuhl.de",
|
||||||
|
"short_name": "hvvstuhl",
|
||||||
|
"start_url": ".",
|
||||||
|
"display": "standalone",
|
||||||
|
"background_color": "#030712",
|
||||||
|
"theme_color": "#047857",
|
||||||
|
"description": "Barrierefreie Aufzugs-Liste",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "/icons/192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icons/512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icons/512-maskable.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icons/512-transparent.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "monochrome"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"screenshots" : [
|
||||||
|
{
|
||||||
|
"src": "images/screenshot-mobile.png",
|
||||||
|
"sizes": "430x900",
|
||||||
|
"type": "image/png",
|
||||||
|
"form_factor": "narrow",
|
||||||
|
"label": "Stationsliste"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "images/screenshot-desktop.png",
|
||||||
|
"sizes": "1280x720",
|
||||||
|
"type": "image/png",
|
||||||
|
"form_factor": "wide",
|
||||||
|
"label": "Stationsliste"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
96
sw.js
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
const version = '0.6.0'
|
||||||
|
const consolePrefix = `[SW v${version}] `
|
||||||
|
|
||||||
|
const cacheName = `hvvstuhl-${version}`;
|
||||||
|
const contentToCache = [
|
||||||
|
'/',
|
||||||
|
'/index.html',
|
||||||
|
'/about.html',
|
||||||
|
'/main.js',
|
||||||
|
'/elevators.js',
|
||||||
|
'/style.css',
|
||||||
|
'/icons/192.png',
|
||||||
|
'/icons/512.png',
|
||||||
|
'/icons/512-maskable.png',
|
||||||
|
'/icons/512-transparent.png',
|
||||||
|
'/icons/favicon.ico',
|
||||||
|
'/icons/favicon.svg',
|
||||||
|
'/icons/favicon-maskable.svg',
|
||||||
|
'/icons/favicon-transparent.svg',
|
||||||
|
'/md_icons/bicycle.svg',
|
||||||
|
'/md_icons/braille.svg',
|
||||||
|
'/md_icons/door_sliding.svg',
|
||||||
|
'/md_icons/elevator.svg',
|
||||||
|
'/md_icons/elevator-slash.svg',
|
||||||
|
'/md_icons/fit_width.svg',
|
||||||
|
'/md_icons/height.svg',
|
||||||
|
'/md_icons/info.svg',
|
||||||
|
'/md_icons/load.svg',
|
||||||
|
'/md_icons/location.svg',
|
||||||
|
'/md_icons/location-searching.svg',
|
||||||
|
'/md_icons/speaker.svg',
|
||||||
|
'/md_icons/up-down.svg',
|
||||||
|
'/md_icons/wheelchair.svg',
|
||||||
|
'/md_icons/width.svg',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Service worker Install: Cache all files
|
||||||
|
self.addEventListener("install", (e) => {
|
||||||
|
console.log("[Service Worker] Wird installiert....");
|
||||||
|
e.waitUntil(
|
||||||
|
(async () => {
|
||||||
|
const cache = await caches.open(cacheName);
|
||||||
|
console.log("[Service Worker] Cache wird aufgebaut...");
|
||||||
|
await cache.addAll(contentToCache);
|
||||||
|
console.log("[Service Worker] FERTIG");
|
||||||
|
})(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// delete old caches
|
||||||
|
const deleteCache = async (key) => {
|
||||||
|
await caches.delete(key);
|
||||||
|
};
|
||||||
|
const deleteOldCaches = async () => {
|
||||||
|
const keyList = await caches.keys();
|
||||||
|
const cachesToDelete = keyList.filter((key) => key !== cacheName);
|
||||||
|
await Promise.all(cachesToDelete.map(deleteCache));
|
||||||
|
};
|
||||||
|
self.addEventListener("activate", (event) => {
|
||||||
|
event.waitUntil(
|
||||||
|
(async () => {
|
||||||
|
await deleteOldCaches()
|
||||||
|
await clients.claim();
|
||||||
|
})(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Respond with data from cache when offline
|
||||||
|
self.addEventListener("fetch", (e) => {
|
||||||
|
e.respondWith(
|
||||||
|
(async () => {
|
||||||
|
const path = new URL(e.request.url).pathname
|
||||||
|
|
||||||
|
if(contentToCache.includes(path)){
|
||||||
|
console.log(`${consolePrefix}Anfrage: ${path}`);
|
||||||
|
|
||||||
|
const r = await caches.match(e.request);
|
||||||
|
if (r) {
|
||||||
|
console.log(`${consolePrefix} Im Cache gefunden.`);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
const response = await fetch(e.request);
|
||||||
|
const cache = await caches.open(cacheName);
|
||||||
|
console.log(`${consolePrefix} Nicht gefunden. Aktualisiere Cache: ${path}`);
|
||||||
|
await cache.put(e.request, response.clone());
|
||||||
|
return response;
|
||||||
|
}else{
|
||||||
|
console.log(`${consolePrefix}Anfrage übersprungen: ${e.request.url}`);
|
||||||
|
return await fetch(e.request);
|
||||||
|
}
|
||||||
|
})(),
|
||||||
|
);
|
||||||
|
});
|