4 Commits

20 changed files with 190 additions and 195 deletions

View File

@@ -34,20 +34,20 @@ These are supplied with the URL to the page you want to embed, for example for a
The supported parameters are as follows. Generally these match the equivalent parameters in the real Spothole API, where a mapping exists.
| Name | Allowed Values | Default | Example | Description |
|----------------|-----------------------|---------|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `embedded` | `true`, `false` | `false` | `?embedded=true` | Enables embedded mode. |
| `dark-mode` | `true`, `false` | `false` | `?dark-mode=true` | Enables dark mode. |
| `time-zone` | `UTC`, `local` | `UTC` | `?time-zone=local` | Sets times to be in UTC or local time. |
| `limit` | 10, 25, 50, 100 | 50 | `?limit=50` | Sets the number of spots that will be displayed on the main spots page |
| `limit` | 25, 50, 100, 200, 500 | 100 | `?limit=100` | Sets the number of alerts that will be displayed on the alerts page |
| `max_age` | 300, 600, 1800, 3600 | 1800 | `?max_age=1800` | Sets the maximum age of spots displayed on the map and bands pages, in seconds. |
| `band` | Comma-separated list | (all) | `?band=20m,40m` | Sets the list of bands that will be shown on the spots, bands and map pages. Available options match the labels of the buttons in the standard web interface. |
| `sig` | Comma-separated list | (all) | `?sig=POTA,SOTA,NO_SIG` | Sets the list of SIGs that will be shown on the spots, bands and map pages. Available options match the labels of the buttons in the standard web interface. |
| `source` | Comma-separated list | (all) | `?source=Cluster` | Sets the list of sources that will be shown on any spot or alert pages. Available options match the labels of the buttons in the standard web interface. |
| `mode_type` | Comma-separated list | (all) | `?mode_type=PHONE,CW` | Sets the list of mode types that will be shown on the spots, bands and map pages. Available options match the labels of the buttons in the standard web interface. |
| `dx_continent` | Comma-separated list | (all) | `?dx_continent=NA,SA` | Sets the list of DX Continents that will be shown on any spot or alert pages. Available options match the labels of the buttons in the standard web interface. |
| `de_continent` | Comma-separated list | (all) | `?de_continent=EU` | Sets the list of DE Continents that will be shown on the spots, bands and map pages. Available options match the labels of the buttons in the standard web interface. |
| Name | Allowed Values | Default | Example | Description |
|----------------|-------------------------|---------|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `embedded` | `true`, `false` | `false` | `?embedded=true` | Enables embedded mode. |
| `color-scheme` | `light`, `dark`, `auto` | `auto` | `?color-scheme=dark` | Forces light or dark mode in preference to the operating system default. |
| `time-zone` | `UTC`, `local` | `UTC` | `?time-zone=local` | Sets times to be in UTC or local time. |
| `limit` | 10, 25, 50, 100 | 50 | `?limit=50` | Sets the number of spots that will be displayed on the main spots page |
| `limit` | 25, 50, 100, 200, 500 | 100 | `?limit=100` | Sets the number of alerts that will be displayed on the alerts page |
| `max_age` | 300, 600, 1800, 3600 | 1800 | `?max_age=1800` | Sets the maximum age of spots displayed on the map and bands pages, in seconds. |
| `band` | Comma-separated list | (all) | `?band=20m,40m` | Sets the list of bands that will be shown on the spots, bands and map pages. Available options match the labels of the buttons in the standard web interface. |
| `sig` | Comma-separated list | (all) | `?sig=POTA,SOTA,NO_SIG` | Sets the list of SIGs that will be shown on the spots, bands and map pages. Available options match the labels of the buttons in the standard web interface. |
| `source` | Comma-separated list | (all) | `?source=Cluster` | Sets the list of sources that will be shown on any spot or alert pages. Available options match the labels of the buttons in the standard web interface. |
| `mode_type` | Comma-separated list | (all) | `?mode_type=PHONE,CW` | Sets the list of mode types that will be shown on the spots, bands and map pages. Available options match the labels of the buttons in the standard web interface. |
| `dx_continent` | Comma-separated list | (all) | `?dx_continent=NA,SA` | Sets the list of DX Continents that will be shown on any spot or alert pages. Available options match the labels of the buttons in the standard web interface. |
| `de_continent` | Comma-separated list | (all) | `?de_continent=EU` | Sets the list of DE Continents that will be shown on the spots, bands and map pages. Available options match the labels of the buttons in the standard web interface. |
More will be added soon to allow customisation of filters and other display properties.

View File

