"use strict"; let puzzeltocht = undefined; window.addEventListener("DOMContentLoaded", () => { puzzeltocht = new Puzzeltocht(); }); class Puzzeltocht { constructor() { this.joinScreen = new JoinScreen(); this.location = new LocationApi(); console.log("puzzeltocht initialised"); } startEvent(eventId, teamId) { this.eventId = this.joinScreen.eventId; this.teamId = teamId; document.getElementById("join").style.display = "none"; document.getElementById("mission").style.display = "block"; document.getElementById("questionMission").style.display = "none"; this.location.enable(p => this.updateLocation(p)) } updateLocation(position) { let l = document.getElementById("location"); if (position.accuracy() > 20) { l.innerText = "Onbetrouwbare locatie: " + position.string(); return; } l.innerText = position.string(); if (this.lastUpdate === undefined || Date.now() - this.lastUpdate > 5000) { Api.sendLocation(this.eventId, this.teamId, position) .then(m => this.updateMission(m)) .catch(e => this.onError(e)); this.lastUpdate = Date.now(); } } updateMission(m) { this.mission = m; document.getElementById("missionTitle").innerText = m.title + " (" + m.distanceToTarget + "m)"; document.getElementById("missionDescription").innerText = m.description; } onError(e) { this.location.disable(); let l = document.getElementById("location"); l.innerText = "Error!"; console.log(e); } } class JoinScreen { constructor() { Api.fetchEvents() .then(JoinScreen.showEvents) .catch(console.log); document.getElementById("joinForm").addEventListener("submit", (e) => this.joinEvent(e)); } joinEvent(submitEvent) { submitEvent.preventDefault(); let form = document.getElementById("joinForm"); this.eventId = form.elements["eventId"].value; let teamName = form.elements["teamName"].value; if (this.eventId === "" || teamName === "") { console.log("required form field empty"); return; } document.getElementById("joinButton").disabled = true; Api.join(this.eventId, teamName) .then(teamId => puzzeltocht.startEvent(this.eventId, teamId)) .catch(r => { console.log(r); document.getElementById("joinButton").disabled = false; }); } static showEvents(eventJson) { let events = document.getElementById("events"); events.innerHTML = ""; eventJson.forEach((e) => { events.innerHTML += ''; }); document.getElementById("joinButton").disabled = false; } } class Api { static fetchEvents() { return FetchJson.get("/api/event") } static join(eventId, teamName) { let url = "/api/event/" + encodeURIComponent(eventId) + "/team"; return FetchJson.post(url, teamName); } static sendLocation(eventId, teamId, position) { let body = { location: {latitude: position.lat(), longitude: position.lon()}, answer: null, }; let url = "/api/event/" + encodeURIComponent(eventId) + "/team/" + encodeURIComponent(teamId); return FetchJson.put(url, body); } } class FetchJson { static get(url) { return fetch(url, {method: "GET"}) .then(FetchJson.responseBody) } static post(url, body) { let options = { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify(body) }; return fetch(url, options) .then(FetchJson.responseBody) } static put(url, body) { let options = { method: "PUT", headers: {"Content-Type": "application/json"}, body: JSON.stringify(body) }; return fetch(url, options) .then(FetchJson.responseBody) } static responseBody(r) { if (!r.ok) { throw Error("HTTP " + r.status + " " + r.statusText + " " + r.url); } return r.json(); } } class Location { constructor(pos) { this.pos = pos; } accuracy() { return this.pos.coords.accuracy.toFixed(1) } age() { return Date.now() - this.pos.timestamp; } lat() { return this.pos.coords.latitude.toFixed(5); } lon() { return this.pos.coords.longitude.toFixed(5); } string() { return "(" + this.lat() + ", " + this.lon() + ")" + " +-" + this.accuracy() + "m, " + this.age() + "s geleden" } } class LocationApi { constructor() { if ("geolocation" in navigator) { console.log("Geolocation API available"); } else { console.log("Geolocation API not available"); document.getElementById("unsupported").style.display = "block"; } if (window.isSecureContext) { console.log("Secure context available"); } else { console.log("Secure context not available"); document.getElementById("unsupported").style.display = "block"; } } disable() { console.log("disabling geolocation watch " + this.watchId); navigator.geolocation.clearWatch(this.watchId); } enable(callback) { const geoOpts = { enableHighAccuracy: true, maximumAge: 10000, timeout: 9500 }; this.watchId = navigator.geolocation.watchPosition( (pos) => callback(new Location(pos)), (err) => console.log(err), geoOpts); } }