"use strict"; let puzzeltocht = undefined; window.addEventListener("DOMContentLoaded", () => { puzzeltocht = new Puzzeltocht(); }); class Puzzeltocht { constructor() { this.joinScreen = new JoinScreen(); this.joinScreen.setJoinListener((e, t) => this.start(e, t)); this.missionScreen = new MissionScreen(); this.missionScreen.setAnswerListener(e => this.answer(e)); this.location = new LocationApi(); console.log("puzzeltocht initialised"); } start(eventId, teamId) { this.eventId = this.joinScreen.eventId; this.teamId = teamId; document.getElementById("join").style.display = "none"; document.getElementById("questionMission").style.display = "none"; document.getElementById("mission").style.display = "block"; this.location.enable(p => this.updateLocation(p)) } answer(a) { this.lastUpdate = Date.now(); Api.sendUpdate(this.eventId, this.teamId, this.position, a) .then(m => this.missionScreen.update(m)) .catch(e => this.onError(e)); } updateLocation(position) { let l = document.getElementById("location"); if (position.accuracy() > 20) { l.innerText = "Onbetrouwbare locatie: " + position.string(); return; } this.position = position; l.innerText = position.string(); if (this.lastUpdate === undefined || Date.now() - this.lastUpdate > 5000) { Api.sendUpdate(this.eventId, this.teamId, position) .then(m => this.missionScreen.update(m)) .catch(e => this.onError(e)); this.lastUpdate = Date.now(); } } onError(e) { this.location.disable(); let l = document.getElementById("location"); l.innerText = "Error!"; console.log(e); } } class MissionScreen { setAnswerListener(callback) { document.getElementById("answerForm").addEventListener("submit", (e) => MissionScreen.answer(e, callback)); } static answer(submitEvent, callback) { submitEvent.preventDefault(); let form = document.getElementById("answerForm"); let answer = form.elements["questionAnswer"].value; form.elements["questionAnswer"].value = ""; document.getElementById("answerButton").disabled = true; callback(answer); } update(m) { this.mission = m; document.getElementById("missionTitle").innerText = m.title + " (" + m.distanceToTarget + "m)"; document.getElementById("missionDescription").innerText = m.description; if (m.type === "QUESTION") { document.getElementById("questionMission").style.display = "block"; document.getElementById("answerButton").disabled = false; } else { document.getElementById("questionMission").style.display = "none"; } } } class JoinScreen { constructor() { Api.fetchEvents() .then(JoinScreen.showEvents) .catch(console.log); } setJoinListener(callback) { document.getElementById("joinForm").addEventListener("submit", (e) => this.joinEvent(e, callback)); } joinEvent(submitEvent, callback) { submitEvent.preventDefault(); let form = document.getElementById("joinForm"); let teamName = form.elements["teamName"].value; this.eventId = form.elements["eventId"].value; if (this.eventId === "" || teamName === "") { console.log("required form field empty"); return; } document.getElementById("joinButton").disabled = true; Api.join(this.eventId, teamName) .then(teamId => callback(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 sendUpdate(eventId, teamId, position, answer = null) { let body = { location: {latitude: position.lat(), longitude: position.lon()}, answer: answer, }; 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); } }