Add a needs_commons parameter (default true) to both the API endpoint and the detail page. When needs_commons=false, look up Wikidata items by OSM relation ID (P402) via WDQS to return the most specific matching item even if it has no Wikimedia Commons category. Only activate this path when the matched item has no Commons category, so that locations with a Commons cat always get the same result regardless of the parameter. Remove the nearest-polygon fallback that was returning incorrect results for inland points in broad admin areas (e.g. returning Falmer for a point in Brighton). That fallback found the nearest polygon by boundary distance without requiring containment, so the pin would appear outside the polygon. The geosearch handles these cases correctly. Redesign the detail page: place name as heading, result card, collapsible API response and SPARQL query, improved OSM element cards with left-border highlight on the matched element, and a toggle button between modes. Redesign the index page: two-column layout with numbered steps and API documentation including the needs_commons parameter, Bootstrap form, and examples as a table. Closes #28 (Add support for returning Wikidata item instead of commons category) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
159 lines
5.4 KiB
HTML
159 lines
5.4 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Geocode to Commons{% endblock %}
|
|
|
|
{% block style %}
|
|
<style>
|
|
.step-number {
|
|
width: 1.75rem;
|
|
height: 1.75rem;
|
|
font-size: 0.8rem;
|
|
font-weight: 600;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.param-name {
|
|
font-family: monospace;
|
|
font-size: 0.95em;
|
|
}
|
|
|
|
.param-value {
|
|
font-family: monospace;
|
|
font-size: 0.85em;
|
|
background: #f8f9fa;
|
|
border: 1px solid #dee2e6;
|
|
border-radius: 3px;
|
|
padding: 0 4px;
|
|
}
|
|
|
|
.example-name {
|
|
min-width: 12rem;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-lg py-4">
|
|
|
|
<div class="row mb-4">
|
|
<div class="col-lg-8">
|
|
<h1 class="mb-1">Geocode to Commons Category</h1>
|
|
<p class="text-muted mb-3">Convert latitude/longitude to a Wikidata item and Wikimedia Commons category.</p>
|
|
|
|
<form class="d-flex gap-2 align-items-center mb-3" action="/">
|
|
<label for="q" class="text-nowrap text-muted small">Lat, Lon</label>
|
|
<input id="q" name="q" class="form-control form-control-sm" style="max-width:18rem" placeholder="e.g. 54.375, -2.999">
|
|
<button type="submit" class="btn btn-sm btn-primary">Go</button>
|
|
</form>
|
|
|
|
<p><a href="{{ url_for("map_page") }}">Interactive map ↗</a> — click any location to geocode it.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-4 mb-5">
|
|
<div class="col-lg-5">
|
|
<h5 class="mb-3">How it works</h5>
|
|
<div class="d-flex flex-column gap-2">
|
|
{% for step in [
|
|
("Find OSM polygons", "Query PostGIS for all polygons that contain the given point."),
|
|
("Sort by admin level", "Order polygons by admin_level descending — most specific first."),
|
|
("Check wikidata tag", "For each polygon, look for a <code>wikidata</code> tag and resolve the Commons category."),
|
|
("Check ref:gss tag", "If no wikidata tag, try <code>ref:gss</code> and look up the matching Wikidata item via WDQS."),
|
|
("Match by name", "Try finding a nearby Wikidata item with the same name using WDQS."),
|
|
("Return result", "Return the most specific Wikidata QID and Commons category found.")
|
|
] %}
|
|
<div class="d-flex gap-3 align-items-start">
|
|
<span class="step-number rounded-circle bg-secondary text-white d-flex align-items-center justify-content-center">{{ loop.index }}</span>
|
|
<div>
|
|
<div class="fw-semibold small">{{ step[0] }}</div>
|
|
<div class="text-muted small">{{ step[1] | safe }}</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-lg-7">
|
|
<h5 class="mb-3">API</h5>
|
|
<div class="card mb-3">
|
|
<div class="card-body">
|
|
<p class="mb-1"><code>GET /?lat=<lat>&lon=<lon></code></p>
|
|
<p class="text-muted small mb-3">Returns JSON with the Wikidata item and Commons category for the given coordinates.</p>
|
|
|
|
<table class="table table-sm small mb-0">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>Parameter</th>
|
|
<th>Values</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td class="param-name">lat</td>
|
|
<td class="text-muted">decimal degrees</td>
|
|
<td>Latitude</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="param-name">lon</td>
|
|
<td class="text-muted">decimal degrees</td>
|
|
<td>Longitude</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="param-name">needs_commons</td>
|
|
<td>
|
|
<span class="param-value">true</span> (default)<br>
|
|
<span class="param-value">false</span>
|
|
</td>
|
|
<td>
|
|
When <span class="param-value">true</span>, only returns a result if a Wikimedia Commons
|
|
category can be found. When <span class="param-value">false</span>, returns the best
|
|
matching Wikidata item even if it has no Commons category — matched by OSM relation or
|
|
way ID via the Wikidata Query Service.
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<h6 class="text-muted small mb-1">Example response</h6>
|
|
<pre class="bg-light rounded p-2 small">{
|
|
"wikidata": "Q184618",
|
|
"commons_cat": {
|
|
"title": "County Tipperary",
|
|
"url": "https://commons.wikimedia.org/wiki/Category:County_Tipperary"
|
|
},
|
|
"admin_level": 6,
|
|
"coords": { "lat": 52.41037, "lon": -7.84651 }
|
|
}</pre>
|
|
</div>
|
|
</div>
|
|
|
|
<h5 class="mb-3">Examples</h5>
|
|
<table class="table table-sm table-hover">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th class="example-name">Place</th>
|
|
<th>Coordinates</th>
|
|
<th colspan="2">Links</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for lat, lon, name in samples %}
|
|
<tr>
|
|
<td><a href="{{ url_for('detail_page', lat=lat, lon=lon) }}" class="text-decoration-none">{{ name }}</a></td>
|
|
<td class="text-muted small" style="font-family:monospace">{{ lat }}, {{ lon }}</td>
|
|
<td><a href="{{ url_for('detail_page', lat=lat, lon=lon) }}" class="small">detail</a></td>
|
|
<td><a href="{{ url_for('index', lat=lat, lon=lon) }}" class="small">API</a></td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
|
|
<p class="text-muted small mt-3">
|
|
Source code: <a href="https://git.4angle.com/edward/geocode">https://git.4angle.com/edward/geocode</a>
|
|
</p>
|
|
|
|
</div>
|
|
{% endblock %}
|