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