]> git.openstreetmap.org Git - nominatim-ui.git/blob - src/pages/DetailsPage.svelte
put search,reverse,by-id links into top navbar (#75)
[nominatim-ui.git] / src / pages / DetailsPage.svelte
1 <script>
2   import { fetch_from_api, update_html_title } from '../lib/api_utils.js';
3   import { page } from '../lib/stores.js';
4
5   import {
6     osmLink, wikipediaLink, coverageType, isAdminBoundary,
7     formatAddressRank, formatKeywordToken
8   } from '../lib/helpers.js';
9   import Header from '../components/Header.svelte';
10   import MapIcon from '../components/MapIcon.svelte';
11   import SearchSectionDetails from '../components/SearchSectionDetails.svelte';
12   import DetailsOneRow from '../components/DetailsOneRow.svelte';
13   import DetailsLink from '../components/DetailsLink.svelte';
14   import Map from '../components/Map.svelte';
15
16   let aPlace;
17   let errorResponse;
18   let base_url = window.location.search;
19   let current_result;
20   let api_request_params;
21
22   function loaddata(search_params) {
23     api_request_params = {
24       place_id: search_params.get('place_id'),
25       osmtype: search_params.get('osmtype'),
26       osmid: search_params.get('osmid'),
27       class: search_params.get('class'),
28       keywords: search_params.get('keywords'),
29       addressdetails: 1,
30       hierarchy: (search_params.get('hierarchy') === '1' ? 1 : 0),
31       group_hierarchy: 1,
32       polygon_geojson: 1,
33       format: 'json'
34     };
35
36     if (api_request_params.place_id || (api_request_params.osmtype && api_request_params.osmid)) {
37
38       if (api_request_params.place_id) {
39         update_html_title('Details for ' + api_request_params.place_id);
40       } else {
41         update_html_title('Details for ' + api_request_params.osmtype + api_request_params.osmid);
42       }
43
44       fetch_from_api('details', api_request_params, function (data) {
45         window.scrollTo(0, 0);
46         if (data.error) {
47           errorResponse = data;
48           current_result = undefined;
49         } else {
50           aPlace = data;
51           errorResponse = undefined;
52           current_result = data;
53         }
54       });
55     } else {
56       aPlace = undefined;
57     }
58   }
59
60   $: {
61     let pageinfo = $page;
62     if (pageinfo.tab === 'details') {
63       loaddata(pageinfo.params);
64     }
65   }
66 </script>
67
68 <Header>
69   <SearchSectionDetails api_request_params={api_request_params}/>
70 </Header>
71 {#if errorResponse}
72   {errorResponse.error.message}
73 {/if}
74 {#if aPlace}
75   <div class="container">
76     <div class="row">
77       <div class="col-sm-10">
78         <h1>
79           {aPlace.localname}
80           <small><DetailsLink feature={aPlace}>link to this page</DetailsLink></small>
81         </h1>
82       </div>
83       <div class="col-sm-2 text-right">
84         <MapIcon aPlace={aPlace} />
85       </div>
86     </div>
87     <div class="row">
88       <div class="col-md-6">
89         <table id="locationdetails" class="table table-striped">
90           <tbody>
91             <tr>
92               <td>Name</td>
93               <td>
94                 {#each Object.keys(aPlace.names) as name}
95                   <div class="line">
96                     <span class="name">{aPlace.names[name]}</span> ({name})
97                   </div>
98                 {/each}
99               </td>
100             </tr>
101             <tr>
102               <td>Type</td>
103               <td>{aPlace.category}:{aPlace.type}</td>
104             </tr>
105             <tr>
106               <td>Last Updated</td>
107               <td>{aPlace.indexed_date}</td>
108             </tr>
109             {#if (isAdminBoundary(aPlace)) }
110             <tr>
111               <td>Admin Level</td>
112               <td>{aPlace.admin_level}</td>
113             </tr>
114             {/if}
115             <tr>
116               <td>Search Rank</td>
117               <td>{aPlace.rank_search}</td>
118             </tr>
119             <tr>
120               <td>Address Rank</td>
121               <td>{aPlace.rank_address} ({formatAddressRank(aPlace.rank_address)})</td>
122             </tr>
123             {#if aPlace.calculated_importance}
124               <tr>
125                 <td>Importance</td>
126                 <td>
127                   {aPlace.calculated_importance}
128                   {#if !aPlace.importance} (estimated){/if}
129                 </td>
130               </tr>
131             {/if}
132             <tr>
133               <td>Coverage</td>
134               <td>{coverageType(aPlace)}</td>
135             </tr>
136             <tr>
137               <td>Centre Point (lat,lon)</td>
138               <td>
139                 {aPlace.centroid.coordinates[1]},{aPlace.centroid.coordinates[0]}
140               </td>
141             </tr>
142             <tr>
143               <td>OSM</td>
144               <td>{@html osmLink(aPlace)}
145             </tr>
146             <tr>
147               <td>
148                 Place Id
149                 (<a href="https://nominatim.org/release-docs/develop/api/Output/#place_id-is-not-a-persistent-id">on this server</a>)
150               </td>
151               <td>{aPlace.place_id}</td>
152             </tr>
153             {#if aPlace.calculated_wikipedia}
154               <tr>
155                 <td>Wikipedia Calculated</td>
156                 <td>{@html wikipediaLink(aPlace)}</td>
157               </tr>
158             {/if}
159             <tr>
160               <td>Computed Postcode</td>
161               <td>{aPlace.calculated_postcode}</td>
162             </tr>
163             <tr>
164               <td>Address Tags</td>
165               <td>
166                 {#each Object.keys(aPlace.addresstags) as name}
167                   <div class="line">
168                     <span class="name">{aPlace.addresstags[name]}</span> ({name})
169                   </div>
170                 {/each}
171               </td>
172             </tr>
173             <tr>
174               <td>Extra Tags</td>
175               <td>
176                 {#each Object.keys(aPlace.extratags) as name}
177                   <div class="line">
178                     <span class="name">{aPlace.extratags[name]}</span> ({name})
179                   </div>
180                 {/each}
181               </td>
182             </tr>
183           </tbody>
184         </table>
185       </div>
186       <div class="col-md-6">
187         <div id="map-wrapper">
188           <Map {current_result} />
189         </div>
190       </div>
191     </div>
192     <div class="row">
193       <div class="col-md-12">
194         <h2>Address</h2>
195          <table id="address" class="table table-striped table-small">
196           <thead>
197             <tr>
198               <th>Local name</th>
199               <th>Type</th>
200               <th>OSM</th>
201               <th>Address rank</th>
202               <th>Admin level</th>
203               <th>Distance</th>
204               <th></th>
205             </tr>
206           </thead>
207           <tbody>
208             {#if aPlace.address}
209               {#each aPlace.address as addressLine}
210                 <DetailsOneRow addressLine={addressLine} bDistanceInMeters=false />
211               {/each}
212             {/if}
213
214             {#if aPlace.linked_places}
215               <tr class="all-columns"><td colspan="6"><h2>Linked Places</h2></td></tr>
216               {#each aPlace.linked_places as addressLine}
217                 <DetailsOneRow addressLine={addressLine} bDistanceInMeters=true />
218               {/each}
219             {/if}
220
221             <tr class="all-columns"><td colspan="6"><h2>Keywords</h2></td></tr>
222             {#if aPlace.keywords}
223               <tr class="all-columns"><td colspan="6"><h3>Name Keywords</h3></td></tr>
224               {#each aPlace.keywords.name as keyword}
225                 <tr>
226                   <td>{formatKeywordToken(keyword.token)}</td>
227                   {#if keyword.id}
228                     <td>word id: {keyword.id}</td>
229                   {/if}
230                 </tr>
231               {/each}
232
233               <tr class="all-columns"><td colspan="6"><h3>Address Keywords</h3></td></tr>
234               {#each aPlace.keywords.address as keyword}
235                 <tr>
236                   <td>{formatKeywordToken(keyword.token)}</td>
237                   {#if keyword.id}
238                     <td>word id: {keyword.id}</td>
239                   {/if}
240               </tr>
241               {/each}
242             {:else}
243               <tr>
244                 <td>
245                    <a class="btn btn-outline-secondary btn-sm"
246                     href="{base_url}&keywords=1">display keywords</a>
247                 </td>
248               </tr>
249             {/if}
250
251             <tr class="all-columns"><td colspan="6"><h2>Parent Of</h2></td></tr>
252             {#if aPlace.hierarchy}
253
254               {#each Object.keys(aPlace.hierarchy) as type}
255                 <tr class="all-columns"><td colspan="6"><h3>{type}</h3></td></tr>
256                 {#each aPlace.hierarchy[type] as line}
257                   <DetailsOneRow addressLine={line} bDistanceInMeters=true />
258                {/each}
259               {/each}
260
261               {#if Object.keys(aPlace.hierarchy) > 500}
262                 <p>There are more child objects which are not shown.</p>
263               {/if}
264             {:else}
265               <tr>
266                 <td>
267                    <a class="btn btn-outline-secondary btn-sm"
268                     href="{base_url}&hierarchy=1">display child places</a>
269                 </td>
270               </tr>
271             {/if}
272           </tbody>
273         </table>
274       </div>
275     </div>
276   </div>
277 {:else if (window.location.search === '')}
278   <!-- <DetailsIndex/> -->
279 {:else}
280   No such place found.
281 {/if}
282
283
284
285 <style>
286   h1 {
287     margin: 10px 0;
288     padding-left: 8px;
289   }
290
291   h1 small :global(a) {
292     font-size: 0.5em;
293     white-space: nowrap;
294   }
295
296   h2 {
297     font-size: 2em;
298     padding-left: 8px;
299     background-color: white;
300   }
301   h3 {
302     font-size: 1.5em;
303     padding-left: 8px;
304   }
305
306   tr.all-columns {
307     background-color: white !important; 
308     border: none;
309   }
310   tr.all-columns td {
311     border-top: none !important;
312     padding-left: 0 !important;
313   }
314
315   .table {
316     width: 100%;
317   }
318   .table td {
319     font-size: 0.9em;
320   }
321   .table>thead>tr>th, .table>tbody>tr>td {
322     padding: 2px 8px;
323   }
324   .name{
325     font-weight: bold;
326   }
327   #map-wrapper {
328     width:100%;
329     min-height: auto;
330     height:300px;
331     border: 1px solid #666;
332   }
333 </style>