const LINKS = [ { label: 'Google Maps', url: 'https://www.google.com/maps/search/?api=1&query={lat},{lon}', }, { label: 'Apple Maps', url: 'https://maps.apple.com/?q={lat},{lon}&t=m', }, { label: 'Default app', url: 'geo:{lat},{lon}', }, { label: 'OpenStreetMap', url: 'https://www.openstreetmap.org/?mlat={lat}&mlon={lon}&zoom=15&layers=M', }, ]; const content = document.getElementById('content'); route(); // TODO: route on hashChange function route() { const latLon = parseLatLon(location.hash.slice(1)); content.innerHTML = ''; if (!latLon) { document.title = 'Share a location'; content.append(createEl('h1', {}, ['not yet implemented'])); } else { document.title = 'Open location'; content.append(createEl('p', {}, ['Open in'])); const linkList = createEl('ul'); const [lat, lon] = latLon; for (const linkSpec of LINKS) { const url = linkSpec.url.replace('{lat}', lat).replace('{lon}', lon); const link = createEl('a', { href: url }, [linkSpec.label]); linkList.append(createEl('li', {}, [link])); } content.append(linkList); } } function parseLatLon(text) { if (text == '') { return null; } let [lat, lon] = text.split(','); lat = parseFloat(lat); lon = parseFloat(lon); if (Number.isNaN(lat) || Number.isNaN(lon)) { throw Error('failed to parse latitude or longitude'); } if (lat < -180 || lat > 180 || lon < -90 || lon > 90) { throw Error('latitude or longitude are out of range'); } return [lat, lon]; } function createEl(tag, attrs = {}, content = []) { const el = document.createElement(tag); for (const [name, value] of Object.entries(attrs)) { el.setAttribute(name, value); } for (const child of content) { el.append(child); } return el; }