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