7 Commits

Author SHA1 Message Date
Ian Renton
461ce94204 Cache-busting ?v= strings for CSS 2026-04-22 10:23:50 +01:00
Ian Renton
49949a0b2e Fix display of the last time cleanup ran 2026-04-11 08:17:30 +01:00
Ian Renton
a3332aa023 Fix a parsing bug with NG3K 2026-04-11 08:14:52 +01:00
Ian Renton
ac1ab4bd2d Ping on new spots option 2026-04-10 08:05:57 +01:00
Ian Renton
82944b9c38 Layout tweaks 2026-04-10 08:02:45 +01:00
Ian Renton
36dba30089 Ping on new spots option 2026-04-10 07:51:26 +01:00
Ian Renton
1ed175e099 Layout fix 2026-04-07 06:20:07 +01:00
15 changed files with 50 additions and 31 deletions

View File

@@ -68,9 +68,9 @@ class NG3K(HTTPAlertProvider):
dx_country = parts[1] dx_country = parts[1]
qsl_info = parts[3] qsl_info = parts[3]
bands = extra_parts[1] bands = extra_parts[1] if len(extra_parts) > 1 else ""
modes = extra_parts[2] if len(extra_parts) > 3 else "" modes = extra_parts[2] if len(extra_parts) > 2 else ""
comment = extra_parts[-1] comment = extra_parts[3] if len(extra_parts) > 3 else ""
# Convert to our alert format # Convert to our alert format
alert = Alert(source=self.name, alert = Alert(source=self.name,

View File

@@ -67,7 +67,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> <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> </div>
<script src="/js/common.js?v=1775499107"></script> <script src="/js/common.js?v=1776849830"></script>
<script>$(document).ready(function() { $("#nav-link-about").addClass("active"); }); <!-- highlight active page in nav --></script> <script>$(document).ready(function() { $("#nav-link-about").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %} {% end %}

View File

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

View File

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

View File

@@ -62,9 +62,9 @@
<script> <script>
let spotProvidersEnabledByDefault = {% raw json_encode(web_ui_options["spot-providers-enabled-by-default"]) %}; let spotProvidersEnabledByDefault = {% raw json_encode(web_ui_options["spot-providers-enabled-by-default"]) %};
</script> </script>
<script src="/js/common.js?v=1775499107"></script> <script src="/js/common.js?v=1776849830"></script>
<script src="/js/spotsbandsandmap.js?v=1775499107"></script> <script src="/js/spotsbandsandmap.js?v=1776849830"></script>
<script src="/js/bands.js?v=1775499107"></script> <script src="/js/bands.js?v=1776849830"></script>
<script>$(document).ready(function() { $("#nav-link-bands").addClass("active"); }); <!-- highlight active page in nav --></script> <script>$(document).ready(function() { $("#nav-link-bands").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %} {% end %}

View File

@@ -24,7 +24,7 @@
<title>Spothole</title> <title>Spothole</title>
<link rel="stylesheet" href="/css/style.css" type="text/css"> <link rel="stylesheet" href="/css/style.css?v=1776849830" type="text/css">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous"> integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
<link href="/fa/css/fontawesome.min.css" rel="stylesheet" /> <link href="/fa/css/fontawesome.min.css" rel="stylesheet" />
@@ -46,9 +46,9 @@
crossorigin="anonymous"></script> crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/tinycolor2@1.6.0/cjs/tinycolor.min.js"></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=1775499107"></script> <script src="https://misc.ianrenton.com/jsutils/utils.js?v=1776849830"></script>
<script src="https://misc.ianrenton.com/jsutils/ui-ham.js?v=1775499107"></script> <script src="https://misc.ianrenton.com/jsutils/ui-ham.js?v=1776849830"></script>
<script src="https://misc.ianrenton.com/jsutils/geo.js?v=1775499107"></script> <script src="https://misc.ianrenton.com/jsutils/geo.js?v=1776849830"></script>
</head> </head>
<body> <body>

View File

@@ -0,0 +1,11 @@
<div class="card">
<div class="card-body">
<h5 class="card-title mb-3">Audio</h5>
<div class="form-group">
<div class="form-check form-check-inline">
<input class="form-check-input storeable-checkbox" type="checkbox" id="pingOnNewSpots" value="pingOnNewSpots" oninput="saveSettings();">
<label class="form-check-label" for="pingOnNewSpots">Ping on new spots</label>
</div>
</div>
</div>
</div>

View File

@@ -230,8 +230,8 @@
</div> </div>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.9/dist/chart.umd.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.9/dist/chart.umd.min.js"></script>
<script src="/js/common.js?v=1775499107"></script> <script src="/js/common.js?v=1776849830"></script>
<script src="/js/conditions.js?v=1775499107"></script> <script src="/js/conditions.js?v=1776849830"></script>
<script>$(document).ready(function () { <script>$(document).ready(function () {
$("#nav-link-conditions").addClass("active"); $("#nav-link-conditions").addClass("active");
}); <!-- highlight active page in nav --></script> }); <!-- highlight active page in nav --></script>

View File

@@ -79,9 +79,9 @@
<script> <script>
let spotProvidersEnabledByDefault = {% raw json_encode(web_ui_options["spot-providers-enabled-by-default"]) %}; let spotProvidersEnabledByDefault = {% raw json_encode(web_ui_options["spot-providers-enabled-by-default"]) %};
</script> </script>
<script src="/js/common.js?v=1775499107"></script> <script src="/js/common.js?v=1776849830"></script>
<script src="/js/spotsbandsandmap.js?v=1775499107"></script> <script src="/js/spotsbandsandmap.js?v=1776849830"></script>
<script src="/js/map.js?v=1775499107"></script> <script src="/js/map.js?v=1776849830"></script>
<script>$(document).ready(function() { $("#nav-link-map").addClass("active"); }); <!-- highlight active page in nav --></script> <script>$(document).ready(function() { $("#nav-link-map").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %} {% end %}

View File

@@ -74,6 +74,9 @@
<div class="col"> <div class="col">
{% module Template("cards/table-columns-spots.html", web_ui_options=web_ui_options) %} {% module Template("cards/table-columns-spots.html", web_ui_options=web_ui_options) %}
</div> </div>
<div class="col">
{% module Template("cards/audio.html", web_ui_options=web_ui_options) %}
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -87,9 +90,9 @@
<script> <script>
let spotProvidersEnabledByDefault = {% raw json_encode(web_ui_options["spot-providers-enabled-by-default"]) %}; let spotProvidersEnabledByDefault = {% raw json_encode(web_ui_options["spot-providers-enabled-by-default"]) %};
</script> </script>
<script src="/js/common.js?v=1775499107"></script> <script src="/js/common.js?v=1776849830"></script>
<script src="/js/spotsbandsandmap.js?v=1775499107"></script> <script src="/js/spotsbandsandmap.js?v=1776849830"></script>
<script src="/js/spots.js?v=1775499107"></script> <script src="/js/spots.js?v=1776849830"></script>
<script>$(document).ready(function() { $("#nav-link-spots").addClass("active"); }); <!-- highlight active page in nav --></script> <script>$(document).ready(function() { $("#nav-link-spots").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %} {% end %}

View File

@@ -59,8 +59,8 @@
</div> </div>
</div> </div>
<script src="/js/common.js?v=1775499107"></script> <script src="/js/common.js?v=1776849830"></script>
<script src="/js/status.js?v=1775499107"></script> <script src="/js/status.js?v=1776849830"></script>
<script> <script>
$(document).ready(function() { $("#nav-link-status").addClass("active"); }); <!-- highlight active page in nav --> $(document).ready(function() { $("#nav-link-status").addClass("active"); }); <!-- highlight active page in nav -->
</script> </script>

BIN
webassets/audio/ping.mp3 Normal file

Binary file not shown.

View File

@@ -61,6 +61,11 @@ function startSSEConnection() {
// Add the new spot to table // Add the new spot to table
addSpotToTopOfTable(newSpot, true); addSpotToTopOfTable(newSpot, true);
// Ping if we need to
if ($("#pingOnNewSpots")[0].checked) {
new Audio("/audio/ping.mp3").play();
}
}; };
evtSource.onerror = function(err) { evtSource.onerror = function(err) {

View File

@@ -19,7 +19,7 @@ function addBandToggleColourCSS(band_options) {
// Generate bands filter card. This one is a special case. // Generate bands filter card. This one is a special case.
function generateBandsMultiToggleFilterCard(band_options) { function generateBandsMultiToggleFilterCard(band_options) {
var $grid = $('<div class="row row-cols-3 row-cols-md-4 g-1 mb-1">'); var $grid = $('<div class="row row-cols-3 row-cols-md-2 row-cols-lg-3 row-cols-xxl-4 g-1 mb-1">');
band_options.forEach(o => { band_options.forEach(o => {
var domSafeName = o["name"].replace(/^[^A-Za-z0-9]+|[^\w]+/gi, ""); var domSafeName = o["name"].replace(/^[^A-Za-z0-9]+|[^\w]+/gi, "");
$grid.append(`<div class="col"><div class="form-check"><input type="checkbox" class="form-check-input filter-button-band storeable-checkbox" id="filter-button-band-${domSafeName}" value="${o['name']}" autocomplete="off" onClick="filtersUpdated()" checked> <label class="form-check-label" id="filter-button-label-band-${domSafeName}" for="filter-button-band-${domSafeName}">${o['name']}</label></div></div>`); $grid.append(`<div class="col"><div class="form-check"><input type="checkbox" class="form-check-input filter-button-band storeable-checkbox" id="filter-button-band-${domSafeName}" value="${o['name']}" autocomplete="off" onClick="filtersUpdated()" checked> <label class="form-check-label" id="filter-button-label-band-${domSafeName}" for="filter-button-band-${domSafeName}">${o['name']}</label></div></div>`);
@@ -40,20 +40,20 @@ function setHamHFBandToggles() {
// Generate SIGs filter card. This one is also a special case. // Generate SIGs filter card. This one is also a special case.
function generateSIGsMultiToggleFilterCard(sig_options) { function generateSIGsMultiToggleFilterCard(sig_options) {
var $grid = $('<div class="row row-cols-2 row-cols-md-3 g-1 mb-1">'); var $grid = $('<div class="row row-cols-2 row-cols-xxl-3 g-1 mb-1">');
sig_options.forEach(o => { sig_options.forEach(o => {
var domSafeName = o["name"].replace(/^[^A-Za-z0-9]+|[^\w]+/gi, ""); var domSafeName = o["name"].replace(/^[^A-Za-z0-9]+|[^\w]+/gi, "");
$grid.append(`<div class="col"><div class="form-check"><input type="checkbox" class="form-check-input filter-button-sig storeable-checkbox" id="filter-button-sig-${domSafeName}" value="${o['name']}" autocomplete="off" onClick="filtersUpdated()" checked><label class="form-check-label" id="filter-button-label-sig-${domSafeName}" for="filter-button-sig-${domSafeName}" title="${o['description']}"><i class="fa-solid ${sigToIcon(o['name'], 'fa-tower-cell')}"></i> ${o['name']}</label></div></div>`); $grid.append(`<div class="col"><div class="form-check"><input type="checkbox" class="form-check-input filter-button-sig storeable-checkbox" id="filter-button-sig-${domSafeName}" value="${o['name']}" autocomplete="off" onClick="filtersUpdated()" checked><label class="form-check-label" id="filter-button-label-sig-${domSafeName}" for="filter-button-sig-${domSafeName}" title="${o['description']}"><i class="fa-solid ${sigToIcon(o['name'], 'fa-tower-cell')}"></i> ${o['name']}</label></div></div>`);
}); });
// Bonus "NO_SIG" / "General DX" option // Bonus "NO_SIG" / "General DX" option
$grid.append(`<div class="col-8"><div class="form-check"><input type="checkbox" class="form-check-input filter-button-sig storeable-checkbox" id="filter-button-sig-NO_SIG" value="NO_SIG" autocomplete="off" onClick="filtersUpdated()" checked><label class="form-check-label" id="filter-button-label-sig-NO_SIG" for="filter-button-sig-NO_SIG"><i class="fa-solid fa-tower-cell"></i> General DX</label></div></div>`); $grid.append(`<div class="w-100"><div class="form-check"><input type="checkbox" class="form-check-input filter-button-sig storeable-checkbox" id="filter-button-sig-NO_SIG" value="NO_SIG" autocomplete="off" onClick="filtersUpdated()" checked><label class="form-check-label" id="filter-button-label-sig-NO_SIG" for="filter-button-sig-NO_SIG"><i class="fa-solid fa-tower-cell"></i> General DX</label></div></div>`);
$("#sig-options").append($grid); $("#sig-options").append($grid);
$("#sig-options").append(`<div class="mt-1"><a href="#" onclick="toggleFilterButtons('sig', true); return false;">All</a> &nbsp; <a href="#" onclick="toggleFilterButtons('sig', false); return false;">None</a></div>`); $("#sig-options").append(`<div class="mt-1"><a href="#" onclick="toggleFilterButtons('sig', true); return false;">All</a> &nbsp; <a href="#" onclick="toggleFilterButtons('sig', false); return false;">None</a></div>`);
} }
// Generate modes filter card. This one is also a special case. // Generate modes filter card. This one is also a special case.
function generateModesMultiToggleFilterCard(mode_options) { function generateModesMultiToggleFilterCard(mode_options) {
var $grid = $('<div class="row row-cols-3 g-1 mb-1">'); var $grid = $('<div class="row row-cols-3 row-cols-md-2 row-cols-lg-3 g-1 mb-1">');
mode_options.forEach(o => { mode_options.forEach(o => {
var domSafeName = o.replace(/^[^A-Za-z0-9]+|[^\w]+/gi, ""); var domSafeName = o.replace(/^[^A-Za-z0-9]+|[^\w]+/gi, "");
$grid.append(`<div class="col"><div class="form-check"><input type="checkbox" class="form-check-input filter-button-mode storeable-checkbox" id="filter-button-mode-${domSafeName}" value="${o}" autocomplete="off" onClick="filtersUpdated()" checked><label class="form-check-label" id="filter-button-label-mode-${domSafeName}" for="filter-button-mode-${domSafeName}">${o}</label></div></div>`); $grid.append(`<div class="col"><div class="form-check"><input type="checkbox" class="form-check-input filter-button-mode storeable-checkbox" id="filter-button-mode-${domSafeName}" value="${o}" autocomplete="off" onClick="filtersUpdated()" checked><label class="form-check-label" id="filter-button-label-mode-${domSafeName}" for="filter-button-mode-${domSafeName}">${o}</label></div></div>`);
@@ -84,7 +84,7 @@ function setDigiModeToggles() {
// set which ones are enabled by default based on config rather than having them all enabled by default. We also sanitise // set which ones are enabled by default based on config rather than having them all enabled by default. We also sanitise
// names here for HTML elements. // names here for HTML elements.
function generateSourcesMultiToggleFilterCard(source_options, sources_enabled_by_default) { function generateSourcesMultiToggleFilterCard(source_options, sources_enabled_by_default) {
var $grid = $('<div class="row row-cols-2 row-cols-md-3 g-1 mb-1">'); var $grid = $('<div class="row row-cols-2 row-cols-xxl-3 g-1 mb-1">');
source_options.forEach(o => { source_options.forEach(o => {
var enable = sources_enabled_by_default.includes(o); var enable = sources_enabled_by_default.includes(o);
var domSafeName = o.replace(/^[^A-Za-z0-9]+|[^\w]+/gi, ""); var domSafeName = o.replace(/^[^A-Za-z0-9]+|[^\w]+/gi, "");

View File

@@ -13,7 +13,7 @@ function loadStatus() {
$("#web-server-last-page").text(moment.unix(jsonData["webserver"]["last_page_access"]).utc().fromNow()); $("#web-server-last-page").text(moment.unix(jsonData["webserver"]["last_page_access"]).utc().fromNow());
$("#cleanup-status").text(jsonData["cleanup"]["status"]); $("#cleanup-status").text(jsonData["cleanup"]["status"]);
$("#cleanu-last-ran").text(moment.unix(jsonData["cleanup"]["last_ran"]).utc().fromNow()); $("#cleanup-last-ran").text(moment.unix(jsonData["cleanup"]["last_ran"]).utc().fromNow());
jsonData["spot_providers"].forEach(p => { jsonData["spot_providers"].forEach(p => {
$("#spot-providers-status-container").append(` $("#spot-providers-status-container").append(`