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