]> git.openstreetmap.org Git - nominatim-ui.git/blob - src/components/SearchBar.svelte
dca6161ad7b187a3924a70d593056ce04d30f277
[nominatim-ui.git] / src / components / SearchBar.svelte
1 <script>
2   import UrlSubmitForm from '../components/UrlSubmitForm.svelte';
3   import DetailsLink from '../components/DetailsLink.svelte';
4   import ReverseLink from '../components/ReverseLink.svelte';
5
6   import { map_store } from '../lib/stores.js';
7   import { get } from 'svelte/store';
8
9   export let bStructuredSearch = false;
10   export let api_request_params = {};
11   let sViewBox;
12   let lat;
13   let lon;
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     console.log('setting', e.target);
71     document.querySelector('input[name=bounded]').value = e.target.checked ? 1 : '';
72   }
73
74   function set_dedupe(e) {
75     document.querySelector('input[name=dedupe]').value = e.target.checked ? 1 : '';
76   }
77
78   function set_api_param(e) {
79     document.querySelector('input[name=' + e.target.dataset.apiParam + ']').value = e.target.value;
80   }
81 </script>
82
83 <div class="top-bar">
84   <ul class="nav nav-tabs">
85     <li class="nav-item">
86       <a class="nav-link" class:active={!bStructuredSearch} data-toggle="tab" href="#simple">simple</a>
87     </li>
88     <li class="nav-item">
89       <a class="nav-link" class:active={bStructuredSearch} data-toggle="tab" href="#structured">structured</a>
90     </li>
91     <div class="search-type-link">
92       <DetailsLink extra_classes="mr-2">search by id</DetailsLink>
93       <ReverseLink lat={lat} lon={lon}>reverse search</ReverseLink>
94     </div>
95   </ul>
96   <div class="tab-content p-2">
97     <div class="tab-pane" class:active={!bStructuredSearch} id="simple" role="tabpanel">
98       <UrlSubmitForm>
99         <input id="q"
100                name="q"
101                type="text"
102                class="form-control form-control-sm"
103                placeholder="Search"
104                value="{api_request_params.q || ''}" />
105
106         <div class="form-group search-button-group">
107           <button type="submit" class="btn btn-primary btn-sm mx-1">Search</button>
108           <input type="hidden" name="viewbox" value="{sViewBox || ''}" />
109           <input type="hidden" name="dedupe" value="{!api_request_params.dedupe ? '' : 1}" />
110           <input type="hidden" name="bounded" value="{api_request_params.bounded ? 1 : ''}" />
111           <input type="hidden" name="accept-language" value="{api_request_params['accept-language'] || ''}" />
112           <input type="hidden" name="countrycodes" value="{api_request_params.countrycodes || ''}" />
113           <input type="hidden" name="limit" value="{api_request_params.limit || ''}" />
114           <input type="hidden" name="polygon_threshold" value="{api_request_params.polygon_threshold || ''}" />
115         </div>
116       </UrlSubmitForm>
117     </div>
118     <div class="tab-pane" class:active={bStructuredSearch} id="structured" role="tabpanel">
119       <UrlSubmitForm>
120         <input name="street" type="text" class="form-control form-control-sm mr-1"
121                placeholder="House number/Street"
122                value="{api_request_params.street || ''}" />
123         <input name="city" type="text" class="form-control form-control-sm mr-1"
124                placeholder="City"
125                value="{api_request_params.city || ''}" />
126         <input id="county" name="county" type="text" class="form-control form-control-sm mr-1"
127                placeholder="County"
128                value="{api_request_params.county || ''}" />
129         <input name="state" type="text" class="form-control form-control-sm mr-1"
130                placeholder="State"
131                value="{api_request_params.state || ''}" />
132         <input name="country" type="text" class="form-control form-control-sm mr-1"
133                placeholder="Country"
134                value="{api_request_params.country || ''}" />
135         <input name="postalcode" type="text" class="form-control form-control-sm mr-1"
136                placeholder="Postal Code"
137                value="{api_request_params.postalcode || ''}" />
138
139         <div class="form-group search-button-group">
140           <button type="submit" class="btn btn-primary btn-sm mx-1">Search</button>
141           <input type="hidden" name="viewbox" value="{sViewBox || ''}" />
142           <input type="hidden" name="dedupe" value="{!api_request_params.dedupe ? '' : 1}" />
143           <input type="hidden" name="bounded" value="{api_request_params.bounded ? 1 : ''}" />
144           <input type="hidden" name="accept-language" value="{api_request_params['accept-language'] || ''}" />
145           <input type="hidden" name="countrycodes" value="{api_request_params.countrycodes || ''}" />
146           <input type="hidden" name="limit" value="{api_request_params.limit || ''}" />
147           <input type="hidden" name="polygon_threshold" value="{api_request_params.polygon_threshold || ''}" />
148         </div>
149       </UrlSubmitForm>
150     </div>
151     <!-- Additional options -->
152     <a href="#advanced" class="btn btn-outline-secondary btn-sm" data-toggle="collapse" data-target="#searchAdvancedOptions" role="button" aria-expanded="false" aria-controls="collapseAdvancedOptions">
153       Advanced options
154     </a>
155     <div class="collapse" id="searchAdvancedOptions">
156       <div id="searchAdvancedOptionsContent">
157           <div class="form-check form-check-inline">
158             <span><input type="checkbox" class="form-check-input api-param-setting"
159                    id="use_viewbox" checked={api_request_params.viewbox} on:change={reset_viewbox}>
160             <label class="form-check-label" for="use_viewbox">apply viewbox</label></span>
161             <span><input type="checkbox" class="form-check-input api-param-setting"
162                    id="option_bounded" checked={!!api_request_params.bounded} on:change={set_bounded}>
163             <label class="form-check-label" for="option_bounded">bounded to viewbox</label></span>
164             <span><input type="checkbox" class="form-check-input api-param-setting"
165                    id="option_dedupe" checked={!!api_request_params.dedupe} on:change={set_dedupe}>
166             <label class="form-check-label" for="option_dedupe">deduplicate results</label></span>
167           </div>
168           <div class="form-check form-check-inline">
169             <span><label class="form-check-label" for="option_limit">Maximum number of results: </label>
170             <input type="number" class="form-check-input api-param-setting" data-api-param="limit" id="option_limit" size="5" min="1" max="50" value="{api_request_params.limit || ''}" on:change={set_api_param}></span>
171             <span><label class="form-check-label" for="option_polygon_threashold">Polygon simplification: </label>
172             <input type="number" class="form-check-input api-param-setting" data-api-param="polygon_threshold" id="option_polygon_threshold" size="5" min="0.0" step="0.01" value="{api_request_params.polygon_threshold || ''}" on:change={set_api_param}></span>
173           </div>
174           <div class="form-check form-check-inline">
175             <span><label class="form-check-label" for="accept_lang">Languages: </label>
176             <input type="text" placeholder="e.g. en,zh-Hant" class="form-check-input api-param-setting" data-api-param="accept-language" id="accept_lang" size="15" value="{api_request_params['accept-language'] || ''}" on:change={set_api_param}></span>
177             <span><label class="form-check-label" for="option_ccode">Countries: </label>
178             <input type="text" placeholder="e.g. de,gb" class="form-check-input api-param-setting" data-api-param="countrycodes" id="option_ccode" size="15" value="{api_request_params.countrycodes || ''}" on:change={set_api_param}></span>
179           </div>
180        </div>
181     </div>
182   </div> <!-- /tab-content -->
183 </div> <!-- /top-bar -->
184
185 <style>
186   .top-bar {
187     width: 100%;
188     padding: 1em 15px;
189   }
190
191   .top-bar #q {
192     max-width: 500px;
193   }
194
195   .tab-content {
196     border: 1px solid #ddd;
197     border-top: none;
198     display: flex;
199     align-items: baseline
200   }
201
202   #q {
203     min-width: 500px;
204   }
205   @media (max-width: 850px) {
206     #q {
207       min-width: 400px;
208     }
209   }
210
211   label {
212     font-weight: normal;
213     margin-left: 0.4rem;
214     margin-right: 0.4rem;
215   }
216
217   #searchAdvancedOptionsContent {
218     display: flex;
219     flex-direction: column;
220     padding: 0 10px
221   }
222
223   #searchAdvancedOptionsContent label {
224     padding: 0 3px;
225   }
226
227   #searchAdvancedOptionsContent span {
228     padding: 4px 10px;
229   }
230
231   .search-type-link {
232     display: inline;
233     margin-right: 2em;
234     position: absolute;
235     right: 0
236   }
237
238   @media (max-width: 768px) {
239     .search-button-group {
240       display: inline;
241     }
242   }
243 </style>