@@ -188,4 +188,6 @@ web-ui-options:
max-spot-age: [5, 10, 30, 60]
max-spot-age-default: 30
alert-count: [25, 50, 100, 200, 500]
alert-count-default: 100
alert-count-default: 100
color-scheme-default: "auto"
band-color-scheme-default: "PSK Reporter (Adjusted)"

View File

@@ -24,3 +24,7 @@ WEB_UI_OPTIONS = config["web-ui-options"]
# but for consistency we provide this to the front-end in web-ui-options because it has no impact outside of the web UI.
WEB_UI_OPTIONS["spot-providers-enabled-by-default"] = [p["name"] for p in config["spot-providers"] if p["enabled"] and (
"enabled-by-default-in-web-ui" not in p or p["enabled-by-default-in-web-ui"] == True)]
# If spotting to this server is enabled, "API" is another valid spot source even though it does not come from
# one of our proviers. We set that to also be enabled by default.
if ALLOW_SPOTTING:
WEB_UI_OPTIONS["spot-providers-enabled-by-default"].append("API")

View File

@@ -34,13 +34,11 @@ class APIOptionsHandler(tornado.web.RequestHandler):
map(lambda p: p["name"], filter(lambda p: p["enabled"], self.status_data["alert_providers"]))),
"continents": CONTINENTS,
"max_spot_age": MAX_SPOT_AGE,
"spot_allowed": ALLOW_SPOTTING,
"web-ui-options": WEB_UI_OPTIONS}
"spot_allowed": ALLOW_SPOTTING}
# If spotting to this server is enabled, "API" is another valid spot source even though it does not come from
# one of our proviers.
if ALLOW_SPOTTING:
options["spot_sources"].append("API")
options["web-ui-options"]["spot-providers-enabled-by-default"].append("API")
self.write(json.dumps(options, default=serialize_everything))
self.set_status(200)

View File

@@ -3,7 +3,7 @@ from datetime import datetime
import pytz
import tornado
from core.config import ALLOW_SPOTTING
from core.config import ALLOW_SPOTTING, WEB_UI_OPTIONS
from core.constants import SOFTWARE_VERSION
from core.prometheus_metrics_handler import page_requests_counter
@@ -22,5 +22,6 @@ class PageTemplateHandler(tornado.web.RequestHandler):
page_requests_counter.inc()
# Load named template, and provide variables used in templates
self.render(self.template_name + ".html", software_version=SOFTWARE_VERSION, allow_spotting=ALLOW_SPOTTING)
self.render(self.template_name + ".html", software_version=SOFTWARE_VERSION, allow_spotting=ALLOW_SPOTTING,
web_ui_options=WEB_UI_OPTIONS)

View File

