]> git.openstreetmap.org Git - nominatim-ui.git/blob - src/components/SearchSection.svelte
Svelte5: runes, events and @render context (#289)
[nominatim-ui.git] / src / components / SearchSection.svelte
1 <script>
2   import UrlSubmitForm from '../components/UrlSubmitForm.svelte';
3
4   import { map_store } from '../lib/stores.js';
5   import { get } from 'svelte/store';
6
7   let { bStructuredSearch = false, api_request_params = {} } = $props();
8
9   let sViewBox = $state();
10
11   // lat,lon are later set in update_reverse_link()
12   let lat; // eslint-disable-line no-unused-vars
13   let lon; // eslint-disable-line no-unused-vars
14
15   function map_viewbox_as_string(map) {
16     var bounds = map.getBounds();
17     var west = bounds.getWest();
18     var east = bounds.getEast();
19
20     if ((east - west) >= 360) { // covers more than whole planet
21       west = map.getCenter().lng - 179.999;
22       east = map.getCenter().lng + 179.999;
23     }
24     east = L.latLng(77, east).wrap().lng;
25     west = L.latLng(77, west).wrap().lng;
26
27     return [
28       west.toFixed(5), // left
29       bounds.getNorth().toFixed(5), // top
30       east.toFixed(5), // right
31       bounds.getSouth().toFixed(5) // bottom
32     ].join(',');
33   }
34
35   function set_viewbox(map) {
36     let use_viewbox = document.getElementById('use_viewbox');
37     if (use_viewbox && use_viewbox.checked) {
38       sViewBox = map_viewbox_as_string(map);
39     } else {
40       sViewBox = '';
41     }
42   }
43
44   function update_reverse_link(map) {
45     let center_lat_lng = map.wrapLatLng(map.getCenter());
46     lat = center_lat_lng.lat.toFixed(5);
47     lon = center_lat_lng.lng.toFixed(5);
48   }
49
50   map_store.subscribe(map => {
51     if (!map) { return; }
52
53     map.on('move', function () {
54       set_viewbox(map);
55       update_reverse_link(map);
56     });
57
58     map.on('load', function () {
59       set_viewbox(map);
60       update_reverse_link(map);
61     });
62   });
63
64   function reset_viewbox() {
65     let map = get(map_store);
66     if (map) { set_viewbox(map); }
67   }
68
69   function set_bounded(e) {
70     document.querySelector('input[name=bounded]').value = e.target.checked ? 1 : '';
71   }
72
73   function set_dedupe(e) {
74     document.querySelector('input[name=dedupe]').value = e.target.checked ? 1 : 0;
75   }
76
77   function set_api_param(e) {
78     document.querySelector('input[name=' + e.target.dataset.apiParam + ']').value = e.target.value;
79   }
80 </script>
81
82 {#snippet submitButton()}
83 <div class="col-auto">
84   <button type="submit" class="btn btn-primary btn-sm">Search</button>
85   <input type="hidden"
86          name="viewbox" value="{sViewBox || ''}" />
87   <input type="hidden"
88          name="dedupe" value="{api_request_params.dedupe === 0 ? 0 : 1}" />
89   <input type="hidden"
90          name="bounded" value="{api_request_params.bounded ? 1 : ''}" />
91   <input type="hidden"
92          name="accept-language" value="{api_request_params['accept-language'] || ''}" />
93   <input type="hidden"
94          name="countrycodes" value="{api_request_params.countrycodes || ''}"
95                              pattern="^[a-zA-Z]{'{2}'}(,[a-zA-Z]{'{2}'})*$" />
96   <input type="hidden"
97          name="limit" value="{api_request_params.limit || ''}" />
98   <input type="hidden"
99          name="polygon_threshold" value="{api_request_params.polygon_threshold || ''}" />
100   <input type="hidden"
101          name="layer" value="{api_request_params.layer || ''}" />
102 </div>
103 {/snippet}
104
105 {#snippet simpleSearchForm()}
106 <div class="col-auto">
107   <input id="q"
108          name="q"
109          type="text"
110          class="form-control form-control-sm"
111          placeholder="Search"
112          value="{api_request_params.q || ''}" />
113 </div>
114 {@render submitButton()}
115 {/snippet}
116
117 {#snippet structuredSearchForm()}
118 <div class="col-auto">
119   <input name="street" type="text" class="form-control form-control-sm me-1"
120          placeholder="House number/Street"
121          value="{api_request_params.street || ''}" />
122 </div>
123 <div class="col-auto">
124   <input name="city" type="text" class="form-control form-control-sm me-1"
125          placeholder="City"
126          value="{api_request_params.city || ''}" />
127 </div>
128 <div class="col-auto">
129   <input id="county" name="county" type="text" class="form-control form-control-sm me-1"
130          placeholder="County"
131          value="{api_request_params.county || ''}" />
132 </div>
133 <div class="col-auto">
134   <input name="state" type="text" class="form-control form-control-sm me-1"
135          placeholder="State"
136          value="{api_request_params.state || ''}" />
137 </div>
138 <div class="col-auto">
139   <input name="country" type="text" class="form-control form-control-sm me-1"
140          placeholder="Country"
141          value="{api_request_params.country || ''}" />
142 </div>
143 <div class="col-auto">
144   <input name="postalcode" type="text" class="form-control form-control-sm me-1"
145          placeholder="Postal Code"
146          value="{api_request_params.postalcode || ''}" />
147 </div>
148 {@render submitButton()}
149 {/snippet}
150
151 <ul class="nav nav-tabs">
152   <li class="nav-item">
153     <a class="nav-link" class:active={!bStructuredSearch} data-bs-toggle="tab" href="#simple">
154       Simple
155     </a>
156   </li>
157   <li class="nav-item">
158     <a class="nav-link" class:active={bStructuredSearch} data-bs-toggle="tab" href="#structured">
159       Structured
160     </a>
161   </li>
162 </ul>
163
164 <div class="tab-content py-2">
165   <div class="tab-pane" class:active={!bStructuredSearch} id="simple" role="tabpanel">
166     <UrlSubmitForm page="search" content={simpleSearchForm} />
167   </div>
168   <div class="tab-pane" class:active={bStructuredSearch} id="structured" role="tabpanel">
169     <UrlSubmitForm page="search" content={structuredSearchForm} />
170   </div>
171 </div> <!-- /tab-content -->
172
173 <!-- Additional options -->
174 <details id="searchAdvancedOptions">
175   <summary><small>Advanced options</small></summary>
176   <ul>
177     <li>
178       <div class="form-check form-check-inline">
179         <label class="form-check-label" for="use_viewbox">apply viewbox</label>
180         <input type="checkbox" class="form-check-input api-param-setting"
181                id="use_viewbox" checked={api_request_params.viewbox} onchange={reset_viewbox}>
182       </div>
183     </li>
184
185     <li>
186       <div class="form-check form-check-inline">
187         <label class="form-check-label" for="option_bounded">bounded to viewbox</label>
188         <input type="checkbox" class="form-check-input api-param-setting"
189                id="option_bounded" checked={!!api_request_params.bounded} onchange={set_bounded}>
190       </div>
191     </li>
192
193     <li>
194       <div class="form-check form-check-inline">
195         <label class="form-check-label" for="option_dedupe">deduplicate results</label>
196         <input type="checkbox"
197                class="form-check-input api-param-setting"
198                id="option_dedupe"
199                checked={api_request_params.dedupe === 0 ? 0 : 1}
200                onchange={set_dedupe}>
201       </div>
202     </li>
203
204     <li>
205       <label for="option_limit">Maximum number of results</label>
206       <input type="number"
207              class="form-control form-control-sm d-inline w-auto api-param-setting"
208              data-api-param="limit" id="option_limit" min="1" max="50"
209              value="{api_request_params.limit || ''}"
210              onchange={set_api_param}>
211     </li>
212
213     <li>
214       <label for="option_polygon_threshold">Polygon simplification</label>
215       <input type="number"
216              class="form-control form-control-sm d-inline w-auto api-param-setting"
217              data-api-param="polygon_threshold" id="option_polygon_threshold"
218              min="0.0" max="1.0" step="0.001"
219              value="{api_request_params.polygon_threshold || ''}"
220              onchange={set_api_param}>
221     </li>
222
223     <li>
224       <label for="accept_lang">Languages</label>
225       <input type="text" placeholder="e.g. en,zh-Hant"
226              class="form-control form-control-sm d-inline w-auto api-param-setting"
227              data-api-param="accept-language" id="accept_lang" size="15"
228              value="{api_request_params['accept-language'] || ''}"
229              onchange={set_api_param}>
230     </li>
231
232     <li>
233       <label for="option_ccode">Country Codes</label>
234       <input type="text" placeholder="e.g. de,gb"
235             class="form-control form-control-sm d-inline w-auto api-param-setting"
236              data-api-param="countrycodes" id="option_ccode" size="15"
237              value="{api_request_params.countrycodes || ''}"
238              pattern="^[a-zA-Z]{'{2}'}(,[a-zA-Z]{'{2}'})*$"
239              onchange={set_api_param}>
240     </li>
241     <li>
242       <label for="option_layer">Layer</label>
243       <input id="option_layer" name="layer" placeholder="e.g. address,poi,railway,natural,manmade"
244         value="{api_request_params.layer || ''}"
245         data-api-param="layer" onchange={set_api_param}
246         class="form-control form-control-sm d-inline w-auto api-param-setting">
247     </li>
248   </ul>
249 </details>
250
251 <style>
252   .nav-tabs {
253     font-size: 0.8em;
254     margin-top: -1em;
255   }
256
257   .nav-link {
258     padding: 0.1rem 1rem;
259   }
260
261   #q {
262     width: 500px;
263     max-width: 100%;
264   }
265
266   #searchAdvancedOptions ul {
267     list-style-type: none;
268     padding: 0;
269     font-size: 0.85rem;
270   }
271
272   #searchAdvancedOptions li {
273     display: inline-block;
274     padding: 4px 10px;
275     border-radius: 5px;
276     border: 1px dotted #ccc;
277     margin-right: 1em;
278   }
279
280   #searchAdvancedOptions label {
281     margin-right: 0.5em;
282   }
283
284 </style>