]> git.openstreetmap.org Git - nominatim-ui.git/blob - src/components/SearchSectionReverse.svelte
Svelte5: runes, events and @render context (#289)
[nominatim-ui.git] / src / components / SearchSectionReverse.svelte
1 <script>
2   import { onDestroy } from 'svelte';
3   import UrlSubmitForm from '../components/UrlSubmitForm.svelte';
4   import { SvelteURLSearchParams } from 'svelte/reactivity';
5
6   import { zoomLevels } from '../lib/helpers.js';
7   import { map_store, refresh_page } from '../lib/stores.js';
8
9   let { lat = '', lon = '', zoom = '', api_request_params = {} } = $props();
10
11   function gotoCoordinates(newlat, newlon, newzoom) {
12     if (newlat === null || newlon === null) return;
13
14     let params = new SvelteURLSearchParams();
15     params.set('lat', newlat);
16     params.set('lon', newlon);
17     params.set('zoom', newzoom || zoom);
18     refresh_page('reverse', params);
19   }
20
21   const unsubscribe = map_store.subscribe(map => {
22     if (map) {
23       map.on('click', (e) => {
24         let coords = e.latlng.wrap();
25         gotoCoordinates(coords.lat.toFixed(5), coords.lng.toFixed(5));
26       });
27     }
28   });
29
30   // common mistake is to copy&paste latitude and longitude into the 'lat' search box
31   function maybeSplitLatitude(e) {
32     var coords_split = e.target.value.split(/,|%2C/);
33     if (coords_split.length === 2) {
34       document.querySelector('input[name=lat]').value = L.Util.trim(coords_split[0]);
35       document.querySelector('input[name=lon]').value = L.Util.trim(coords_split[1]);
36     }
37   }
38
39   function set_api_param(e) {
40     document.querySelector('input[name=' + e.target.dataset.apiParam + ']').value = e.target.value;
41   }
42
43   function onSwitchCoords(e) {
44     e.preventDefault();
45     e.stopPropagation();
46     gotoCoordinates(lon, lat);
47   }
48
49   onDestroy(unsubscribe);
50 </script>
51
52 {#snippet content()}
53   <div class="col-auto">
54     <label for="reverse-lat">lat</label>
55   </div>
56   <div class="col-auto">
57     <input id="reverse-lat"
58            name="lat"
59            type="text"
60            class="form-control form-control-sm d-inline"
61            placeholder="latitude"
62            pattern="^-?\d+(\.\d+)?$"
63            bind:value={lat}
64            onchange={maybeSplitLatitude} />
65   </div>
66   <div class="col-auto">
67     <button id="switch-coords"
68        onclick={onSwitchCoords}
69        class="btn btn-outline-secondary btn-sm"
70        title="switch lat and lon">&lt;&gt;</button>
71   </div>
72   <div class="col-auto">
73     <label for="reverse-lon">lon</label>
74   </div>
75   <div class="col-auto">
76     <input id="reverse-lon"
77            name="lon"
78            type="text"
79            class="form-control form-control-sm"
80            placeholder="longitude"
81            pattern="^-?\d+(\.\d+)?$"
82            bind:value={lon} />
83   </div>
84   <div class="col-auto">
85     <label for="reverse-zoom">max zoom</label>
86   </div>
87   <div class="col-auto">
88     <select id="reverse-zoom" name="zoom" class="form-select form-select-sm" bind:value={zoom}>
89       <option value="">---</option>
90       {#each zoomLevels() as zoomTitle, i}
91         <option value="{i}">{i} - {zoomTitle}</option>
92       {/each}
93     </select>
94   </div>
95   <input type="hidden"
96          name="layer" value="{api_request_params.layer || ''}" />
97   <div class="col-auto">
98     <button type="submit" class="btn btn-primary btn-sm mx-1">Search</button>
99   </div>
100 {/snippet}
101 <UrlSubmitForm page="reverse" {content} />
102
103 <!-- Additional options -->
104 <details id="searchAdvancedOptions" class="mt-2">
105   <summary><small>Advanced options</small></summary>
106   <ul>
107     <li>
108       <label for="option_layer">Layer</label>
109       <input id="option_layer" name="layer" placeholder="e.g. address,poi,railway,natural,manmade"
110         value="{api_request_params.layer || ''}"
111         data-api-param="layer" onchange={set_api_param}
112         class="form-control form-control-sm d-inline w-auto api-param-setting">
113     </li>
114   </ul>
115 </details>
116
117 <style>
118   label {
119     font-size: 0.9rem;
120     margin-top: 0.3rem;
121   }
122
123   #switch-coords {
124     font-size: 0.6rem;
125     font-weight: bold;
126     cursor: pointer;
127     padding: 2px;
128     margin: 5px;
129   }
130
131   #searchAdvancedOptions ul {
132     list-style-type: none;
133     padding: 0;
134     font-size: 0.85rem;
135   }
136
137   #searchAdvancedOptions li {
138     display: inline-block;
139     padding: 4px 10px;
140     border-radius: 5px;
141     border: 1px dotted #ccc;
142     margin-right: 1em;
143   }
144
145   #searchAdvancedOptions label {
146     margin-right: 0.5em;
147   }
148
149   @media (max-width: 850px) {
150     #reverse-lon, #reverse-lat, #reverse-zoom {
151       width: 8em;
152     }
153   }
154 </style>