@@ -63,7 +63,7 @@
<p>This software is dedicated to the memory of Tom G1PJB, SK, a friend and colleague who sadly passed away around the time I started writing it in Autumn 2025. I was looking forward to showing it to you when it was done.</p>
</div>
<script src="/js/common.js?v=6"></script>
<script src="/js/common.js?v=7"></script>
<script>$(document).ready(function() { $("#nav-link-about").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %}

View File

@@ -69,8 +69,8 @@
</div>
<script src="/js/common.js?v=6"></script>
<script src="/js/add-spot.js?v=6"></script>
<script src="/js/common.js?v=7"></script>
<script src="/js/add-spot.js?v=7"></script>
<script>$(document).ready(function() { $("#nav-link-add-spot").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %}

View File

@@ -102,6 +102,9 @@
<h5 class="card-title">Number of Alerts</h5>
<p class="card-text spothole-card-text">Show up to
<select id="alerts-to-fetch" class="storeable-select form-select ms-2" oninput="filtersUpdated();" style="width: 5em;display: inline-block;">
{% for c in web_ui_options["alert-count"] %}
<option value="{{c}}" {% if web_ui_options["alert-count-default"] == c %}selected{% end %}>{{c}}</option>
{% end %}
</select>
alerts
</p>
@@ -112,12 +115,14 @@
<div class="card">
<div class="card-body">
<h5 class="card-title">Theme</h5>
<div class="form-group">
<div class="form-check form-check-inline">
<input class="form-check-input storeable-checkbox" type="checkbox" id="darkMode" value="darkMode" oninput="toggleDarkMode();">
<label class="form-check-label" for="darkMode">Dark mode</label>
</div>
</div>
<p class="card-text spothole-card-text">
<label class="form-check-label" for="color-scheme">UI color scheme</label>
<select id="color-scheme" class="storeable-select form-select d-inline-block" oninput="setColorSchemeFromUI();" style="display: inline-block;">
<option value="auto" {% if web_ui_options["color-scheme-default"] == "auto" %}selected{% end %}>Automatic</option>
<option value="light" {% if web_ui_options["color-scheme-default"] == "light" %}selected{% end %}>Light</option>
<option value="dark" {% if web_ui_options["color-scheme-default"] == "dark" %}selected{% end %}>Dark</option>
</select>
</p>
</div>
</div>
</div>
@@ -168,8 +173,8 @@
</div>
<script src="/js/common.js?v=6"></script>
<script src="/js/alerts.js?v=6"></script>
<script src="/js/common.js?v=7"></script>
<script src="/js/alerts.js?v=7"></script>
<script>$(document).ready(function() { $("#nav-link-alerts").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %}

View File

@@ -102,6 +102,9 @@
<h5 class="card-title">Spot Age</h5>
<p class="card-text spothole-card-text">Last
<select id="max-spot-age" class="storeable-select form-select ms-2 me-2 d-inline-block" oninput="filtersUpdated();" style="width: 5em; display: inline-block;">
{% for a in web_ui_options["max-spot-age"] %}
<option value="{{a*60}}" {% if web_ui_options["max-spot-age-default"] == a*60 %}selected{% end %}>{{a}}</option>
{% end %}
</select>
minutes
</p>
@@ -112,17 +115,29 @@
<div class="card">
<div class="card-body">
<h5 class="card-title">Theme</h5>
<div class="form-group">
<div class="form-check form-check-inline">
<input class="form-check-input storeable-checkbox" type="checkbox" id="darkMode" value="darkMode" oninput="toggleDarkMode();">
<label class="form-check-label" for="darkMode">Dark mode</label>
</div>
<p class="card-text spothole-card-text">
Band color scheme<br/>
<select id="band-color-scheme" class="storeable-select form-select d-inline-block" oninput="setBandColorSchemeFromUI();" style="display: inline-block;">
</select>
</p>
</div>
<p class="card-text spothole-card-text">
<label class="form-check-label" for="color-scheme">UI color scheme</label>
<select id="color-scheme" class="storeable-select form-select d-inline-block" oninput="setColorSchemeFromUI();" style="display: inline-block;">
<option value="auto" {% if web_ui_options["color-scheme-default"] == "auto" %}selected{% end %}>Automatic</option>
<option value="light" {% if web_ui_options["color-scheme-default"] == "light" %}selected{% end %}>Light</option>
<option value="dark" {% if web_ui_options["color-scheme-default"] == "dark" %}selected{% end %}>Dark</option>
</select>
</p>
<p class="card-text spothole-card-text">
<label class="form-check-label" for="band-color-scheme">Band color scheme</label><br/>
<select id="band-color-scheme" class="storeable-select form-select d-inline-block" oninput="setBandColorSchemeFromUI();" style="display: inline-block;">
<option value="PSK Reporter" {% if web_ui_options["band-color-scheme-default"] == "PSK Reporter" %}selected{% end %}>PSK Reporter</option>
<option value="PSK Reporter (Adjusted)" {% if web_ui_options["band-color-scheme-default"] == "PSK Reporter (Adjusted)" %}selected{% end %}>PSK Reporter (Adjusted)</option>
<option value="RBN" {% if web_ui_options["band-color-scheme-default"] == "RBN" %}selected{% end %}>RBN</option>
<option value="Ham Rainbow" {% if web_ui_options["band-color-scheme-default"] == "Ham Rainbow" %}selected{% end %}>Ham Rainbow</option>
<option value="Ham Rainbow (Reverse)" {% if web_ui_options["band-color-scheme-default"] == "Ham Rainbow (Reverse)" %}selected{% end %}>Ham Rainbow (Reverse)</option>
<option value="Kate Morley" {% if web_ui_options["band-color-scheme-default"] == "Kate Morley" %}selected{% end %}>Kate Morley</option>
<option value="ColorBrewer" {% if web_ui_options["band-color-scheme-default"] == "ColorBrewer" %}selected{% end %}>ColorBrewer</option>
<option value="IWantHue" {% if web_ui_options["band-color-scheme-default"] == "IWantHue" %}selected{% end %}>IWantHue</option>
<option value="IWantHue (Color Blind)" {% if web_ui_options["band-color-scheme-default"] == "IWantHue (Color Blind)" %}selected{% end %}>IWantHue (Color Blind)</option>
<option value="Mokole" {% if web_ui_options["band-color-scheme-default"] == "Mokole" %}selected{% end %}>Mokole</option>
</select>
</p>
</div>
</div>
</div>
@@ -134,9 +149,12 @@
</div>
<script src="/js/common.js?v=6"></script>
<script src="/js/spotsbandsandmap.js?v=6"></script>
<script src="/js/bands.js?v=6"></script>
<script>
let spotProvidersEnabledByDefault = {% raw json_encode(web_ui_options["spot-providers-enabled-by-default"]) %};
</script>
<script src="/js/common.js?v=7"></script>
<script src="/js/spotsbandsandmap.js?v=7"></script>
<script src="/js/bands.js?v=7"></script>
<script>$(document).ready(function() { $("#nav-link-bands").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %}

View File

@@ -46,10 +46,10 @@
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/tinycolor2@1.6.0/cjs/tinycolor.min.js"></script>
<script src="https://misc.ianrenton.com/jsutils/utils.js?v=6"></script>
<script src="https://misc.ianrenton.com/jsutils/storage.js?v=6"></script>
<script src="https://misc.ianrenton.com/jsutils/ui-ham.js?v=6"></script>
<script src="https://misc.ianrenton.com/jsutils/geo.js?v=6"></script>
<script src="https://misc.ianrenton.com/jsutils/utils.js?v=7"></script>
<script src="https://misc.ianrenton.com/jsutils/storage.js?v=7"></script>
<script src="https://misc.ianrenton.com/jsutils/ui-ham.js?v=7"></script>
<script src="https://misc.ianrenton.com/jsutils/geo.js?v=7"></script>
</head>
<body>

View File

@@ -101,6 +101,9 @@
<h5 class="card-title">Spot Age</h5>
<p class="card-text spothole-card-text">Last
<select id="max-spot-age" class="storeable-select form-select ms-2 me-2 d-inline-block" oninput="filtersUpdated();" style="width: 5em; display: inline-block;">
{% for a in web_ui_options["max-spot-age"] %}
<option value="{{a*60}}" {% if web_ui_options["max-spot-age-default"] == a*60 %}selected{% end %}>{{a}}</option>
{% end %}
</select>
minutes
</p>
@@ -124,17 +127,29 @@
<div class="card">
<div class="card-body">
<h5 class="card-title">Theme</h5>
<div class="form-group">
<div class="form-check form-check-inline">
<input class="form-check-input storeable-checkbox" type="checkbox" id="darkMode" value="darkMode" oninput="toggleDarkMode();">
<label class="form-check-label" for="darkMode">Dark mode</label>
</div>
<p class="card-text spothole-card-text">
Band color scheme<br/>
<select id="band-color-scheme" class="storeable-select form-select d-inline-block" oninput="setBandColorSchemeFromUI();" style="display: inline-block;">
</select>
</p>
</div>
<p class="card-text spothole-card-text">
<label class="form-check-label" for="color-scheme">UI color scheme</label>
<select id="color-scheme" class="storeable-select form-select d-inline-block" oninput="setColorSchemeFromUI();" style="display: inline-block;">
<option value="auto" {% if web_ui_options["color-scheme-default"] == "auto" %}selected{% end %}>Automatic</option>
<option value="light" {% if web_ui_options["color-scheme-default"] == "light" %}selected{% end %}>Light</option>
<option value="dark" {% if web_ui_options["color-scheme-default"] == "dark" %}selected{% end %}>Dark</option>
</select>
</p>
<p class="card-text spothole-card-text">
<label class="form-check-label" for="band-color-scheme">Band color scheme</label><br/>
<select id="band-color-scheme" class="storeable-select form-select d-inline-block" oninput="setBandColorSchemeFromUI();" style="display: inline-block;">
<option value="PSK Reporter" {% if web_ui_options["band-color-scheme-default"] == "PSK Reporter" %}selected{% end %}>PSK Reporter</option>
<option value="PSK Reporter (Adjusted)" {% if web_ui_options["band-color-scheme-default"] == "PSK Reporter (Adjusted)" %}selected{% end %}>PSK Reporter (Adjusted)</option>
<option value="RBN" {% if web_ui_options["band-color-scheme-default"] == "RBN" %}selected{% end %}>RBN</option>
<option value="Ham Rainbow" {% if web_ui_options["band-color-scheme-default"] == "Ham Rainbow" %}selected{% end %}>Ham Rainbow</option>
<option value="Ham Rainbow (Reverse)" {% if web_ui_options["band-color-scheme-default"] == "Ham Rainbow (Reverse)" %}selected{% end %}>Ham Rainbow (Reverse)</option>
<option value="Kate Morley" {% if web_ui_options["band-color-scheme-default"] == "Kate Morley" %}selected{% end %}>Kate Morley</option>
<option value="ColorBrewer" {% if web_ui_options["band-color-scheme-default"] == "ColorBrewer" %}selected{% end %}>ColorBrewer</option>
<option value="IWantHue" {% if web_ui_options["band-color-scheme-default"] == "IWantHue" %}selected{% end %}>IWantHue</option>
<option value="IWantHue (Color Blind)" {% if web_ui_options["band-color-scheme-default"] == "IWantHue (Color Blind)" %}selected{% end %}>IWantHue (Color Blind)</option>
<option value="Mokole" {% if web_ui_options["band-color-scheme-default"] == "Mokole" %}selected{% end %}>Mokole</option>
</select>
</p>
</div>
</div>
</div>
@@ -152,9 +167,12 @@
<script src="https://cdn.jsdelivr.net/npm/leaflet.geodesic"></script>
<script src="https://cdn.jsdelivr.net/npm/@joergdietrich/leaflet.terminator@1.1.0/L.Terminator.min.js"></script>
<script src="/js/common.js?v=6"></script>
<script src="/js/spotsbandsandmap.js?v=6"></script>
<script src="/js/map.js?v=6"></script>
<script>
let spotProvidersEnabledByDefault = {% raw json_encode(web_ui_options["spot-providers-enabled-by-default"]) %};
</script>
<script src="/js/common.js?v=7"></script>
<script src="/js/spotsbandsandmap.js?v=7"></script>
<script src="/js/map.js?v=7"></script>
<script>$(document).ready(function() { $("#nav-link-map").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %}

View File

@@ -134,6 +134,9 @@
<h5 class="card-title">Number of Spots</h5>
<p class="card-text spothole-card-text">Show up to
<select id="spots-to-fetch" class="storeable-select form-select ms-2 me-2 d-inline-block" oninput="filtersUpdated();" style="width: 5em; display: inline-block;">
{% for c in web_ui_options["spot-count"] %}
<option value="{{c}}" {% if web_ui_options["spot-count-default"] == c %}selected{% end %}>{{c}}</option>
{% end %}
</select>
spots
</p>
@@ -155,15 +158,27 @@
<div class="card">
<div class="card-body">
<h5 class="card-title">Theme</h5>
<div class="form-group">
<div class="form-check form-check-inline">
<input class="form-check-input storeable-checkbox" type="checkbox" id="darkMode" value="darkMode" oninput="toggleDarkMode();">
<label class="form-check-label" for="darkMode">Dark mode</label>
</div>
</div>
<p class="card-text spothole-card-text">
Band color scheme<br/>
<label class="form-check-label" for="color-scheme">UI color scheme</label>
<select id="color-scheme" class="storeable-select form-select d-inline-block" oninput="setColorSchemeFromUI();" style="display: inline-block;">
<option value="auto" {% if web_ui_options["color-scheme-default"] == "auto" %}selected{% end %}>Automatic</option>
<option value="light" {% if web_ui_options["color-scheme-default"] == "light" %}selected{% end %}>Light</option>
<option value="dark" {% if web_ui_options["color-scheme-default"] == "dark" %}selected{% end %}>Dark</option>
</select>
</p>
<p class="card-text spothole-card-text">
<label class="form-check-label" for="band-color-scheme">Band color scheme</label><br/>
<select id="band-color-scheme" class="storeable-select form-select d-inline-block" oninput="setBandColorSchemeFromUI();" style="display: inline-block;">
<option value="PSK Reporter" {% if web_ui_options["band-color-scheme-default"] == "PSK Reporter" %}selected{% end %}>PSK Reporter</option>
<option value="PSK Reporter (Adjusted)" {% if web_ui_options["band-color-scheme-default"] == "PSK Reporter (Adjusted)" %}selected{% end %}>PSK Reporter (Adjusted)</option>
<option value="RBN" {% if web_ui_options["band-color-scheme-default"] == "RBN" %}selected{% end %}>RBN</option>
<option value="Ham Rainbow" {% if web_ui_options["band-color-scheme-default"] == "Ham Rainbow" %}selected{% end %}>Ham Rainbow</option>
<option value="Ham Rainbow (Reverse)" {% if web_ui_options["band-color-scheme-default"] == "Ham Rainbow (Reverse)" %}selected{% end %}>Ham Rainbow (Reverse)</option>
<option value="Kate Morley" {% if web_ui_options["band-color-scheme-default"] == "Kate Morley" %}selected{% end %}>Kate Morley</option>
<option value="ColorBrewer" {% if web_ui_options["band-color-scheme-default"] == "ColorBrewer" %}selected{% end %}>ColorBrewer</option>
<option value="IWantHue" {% if web_ui_options["band-color-scheme-default"] == "IWantHue" %}selected{% end %}>IWantHue</option>
<option value="IWantHue (Color Blind)" {% if web_ui_options["band-color-scheme-default"] == "IWantHue (Color Blind)" %}selected{% end %}>IWantHue (Color Blind)</option>
<option value="Mokole" {% if web_ui_options["band-color-scheme-default"] == "Mokole" %}selected{% end %}>Mokole</option>
</select>
</p>
</div>
@@ -224,9 +239,12 @@
</div>
<script src="/js/common.js?v=6"></script>
<script src="/js/spotsbandsandmap.js?v=6"></script>
<script src="/js/spots.js?v=6"></script>
<script>
let spotProvidersEnabledByDefault = {% raw json_encode(web_ui_options["spot-providers-enabled-by-default"]) %};
</script>
<script src="/js/common.js?v=7"></script>
<script src="/js/spotsbandsandmap.js?v=7"></script>
<script src="/js/spots.js?v=7"></script>
<script>$(document).ready(function() { $("#nav-link-spots").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %}

View File

@@ -3,8 +3,8 @@
<div id="status-container" class="row row-cols-1 row-cols-md-4 g-4 mt-4"></div>
<script src="/js/common.js?v=6"></script>
<script src="/js/status.js?v=6"></script>
<script src="/js/common.js?v=7"></script>
<script src="/js/status.js?v=7"></script>
<script>$(document).ready(function() { $("#nav-link-status").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %}

View File

@@ -483,7 +483,7 @@ paths:
tags:
- General
summary: Get enumeration options
description: Retrieves the list of options for various enumerated types, which can be found in the spots and also provided back to the API as query parameters. While these enumerated options are defined in this spec anyway, providing them in an API call allows us to define extra parameters, like the colours associated with bands, and also allows clients to set up their filters and features without having to have internal knowledge about, for example, what bands the server knows about. The call also returns a variety of other parameters that may be of use to a web UI, including the contents of the "web-ui-options" config section, which provides guidance for web UI implementations such as the built-in one on sensible configuration options such as the number of spots/alerts to retrieve, or the maximum age of spots to retrieve.
description: Retrieves the list of options for various enumerated types, which can be found in the spots and also provided back to the API as query parameters. While these enumerated options are defined in this spec anyway, providing them in an API call allows us to define extra parameters, like the colours associated with bands, and also allows clients to set up their filters and features without having to have internal knowledge about, for example, what bands the server knows about. The call also returns a variety of other parameters that may be of use to a web UI or other client.
operationId: options
responses:
'200':
@@ -535,46 +535,6 @@ paths:
type: boolean
description: Whether the POST /spot call, to add spots to the server directly via its API, is permitted on this server.
example: true
web-ui-options:
type: object
properties:
spot-count:
type: array
description: An array of suggested "spot counts" that the web UI can retrieve from the API
items:
type: integer
example: 50
spot-count-default:
type: integer
example: 50
description: The suggested default "spot count" that the web UI should retrieve from the API
max-spot-age:
type: array
description: An array of suggested "maximum spot ages" that the web UI can retrieve from the API
items:
type: integer
example: 30
max-spot-age-default:
type: integer
example: 30
description: The suggested default "maximum spot age" that the web UI should retrieve from the API
spot-providers-enabled-by-default:
type: array
description: A list of the spot providers that should be enabled in the web UI on first load, if the user hasn't already got a localStorage setting that sets their preference. This is to allow some high-volume providers like RBN to be enabled in Spothole's back-end and displayable in the web UI if the user wants, but by default the experience will not include them.
items:
type: string
example: "POTA"
alert-count:
type: array
description: An array of suggested "alert counts" that the web UI can retrieve from the API
items:
type: integer
example: 100
alert-count-default:
type: integer
example: 100
description: The suggested default "alert count" that the web UI should retrieve from the API
/lookup/call:
get:

View File

@@ -285,13 +285,6 @@ function loadOptions() {
generateMultiToggleFilterCard("#dx-continent-options", "dx_continent", options["continents"]);
generateMultiToggleFilterCard("#source-options", "source", options["alert_sources"]);
// Populate the Display panel
options["web-ui-options"]["alert-count"].forEach(sc => $("#alerts-to-fetch").append($('<option>', {
value: sc,
text: sc
})));
$("#alerts-to-fetch").val(options["web-ui-options"]["alert-count-default"]);
// Load URL params. These may select things from the various filter & display options, so the function needs
// to be called after these are set up, but if the URL params ask for "embedded mode", this will suppress
// loading settings, so this needs to be called before that.
@@ -299,6 +292,7 @@ function loadOptions() {
// Load filters from settings storage
loadSettings();
setColorScheme($("#color-scheme option:selected").val());
// Load alerts and set up the timer
loadAlerts();
@@ -312,12 +306,6 @@ function filtersUpdated() {
saveSettings();
}
// Function to set dark mode based on the state of the UI toggle in spots, bands and map pages
function toggleDarkMode() {
enableDarkMode($("#darkMode")[0].checked);
saveSettings();
}
// React to toggling/closing panels
function toggleFiltersPanel() {
// If we are going to display the filters panel, hide the display panel

View File

@@ -228,19 +228,9 @@ function loadOptions() {
// Store options
options = jsonData;
// Populate the Display panel
options["web-ui-options"]["max-spot-age"].forEach(sc => $("#max-spot-age").append($('<option>', {
value: sc * 60,
text: sc
})));
$("#max-spot-age").val(options["web-ui-options"]["max-spot-age-default"] * 60);
getAvailableBandColorSchemes().forEach(sc => $("#band-color-scheme").append($('<option>', {
value: sc,
text: sc
})));
// First pass loading settings, so we can load the band colour scheme before the filters that need to use it
loadSettings();
setColorScheme($("#color-scheme option:selected").val());
setBandColorScheme($("#band-color-scheme option:selected").val());
// Add CSS for band toggle buttons
@@ -252,7 +242,7 @@ function loadOptions() {
generateMultiToggleFilterCard("#dx-continent-options", "dx_continent", options["continents"]);
generateMultiToggleFilterCard("#de-continent-options", "de_continent", options["continents"]);
generateModesMultiToggleFilterCard(options["modes"]);
generateSourcesMultiToggleFilterCard(options["spot_sources"], options["web-ui-options"]["spot-providers-enabled-by-default"]);
generateSourcesMultiToggleFilterCard(options["spot_sources"], spotProvidersEnabledByDefault);
// Load URL params. These may select things from the various filter & display options, so the function needs
// to be called after these are set up, but if the URL params ask for "embedded mode", this will suppress

View File

@@ -20,8 +20,8 @@ function loadURLParams() {
}
// Handle other params
updateCheckboxFromParam(params, "dark-mode", "darkMode");
updateSelectFromParam(params, "time-zone", "timeZone"); // Only on Spots and Alerts pages
updateSelectFromParam(params, "color-scheme", "color-scheme");
updateSelectFromParam(params, "time-zone", "time-zone"); // Only on Spots and Alerts pages
updateSelectFromParam(params, "limit", "spots-to-fetch"); // Only on Spots page
updateSelectFromParam(params, "limit", "alerts-to-fetch"); // Only on Alerts page
updateSelectFromParam(params, "max_age", "max-spot-age"); // Only on Map & Bands pages
@@ -38,10 +38,6 @@ function updateCheckboxFromParam(params, paramName, checkboxID) {
let v = params.get(paramName);
if (v != null) {
$("#" + checkboxID).prop("checked", (v === "true") ? true : false);
// Extra check if this is the "dark mode" toggle
if (checkboxID == "darkMode") {
enableDarkMode((v === "true") ? true : false);
}
}
}
@@ -50,6 +46,10 @@ function updateSelectFromParam(params, paramName, selectID) {
let v = params.get(paramName);
if (v != null) {
$("#" + selectID).prop("value", v);
// Extra check if this is the "color scheme" select
if (selectID == "color-scheme") {
setColorScheme(v);
}
}
}
@@ -142,30 +142,49 @@ function columnsUpdated() {
saveSettings();
}
// Function to set dark mode on or off
function enableDarkMode(dark) {
$("html").attr("data-bs-theme", dark ? "dark" : "light");
const metaThemeColor = document.querySelector("meta[name=theme-color]");
metaThemeColor.setAttribute("content", dark ? "black" : "white");
const metaAppleStatusBarStyle = document.querySelector("meta[name=apple-mobile-web-app-status-bar-style]");
metaAppleStatusBarStyle.setAttribute("content", dark ? "black-translucent" : "white-translucent");
// Function to set the colour scheme based on the state of the UI select box
function setColorSchemeFromUI() {
let theme = $("#color-scheme option:selected").val();
if (theme != "") {
setColorScheme(theme);
saveSettings();
}
}
// Startup function to determine whether to use light or dark mode
function usePreferredTheme() {
// First, work out if we have ever explicitly saved the value of our toggle
let val = localStorage.getItem("#darkMode:checked");
if (val != null) {
enableDarkMode(JSON.parse(val));
} else {
// Never set it before, so use the system default theme and set the toggle up to match
let dark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
enableDarkMode(dark);
$("#darkMode").prop('checked', dark);
// Function to set the color scheme. Supported values: "dark", "light", "auto"
function setColorScheme(mode) {
let effectiveModeDark = mode == "dark";
if (mode == "auto") {
effectiveModeDark = window.matchMedia('(prefers-color-scheme: dark)').matches
}
$("html").attr("data-bs-theme", effectiveModeDark ? "dark" : "light");
const metaThemeColor = document.querySelector("meta[name=theme-color]");
metaThemeColor.setAttribute("content", effectiveModeDark ? "black" : "white");
const metaAppleStatusBarStyle = document.querySelector("meta[name=apple-mobile-web-app-status-bar-style]");
metaAppleStatusBarStyle.setAttribute("content", effectiveModeDark ? "black-translucent" : "white-translucent");
}
// Startup function to determine whether to use light or dark mode, or leave as auto
function usePreferredTheme() {
// Work out if we have ever explicitly saved the value of our select box. If so, we set our colour scheme now based
// on that. If not, we let the select stay with nothing selected, so that the server sets it to whatever the
// server's default is when the options call is retrieved.
let val = localStorage.getItem("#color-scheme:value");
if (val != null) {
setColorScheme(JSON.parse(val));
}
}
// Sets up a listener on the OS light-dark theme change. If the Spothole user theme is set to Auto, the UI will be
// updated, otherwise if the Spothole user theme is forced to light or dark, that preference will remain.
function listenForOSThemeChange() {
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
setColorScheme($("#color-scheme option:selected").val());
});
}
// Startup
$(document).ready(function() {
usePreferredTheme();
listenForOSThemeChange();
});

View File

@@ -160,19 +160,9 @@ function loadOptions() {
// Store options
options = jsonData;
// Populate the Display panel
options["web-ui-options"]["max-spot-age"].forEach(sc => $("#max-spot-age").append($('<option>', {
value: sc * 60,
text: sc
})));
$("#max-spot-age").val(options["web-ui-options"]["max-spot-age-default"] * 60);
getAvailableBandColorSchemes().forEach(sc => $("#band-color-scheme").append($('<option>', {
value: sc,
text: sc
})));
// First pass loading settings, so we can load the band colour scheme before the filters that need to use it
loadSettings();
setColorScheme($("#color-scheme option:selected").val());
setBandColorScheme($("#band-color-scheme option:selected").val());
// Add CSS for band toggle buttons
@@ -184,7 +174,7 @@ function loadOptions() {
generateMultiToggleFilterCard("#dx-continent-options", "dx_continent", options["continents"]);
generateMultiToggleFilterCard("#de-continent-options", "de_continent", options["continents"]);
generateModesMultiToggleFilterCard(options["modes"]);
generateSourcesMultiToggleFilterCard(options["spot_sources"], options["web-ui-options"]["spot-providers-enabled-by-default"]);
generateSourcesMultiToggleFilterCard(options["spot_sources"], spotProvidersEnabledByDefault);
// Load URL params. These may select things from the various filter & display options, so the function needs
// to be called after these are set up, but if the URL params ask for "embedded mode", this will suppress

View File

@@ -386,19 +386,9 @@ function loadOptions() {
// Store options
options = jsonData;
// Populate the Display panel
options["web-ui-options"]["spot-count"].forEach(sc => $("#spots-to-fetch").append($('<option>', {
value: sc,
text: sc
})));
$("#spots-to-fetch").val(options["web-ui-options"]["spot-count-default"]);
getAvailableBandColorSchemes().forEach(sc => $("#band-color-scheme").append($('<option>', {
value: sc,
text: sc
})));
// First pass loading settings, so we can load the band colour scheme before the filters that need to use it
loadSettings();
setColorScheme($("#color-scheme option:selected").val());
setBandColorScheme($("#band-color-scheme option:selected").val());
// Add CSS for band toggle buttons
@@ -410,7 +400,7 @@ function loadOptions() {
generateMultiToggleFilterCard("#dx-continent-options", "dx_continent", options["continents"]);
generateMultiToggleFilterCard("#de-continent-options", "de_continent", options["continents"]);
generateModesMultiToggleFilterCard(options["modes"]);
generateSourcesMultiToggleFilterCard(options["spot_sources"], options["web-ui-options"]["spot-providers-enabled-by-default"]);
generateSourcesMultiToggleFilterCard(options["spot_sources"], spotProvidersEnabledByDefault);
// Load URL params. These may select things from the various filter & display options, so the function needs
// to be called after these are set up, but if the URL params ask for "embedded mode", this will suppress

View File

@@ -110,12 +110,6 @@ function filtersUpdated() {
saveSettings();
}
// Function to set dark mode based on the state of the UI toggle in spots, bands and map pages
function toggleDarkMode() {
enableDarkMode($("#darkMode")[0].checked);
saveSettings();
}
// Function to update the band colour scheme in spots, bands and map pages
function setBandColorSchemeFromUI() {
setBandColorScheme($("#band-color-scheme option:selected").val());