diff --git a/templates/static/main.js b/templates/static/main.js index 4d269d3..c9d6bbc 100644 --- a/templates/static/main.js +++ b/templates/static/main.js @@ -11,10 +11,13 @@ const app = () => ({ supportedSalathLangs: ["tr", "de", "en", "ar"], userMinutes: 0, now: new Date(), - debug: location.hash === "#debug", + debug: hasDebugHashFlag(), async init() { - if (this.selectedLocation) { + const urlCoords = getURLCoords(); + if (urlCoords) { + await this.selectNearestLocation(urlCoords.latitude, urlCoords.longitude, {updateURL: false}); + } else if (this.selectedLocation) { this.searchQuery = this.formatLocationLabel(this.selectedLocation); await this.refreshPrayerTimes(); } @@ -23,16 +26,23 @@ const app = () => ({ this.now = new Date(); }, 500); - try { - const coords = await getUserLocation(); - await this.selectNearestLocation(coords.latitude, coords.longitude); - } catch (_error) { - // Ignore geolocation errors and rely on manual search. + if (!urlCoords) { + try { + const coords = await getUserLocation(); + await this.selectNearestLocation(coords.latitude, coords.longitude, {updateURL: true}); + } catch (_error) { + // Ignore geolocation errors and rely on manual search. + } } }, onHash() { - this.debug = location.hash === "#debug"; + this.debug = hasDebugHashFlag(); + + const urlCoords = getURLCoords(); + if (urlCoords) { + this.selectNearestLocation(urlCoords.latitude, urlCoords.longitude, {updateURL: false}); + } }, onSearchInput() { @@ -67,20 +77,23 @@ const app = () => ({ } }, - async selectNearestLocation(latitude, longitude) { + async selectNearestLocation(latitude, longitude, {updateURL = false} = {}) { const response = await fetchJSON(`/api/v1/diyanet/location?latitude=${encodeURIComponent(latitude)}&longitude=${encodeURIComponent(longitude)}`); const first = (response.locations ?? [])[0]; if (!first) { return; } - await this.selectLocation(first); + await this.selectLocation(first, {updateURL}); }, - async selectLocation(location) { + async selectLocation(location, {updateURL = true} = {}) { this.selectedLocation = location; this.searchQuery = this.formatLocationLabel(location); this.searchOpen = false; this.searchResults = []; + if (updateURL) { + setURLCoords(location.latitude, location.longitude); + } await this.refreshPrayerTimes(); }, @@ -308,3 +321,49 @@ function getUserLocation() { function normalizeLanguageTag(tag) { return String(tag).toLowerCase().split("-")[0]; } + +function parseCoordinate(value) { + const parsed = Number.parseFloat(value); + return Number.isFinite(parsed) ? parsed : null; +} + +function parseCoordsFromSearchParams(params) { + const latitude = parseCoordinate(params.get("latitude") ?? params.get("lat")); + const longitude = parseCoordinate(params.get("longitude") ?? params.get("lon")); + if (latitude === null || longitude === null) { + return null; + } + + return {latitude, longitude}; +} + +function getHashSearchParams() { + const hash = location.hash.startsWith("#") ? location.hash.slice(1) : location.hash; + if (hash === "") { + return new URLSearchParams(); + } + return new URLSearchParams(hash); +} + +function hasDebugHashFlag() { + const params = getHashSearchParams(); + return params.has("debug") || location.hash === "#debug"; +} + +function getURLCoords() { + const queryCoords = parseCoordsFromSearchParams(new URLSearchParams(location.search)); + if (queryCoords) { + return queryCoords; + } + + return parseCoordsFromSearchParams(getHashSearchParams()); +} + +function setURLCoords(latitude, longitude) { + const url = new URL(window.location.href); + url.searchParams.set("latitude", String(latitude)); + url.searchParams.set("longitude", String(longitude)); + url.searchParams.delete("lat"); + url.searchParams.delete("lon"); + window.history.replaceState({}, "", url.toString()); +}