From de74a5dc08de3ca6b5d5dc422e123f0eb0737aed Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Mon, 16 Jun 2025 02:33:37 +0200 Subject: [PATCH] Feature(pwa): add protocol handler --- scripts/generateLayouts.ts | 9 +++++- src/Logic/Actors/InitialMapPositioning.ts | 15 ++++++++++ src/Logic/State/SearchState.ts | 5 +++- src/Models/ThemeViewState/WithSearchState.ts | 31 ++++++++++---------- 4 files changed, 43 insertions(+), 17 deletions(-) diff --git a/scripts/generateLayouts.ts b/scripts/generateLayouts.ts index cb3446241..c7aa518ec 100644 --- a/scripts/generateLayouts.ts +++ b/scripts/generateLayouts.ts @@ -168,6 +168,7 @@ class GenerateLayouts extends Script { manifest: any whiteIcons: string[] }> { + const id = layout.id Translation.forcedLanguage = "en" const icons = [] @@ -228,7 +229,7 @@ class GenerateLayouts extends Script { const manifest = { name: ogTitle, short_name: ogTitle, - start_url: `${layout.id.toLowerCase()}.html`, + start_url: `${id.toLowerCase()}.html`, lang: "en", display: "standalone", background_color: "#fff", @@ -236,6 +237,12 @@ class GenerateLayouts extends Script { orientation: "portrait-primary, landscape-primary", icons: icons, categories: ["map", "navigation"], + "protocol_handlers": [ + { + "protocol": "geo", + "url": `/${id.toLowerCase()}.html?geouri=%s` + } + ] } return { manifest, diff --git a/src/Logic/Actors/InitialMapPositioning.ts b/src/Logic/Actors/InitialMapPositioning.ts index 8d62baf60..3a55f746a 100644 --- a/src/Logic/Actors/InitialMapPositioning.ts +++ b/src/Logic/Actors/InitialMapPositioning.ts @@ -66,6 +66,21 @@ export default class InitialMapPositioning { defaultLon, "The initial/current longitude of the app" ) + const geouri = QueryParameters.GetQueryParameter("geouri", undefined, "Alternative format to set lat/lon; but with an entire geouri instead. ") + console.log("geouri", geouri.data, !!geouri.data) + if (geouri.data) { + try { + const url = new URL("geo:"+decodeURIComponent(geouri.data)) + const [latN, lonN] = url.pathname.split(",").map(n => parseFloat(n)) + lat.set(latN) + lon.set(lonN) + if(url.searchParams.has("q")){ + QueryParameters.GetQueryParameter("q", undefined).set(url.searchParams.get("q")) + } + } catch (e) { + console.warn("Could not parse geoURI:", e) + } + } this.location = new UIEventSource({ lon: lon.data, lat: lat.data }) // Note: this syncs only in one direction diff --git a/src/Logic/State/SearchState.ts b/src/Logic/State/SearchState.ts index da90c4759..fd004dfa3 100644 --- a/src/Logic/State/SearchState.ts +++ b/src/Logic/State/SearchState.ts @@ -17,10 +17,11 @@ import { FeatureSource } from "../FeatureSource/FeatureSource" import { Feature } from "geojson" import OpenLocationCodeSearch from "../Search/OpenLocationCodeSearch" import { BBox } from "../BBox" +import { QueryParameters } from "../Web/QueryParameters" export default class SearchState { public readonly feedback: UIEventSource = new UIEventSource(undefined) - public readonly searchTerm: UIEventSource = new UIEventSource("") + public readonly searchTerm: UIEventSource public readonly searchIsFocused = new UIEventSource(false) public readonly suggestions: Store public readonly filterSuggestions: Store @@ -36,6 +37,8 @@ export default class SearchState { constructor(state: ThemeViewState) { this.state = state + this.searchTerm = QueryParameters.GetQueryParameter("q", "", "The term in the search field") + this.locationSearchers = [ new LocalElementSearch(state, 5), new CoordinateSearch(), diff --git a/src/Models/ThemeViewState/WithSearchState.ts b/src/Models/ThemeViewState/WithSearchState.ts index a9235c3ea..e0f8c085c 100644 --- a/src/Models/ThemeViewState/WithSearchState.ts +++ b/src/Models/ThemeViewState/WithSearchState.ts @@ -16,24 +16,25 @@ export class WithSearchState extends WithVisualFeedbackState { super(theme, mvtAvailableLayers) this.searchState = new SearchState(this) this.initHotkeysSearch() + this.displaySearchLayer() - { - // Register the search layer on the map + } - const source = this.searchState.locationResults - const flayer = this.layerState.filteredLayers.get("search") - this.featureProperties.trackFeatureSource(source) - const options: ShowDataLayerOptions & { layer: LayerConfig } = { - features: source, - doShowLayer: flayer.isDisplayed, - layer: flayer.layerDef, - metaTags: this.userRelatedState.preferencesAsTags, - onClick: (feature) => { - this.searchState.clickedOnMap(feature) - }, - } - new ShowDataLayer(this.map, options) + private displaySearchLayer() { + + const source = this.searchState.locationResults + const flayer = this.layerState.filteredLayers.get("search") + this.featureProperties.trackFeatureSource(source) + const options: ShowDataLayerOptions & { layer: LayerConfig } = { + features: source, + doShowLayer: flayer.isDisplayed, + layer: flayer.layerDef, + metaTags: this.userRelatedState.preferencesAsTags, + onClick: (feature) => { + this.searchState.clickedOnMap(feature) + }, } + new ShowDataLayer(this.map, options) } private initHotkeysSearch() {