Fix the hero's "Use my location" doing nothing (#179)
The button was dead on plain HTTP and failed silently everywhere.
Browsers only expose geolocation on secure origins, but `navigator.geolocation`
still EXISTS on http:// — getCurrentPosition just fails with a permission error
("Only secure origins are allowed"). The guard was `if (!navigator.geolocation)
return;`, which passes on http://, so the call went ahead, errored, and landed
in an empty error callback. Nothing happened at all.
`make lan-run` serves plain HTTP on 0.0.0.0:8137 so phones can reach it, so the
button could never work in the normal dev-and-phone workflow, and gave no hint
why. It would have worked on thermograph.org, which is HTTPS.
- Gate on `window.isSecureContext`, not just the API's presence. Where the
browser will refuse, hide the locate button and promote "Pick on the map" to
primary rather than offering a control that cannot work.
- Report failures: a declined prompt, a timeout, and an unavailable fix each get
their own message in an aria-live slot. A silent failure is indistinguishable
from a broken button, which is exactly how this went unnoticed.
- Show a "Locating…" state while the fix is pending; it can take seconds.
To exercise geolocation against the LAN dev server, serve it over TLS:
`make lan-run TLS=1` (self-signed cert into certs/).
Verified by driving the button in a real browser across all three cases:
insecure origin (button hidden, map promoted), permission granted (hero
re-points at the located place), permission denied (message shown, button
restored).
This commit is contained in:
parent
3a66682322
commit
aab42610ef
2 changed files with 13 additions and 0 deletions
|
|
@ -62,9 +62,12 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
<div class="hero-actions">
|
||||
{# app.js hides the locate button outside a secure context, where the
|
||||
browser refuses geolocation and it could only ever fail. #}
|
||||
<button type="button" id="hero-locate" class="btn-primary">Use my location</button>
|
||||
<button type="button" id="hero-pick" class="btn-ghost">Pick on the map</button>
|
||||
</div>
|
||||
<p class="hero-locate-msg" id="hero-locate-msg" role="status" aria-live="polite" hidden></p>
|
||||
<p class="hero-jump"><a href="#panel">See your week ↓</a></p>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -124,6 +124,16 @@ def test_homepage_is_complete_without_js(client, no_feed):
|
|||
assert 'p class="site-name"' in html
|
||||
|
||||
|
||||
def test_hero_locate_has_a_status_slot(client, no_feed):
|
||||
"""The locate button needs somewhere to report a declined prompt or a
|
||||
timeout. Without it the control fails silently, which is how it shipped
|
||||
broken: navigator.geolocation exists on plain http:// but always errors."""
|
||||
html = client.get(f"{B}/").text
|
||||
assert 'id="hero-locate"' in html
|
||||
assert 'id="hero-locate-msg"' in html
|
||||
assert 'aria-live="polite"' in html
|
||||
|
||||
|
||||
def test_city_chips_all_resolve(client, no_feed):
|
||||
"""Every homepage chip must be a real, routable city — a stale slug would
|
||||
render an empty chip list and leak a 404 link."""
|
||||
|
|
|
|||
Loading…
Reference in a new issue