116 lines
4 KiB
Svelte
116 lines
4 KiB
Svelte
<script lang="ts">
|
|
|
|
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";
|
|
|
|
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;
|
|
|
|
let searchContents: string = ""
|
|
export let triggerSearch: UIEventSource<any> = new UIEventSource<any>(undefined)
|
|
onDestroy(triggerSearch.addCallback(_ => {
|
|
console.log("TriggerRun pinged")
|
|
performSearch()
|
|
}))
|
|
|
|
let isRunning: boolean = false;
|
|
|
|
let inputElement: HTMLInputElement;
|
|
|
|
let feedback: string = undefined;
|
|
|
|
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)
|
|
}
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
}
|
|
searchContents = ""
|
|
dispatch("searchIsValid", false)
|
|
dispatch("searchCompleted")
|
|
} catch (e) {
|
|
console.error(e);
|
|
feedback = Translations.t.general.search.error.txt;
|
|
} finally {
|
|
isRunning = false;
|
|
}
|
|
}
|
|
|
|
</script>
|
|
|
|
<div class="flex normal-background rounded-full pl-2 justify-between">
|
|
<form class="w-full">
|
|
|
|
{#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}
|
|
|
|
bind:value={searchContents}
|
|
placeholder={Translations.t.general.search.search}>
|
|
{/if}
|
|
|
|
</form>
|
|
<div class="w-6 h-6 self-end" on:click={performSearch}>
|
|
<ToSvelte construct={Svg.search_svg}></ToSvelte>
|
|
</div>
|
|
</div>
|