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