| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  | <script lang="ts"> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 15:44:54 +02:00
										 |  |  |     import {UIEventSource} from "../../Logic/UIEventSource"; | 
					
						
							|  |  |  |     import type {Feature} from "geojson"; | 
					
						
							|  |  |  |     import LayerConfig from "../../Models/ThemeConfig/LayerConfig"; | 
					
						
							|  |  |  |     import ToSvelte from "../Base/ToSvelte.svelte"; | 
					
						
							|  |  |  |     import Svg from "../../Svg.js"; | 
					
						
							|  |  |  |     import Translations from "../i18n/Translations"; | 
					
						
							|  |  |  |     import Loading from "../Base/Loading.svelte"; | 
					
						
							|  |  |  |     import Hotkeys from "../Base/Hotkeys"; | 
					
						
							|  |  |  |     import {Geocoding} from "../../Logic/Osm/Geocoding"; | 
					
						
							|  |  |  |     import {BBox} from "../../Logic/BBox"; | 
					
						
							|  |  |  |     import {GeoIndexedStoreForLayer} from "../../Logic/FeatureSource/Actors/GeoIndexedStore"; | 
					
						
							|  |  |  |     import {createEventDispatcher, onDestroy} from "svelte"; | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 15:44:54 +02:00
										 |  |  |     export let perLayer: ReadonlyMap<string, GeoIndexedStoreForLayer> | undefined = undefined; | 
					
						
							|  |  |  |     export let bounds: UIEventSource<BBox>; | 
					
						
							|  |  |  |     export let selectedElement: UIEventSource<Feature> | undefined = undefined; | 
					
						
							|  |  |  |     export let selectedLayer: UIEventSource<LayerConfig> | undefined = undefined; | 
					
						
							| 
									
										
										
										
											2023-06-07 22:45:42 +02:00
										 |  |  |      | 
					
						
							|  |  |  |     export let clearAfterView: boolean = true | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 15:44:54 +02:00
										 |  |  |     let searchContents: string = "" | 
					
						
							|  |  |  |     export let triggerSearch: UIEventSource<any> = new UIEventSource<any>(undefined) | 
					
						
							|  |  |  |     onDestroy(triggerSearch.addCallback(_ => { | 
					
						
							|  |  |  |         performSearch() | 
					
						
							|  |  |  |     })) | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 15:44:54 +02:00
										 |  |  |     let isRunning: boolean = false; | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 15:44:54 +02:00
										 |  |  |     let inputElement: HTMLInputElement; | 
					
						
							| 
									
										
										
										
											2023-04-14 02:42:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 15:44:54 +02:00
										 |  |  |     let feedback: string = undefined; | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 15:44:54 +02:00
										 |  |  |     Hotkeys.RegisterHotkey( | 
					
						
							|  |  |  |         {ctrl: "F"}, | 
					
						
							|  |  |  |         Translations.t.hotkeyDocumentation.selectSearch, | 
					
						
							|  |  |  |         () => { | 
					
						
							|  |  |  |             inputElement?.focus(); | 
					
						
							|  |  |  |             inputElement?.select(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     const dispatch = createEventDispatcher<{ searchCompleted, searchIsValid: boolean }>() | 
					
						
							|  |  |  |     $: { | 
					
						
							|  |  |  |         if (!searchContents?.trim()) { | 
					
						
							|  |  |  |             dispatch("searchIsValid", false) | 
					
						
							|  |  |  |         }else{ | 
					
						
							|  |  |  |             dispatch("searchIsValid", true) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-04-14 02:42:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 15:44:54 +02:00
										 |  |  |     async function performSearch() { | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |             isRunning = true; | 
					
						
							|  |  |  |             searchContents = searchContents?.trim() ?? ""; | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             if (searchContents === "") { | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             const result = await Geocoding.Search(searchContents, bounds.data); | 
					
						
							|  |  |  |             if (result.length == 0) { | 
					
						
							|  |  |  |                 feedback = Translations.t.general.search.nothing.txt; | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             const poi = result[0]; | 
					
						
							|  |  |  |             const [lat0, lat1, lon0, lon1] = poi.boundingbox; | 
					
						
							|  |  |  |             bounds.set(new BBox([[lon0, lat0], [lon1, lat1]]).pad(0.01)); | 
					
						
							|  |  |  |             if (perLayer !== undefined) { | 
					
						
							|  |  |  |                 const id = poi.osm_type + "/" + poi.osm_id; | 
					
						
							|  |  |  |                 const layers = Array.from(perLayer?.values() ?? []); | 
					
						
							|  |  |  |                 for (const layer of layers) { | 
					
						
							|  |  |  |                     const found = layer.features.data.find(f => f.properties.id === id); | 
					
						
							|  |  |  |                     selectedElement?.setData(found); | 
					
						
							|  |  |  |                     selectedLayer?.setData(layer.layer.layerDef); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-06-07 22:45:42 +02:00
										 |  |  |             if(clearAfterView){ | 
					
						
							|  |  |  |                 searchContents = "" | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-05-18 15:44:54 +02:00
										 |  |  |             dispatch("searchIsValid", false) | 
					
						
							|  |  |  |             dispatch("searchCompleted") | 
					
						
							|  |  |  |         } catch (e) { | 
					
						
							|  |  |  |             console.error(e); | 
					
						
							|  |  |  |             feedback = Translations.t.general.search.error.txt; | 
					
						
							|  |  |  |         } finally { | 
					
						
							|  |  |  |             isRunning = false; | 
					
						
							| 
									
										
										
										
											2023-04-14 02:42:57 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </script> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-24 02:27:55 +02:00
										 |  |  | <div class="flex normal-background rounded-full pl-2 justify-between"> | 
					
						
							| 
									
										
										
										
											2023-05-18 15:44:54 +02:00
										 |  |  |     <form class="w-full"> | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 15:44:54 +02:00
										 |  |  |         {#if isRunning} | 
					
						
							|  |  |  |             <Loading>{Translations.t.general.search.searching}</Loading> | 
					
						
							|  |  |  |         {:else if feedback !== undefined} | 
					
						
							|  |  |  |             <div class="alert" on:click={() => feedback = undefined}> | 
					
						
							|  |  |  |                 {feedback} | 
					
						
							|  |  |  |             </div> | 
					
						
							|  |  |  |         {:else } | 
					
						
							|  |  |  |             <input | 
					
						
							|  |  |  |                     type="search" | 
					
						
							|  |  |  |                     class="w-full" | 
					
						
							|  |  |  |                     bind:this={inputElement} | 
					
						
							|  |  |  |                     on:keypress={keypr => keypr.key === "Enter" ? performSearch() : undefined} | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 15:44:54 +02:00
										 |  |  |                     bind:value={searchContents} | 
					
						
							|  |  |  |                     placeholder={Translations.t.general.search.search}> | 
					
						
							|  |  |  |         {/if} | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 15:44:54 +02:00
										 |  |  |     </form> | 
					
						
							|  |  |  |     <div class="w-6 h-6 self-end" on:click={performSearch}> | 
					
						
							|  |  |  |         <ToSvelte construct={Svg.search_svg}></ToSvelte> | 
					
						
							|  |  |  |     </div> | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  | </div> |