diff --git a/static/css/style.css b/static/css/style.css index 6bc3614..97fbe09 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -181,12 +181,15 @@ tr.table-faded td span { } /* New spot styles */ -tr.new td { +tr.row-new td { animation: 2s linear newspotanim; } @keyframes newspotanim { 0% { + background-color: initial; + } + 10% { background-color: var(--bs-success-border-subtle); } 100% { @@ -194,6 +197,37 @@ tr.new td { } } +/* Wanted spot styles */ +tr.row-wanted td { + animation: wantedanim 1.5s ease-in-out alternate infinite; +} + +div.band-spot-wanted { + animation: wantedanim 1.5s ease-in-out alternate infinite; +} + +.leaflet-marker-icon.marker-icon-wanted::after { + content: ""; + width: 20px; + height: 20px; + left: 7px; + top: 13px; + background-color: #cf9e3d; + box-shadow: 0px 0px 10px 15px #cf9e3d; + position: absolute; + z-index: -1; + border-radius: 1000%; +} + +@keyframes wantedanim { + 0% { + background-color: #cf9e3d; + } + 100% { + background-color: #e1b655; + } +} + /* TABLE */ #table-container { diff --git a/static/js/alerts.js b/static/js/alerts.js index 3ba0029..fc4e37e 100644 --- a/static/js/alerts.js +++ b/static/js/alerts.js @@ -9,15 +9,17 @@ let alerts = []; // Load alerts and populate the table. No need for QRZ/HamQTH credential headers as these won't add any useful data // to alerts function loadAlerts() { - $.ajax({url: '/api/v2/alerts' + buildQueryString(), dataType: 'json', success: function (jsonData) { - // Store last updated time - lastUpdateTime = moment.utc(); - updateRefreshDisplay(); - // Store data - alerts = jsonData; - // Update table - updateTable(); - }}); + $.ajax({ + url: '/api/v2/alerts' + buildQueryString(), dataType: 'json', success: function (jsonData) { + // Store last updated time + lastUpdateTime = moment.utc(); + updateRefreshDisplay(); + // Store data + alerts = jsonData; + // Update table + updateTable(); + } + }); } // Build a query string for the API, based on the filters that the user has selected. @@ -115,12 +117,28 @@ function addAlertRowsToTable(tbody, alerts) { // Create row let $tr = $(''); + // Calculate some values + let wantThis = false; + if (a["dx_calls"] != null) { + for (i in a["dx_calls"]) { + if (callWanted(a["dx_calls"][i])) { + wantThis = true; + break; + } + } + } + // Apply striping to the table. We can't just use Bootstrap's table-striped class because we have all sorts of // extra faff to deal with, like the mobile view having extra rows, and the On Now / Next 24h / Later banners - // which cause the table-striped colouring to go awry. - if (count % 2 === 1) { + // which cause the table-striped colouring to go awry. If the call is wanted, suppress the striping so the + // highlight colour looks right. + if (count % 2 === 1 && !wantThis) { $tr.addClass("table-active"); } + // If this is a wanted call, highlight it + if (wantThis) { + $tr.addClass("row-wanted"); + } // Use local time instead of UTC? const useLocalTime = $("#timeZone")[0].value === "local"; @@ -255,9 +273,13 @@ function addAlertRowsToTable(tbody, alerts) { // Second row for mobile view only, containing source, ref, freqs/modes & comment const $tr2 = $(""); - if (count % 2 === 1) { + if (count % 2 === 1 && !wantThis) { $tr2.addClass("table-active"); } + if (wantThis) { + $tr2.addClass("row-wanted"); + } + const $td2 = $(""); if (showSource) { $td2.append(` `); diff --git a/static/js/bands.js b/static/js/bands.js index c11ac22..c9cee3d 100644 --- a/static/js/bands.js +++ b/static/js/bands.js @@ -19,7 +19,8 @@ function loadSpots() { if (sseAbortController != null) { sseAbortController.abort(); } - $.ajax({url: '/api/v2/spots' + buildQueryString(), dataType: 'json', success: function (jsonData) { + $.ajax({ + url: '/api/v2/spots' + buildQueryString(), dataType: 'json', success: function (jsonData) { // Store data spots = jsonData; // Update bands display @@ -201,7 +202,8 @@ function updateBands() { // Now each spot is tagged with how far down the div it should go, add them to the DOM. spotList.forEach(s => { let worked = alreadyWorked(s["dx_call"], s["band"], s["mode"]); - bandSpotsDiv.append(`
${s.dx_call}${s.dx_ssid != null ? "-" + s.dx_ssid : ""}${s.dx_call}${s.dx_ssid != null ? "-" + s.dx_ssid : ""} ${(s.freq / 1000000).toFixed(3)} ${s.mode}
`); + let wanted = callWanted(s["dx_call"]) && !worked; + bandSpotsDiv.append(`
${s.dx_call}${s.dx_ssid != null ? "-" + s.dx_ssid : ""}${s.dx_call}${s.dx_ssid != null ? "-" + s.dx_ssid : ""} ${(s.freq / 1000000).toFixed(3)} ${s.mode}
`); }); // Work out how tall the canvas should be. Normally this is matching the normal band column height, but if some diff --git a/static/js/common.js b/static/js/common.js index 2161a90..dd543ea 100644 --- a/static/js/common.js +++ b/static/js/common.js @@ -269,6 +269,22 @@ function getCredentialHeaders() { return headers; } +// Does the DX call match something in the user's "wanted" list? +function callWanted(call) { + let wantedString = $("#wantedCalls").val(); + if (wantedString) { + let split = wantedString.split(/[ ,]+/); + for (const i in split) { + if (split[i].length > 0 && call.toUpperCase().includes(split[i].toUpperCase())) { + return true; + } + } + return false; + } else { + return false; + } +} + // Startup $(document).ready(function () { diff --git a/static/js/map.js b/static/js/map.js index 9a71a98..efe25ac 100644 --- a/static/js/map.js +++ b/static/js/map.js @@ -46,34 +46,35 @@ function loadSpots() { // data if they can. $.ajax({ url: '/api/v2/spots' + buildQueryString(), dataType: 'json', success: function (jsonData) { - // Store data - spots = jsonData; - // Update map - updateMap(); - if ($("#showTerminator")[0].checked) { - terminator.setTime(); + // Store data + spots = jsonData; + // Update map + updateMap(); + if ($("#showTerminator")[0].checked) { + terminator.setTime(); + } + // Check if we have any credentials to use + if (Object.keys(getCredentialHeaders()).length > 0) { + // OK, we have credentials and have loaded once without them so the user has a basic map. Now reload + // with the credentials and replace what's on the map, so we can improve the data. + $.ajax({ + url: '/api/v2/spots' + buildQueryString(), + dataType: 'json', + headers: getCredentialHeaders(), + success: function (jsonData2) { + spots = jsonData2; + updateMap(); + // Now start the ongoing SSE connection + startSSEConnection(); + } + }); + } else { + // We had no credentials with which to augment the data anyway, so just start the SSE connection + // now + startSSEConnection(); + } } - // Check if we have any credentials to use - if (Object.keys(getCredentialHeaders()).length > 0) { - // OK, we have credentials and have loaded once without them so the user has a basic map. Now reload - // with the credentials and replace what's on the map, so we can improve the data. - $.ajax({ - url: '/api/v2/spots' + buildQueryString(), - dataType: 'json', - headers: getCredentialHeaders(), - success: function(jsonData2) { - spots = jsonData2; - updateMap(); - // Now start the ongoing SSE connection - startSSEConnection(); - } - }); - } else { - // We had no credentials with which to augment the data anyway, so just start the SSE connection - // now - startSSEConnection(); - } - }}); + }); } // Start the SSE connection to receive new spots as they arrive @@ -143,6 +144,12 @@ function addSpotToMap(s) { markersLayer.addLayer(m); oms.addMarker(m); + // Add highlight for wanted spots + if (callWanted(s["dx_call"])) { + console.log(s["dx_call"]); + $(m._icon).addClass('marker-icon-wanted'); + } + let geodesic = null; if ($("#mapShowGeodesics")[0].checked && s["de_latitude"] != null && s["de_longitude"] != null) { try { diff --git a/static/js/spots.js b/static/js/spots.js index 78ed1cc..2fe0f59 100644 --- a/static/js/spots.js +++ b/static/js/spots.js @@ -19,17 +19,19 @@ function loadSpots() { } // Make the new query. No credential headers on the first load to keep things quick - $.ajax({url: '/api/v2/spots' + buildQueryString(), dataType: 'json', success: function (jsonData) { - // Store data - spots = jsonData; - // Update table - updateTable(); - // Start SSE connection to fetch updates in the background, if we are in "run" mode - let run = $('#runButton:checked').val(); - if (run) { - startSSEConnection(); + $.ajax({ + url: '/api/v2/spots' + buildQueryString(), dataType: 'json', success: function (jsonData) { + // Store data + spots = jsonData; + // Update table + updateTable(); + // Start SSE connection to fetch updates in the background, if we are in "run" mode + let run = $('#runButton:checked').val(); + if (run) { + startSSEConnection(); + } } - }}); + }); } // Start an SSE connection (closing an existing one if it exists). This will then be used to add to the table on the @@ -210,23 +212,32 @@ function createNewTableRowsForSpot(s, highlightNew) { // Create row let $tr = $(''); + // Calculate some values + let alreadyWorkedThis = alreadyWorked(s["dx_call"], s["band"], s["mode"]); + let wantThis = callWanted(s["dx_call"]); + let qrt = s["qrt"] + // Apply striping to the table. We can't just use Bootstrap's table-striped class because we have all sorts of // extra faff to deal with, like the mobile view having extra rows, and the On Now / Next 24h / Later banners - // which cause the table-striped colouring to go awry. - if (rowCount % 2 === 1) { + // which cause the table-striped colouring to go awry. If the call is wanted, suppress the striping so the highlight + // colour looks right. + if (rowCount % 2 === 1 && !(wantThis && !qrt && !alreadyWorkedThis)) { $tr.addClass("table-active"); } // Show faded out if QRT or already worked - let alreadyWorkedThis = alreadyWorked(s["dx_call"], s["band"], s["mode"]); - if (s["qrt"] === true || alreadyWorkedThis) { + if (qrt || alreadyWorkedThis) { $tr.addClass("table-faded"); } // If we are asked to highlight new rows (i.e. this row is being added "live" via the SSE client and not as a bulk - // reload of the whole table) - if (highlightNew) { - $tr.addClass("new"); + // reload of the whole table), do so + if (highlightNew && !qrt && !alreadyWorkedThis) { + $tr.addClass("row-new"); + } + // If this is a wanted call, highlight it + if (wantThis && !qrt && !alreadyWorkedThis) { + $tr.addClass("row-wanted"); } // Format a UTC or local time for display @@ -399,14 +410,17 @@ function createNewTableRowsForSpot(s, highlightNew) { const $tr2 = $(""); // Apply styles as per the first row - if (rowCount % 2 === 1) { + if (rowCount % 2 === 1 && !(wantThis && !qrt && !alreadyWorkedThis)) { $tr2.addClass("table-active"); } - if (s["qrt"] === true || alreadyWorkedThis) { + if (qrt || alreadyWorkedThis) { $tr2.addClass("table-faded"); } - if (highlightNew) { - $tr2.addClass("new"); + if (highlightNew && !qrt && !alreadyWorkedThis) { + $tr2.addClass("row-new"); + } + if (wantThis && !qrt && !alreadyWorkedThis) { + $tr2.addClass("row-wanted"); } const $td2 = $(""); diff --git a/templates/add_spot.html b/templates/add_spot.html index e7b2d13..98c0c5f 100644 --- a/templates/add_spot.html +++ b/templates/add_spot.html @@ -76,7 +76,7 @@ - + diff --git a/templates/alerts.html b/templates/alerts.html index 8650073..e51e07c 100644 --- a/templates/alerts.html +++ b/templates/alerts.html @@ -8,8 +8,7 @@
- {% module Template("widgets/filters_display_data_buttons.html", web_ui_options=web_ui_options, - show_data_button=web_ui_options["qrz_enabled"] or web_ui_options["hamqth_enabled"]) %} + {% module Template("widgets/filters_display_data_buttons.html", web_ui_options=web_ui_options) %}
@@ -66,6 +65,9 @@ {% module Template("cards/hamqth.html", web_ui_options=web_ui_options) %} {% end %} +
+ {% module Template("cards/wanted_calls.html", web_ui_options=web_ui_options) %} +
@@ -82,7 +84,7 @@ - + diff --git a/templates/bands.html b/templates/bands.html index 3001fc5..cbaeb29 100644 --- a/templates/bands.html +++ b/templates/bands.html @@ -6,8 +6,7 @@
- {% module Template("widgets/filters_display_data_buttons.html", web_ui_options=web_ui_options, - show_data_button=web_ui_options["qrz_enabled"] or web_ui_options["hamqth_enabled"]) %} + {% module Template("widgets/filters_display_data_buttons.html", web_ui_options=web_ui_options) %}
@@ -18,22 +17,17 @@
{% module Template("cards/bands.html", web_ui_options=web_ui_options) %} +
+ {% module Template("cards/dx_continent.html", web_ui_options=web_ui_options) %} +
+ {% module Template("cards/de_continent.html", web_ui_options=web_ui_options) %}
{% module Template("cards/sigs.html", web_ui_options=web_ui_options) %}
{% module Template("cards/sources.html", web_ui_options=web_ui_options) %} -
-
-
-
- {% module Template("cards/dx_continent.html", web_ui_options=web_ui_options) %} -
-
- {% module Template("cards/de_continent.html", web_ui_options=web_ui_options) %} -
-
+
{% module Template("cards/modes.html", web_ui_options=web_ui_options) %}
@@ -70,6 +64,9 @@ {% module Template("cards/hamqth.html", web_ui_options=web_ui_options) %} {% end %} +
+ {% module Template("cards/wanted_calls.html", web_ui_options=web_ui_options) %} +
@@ -79,8 +76,8 @@ - - + + diff --git a/templates/base.html b/templates/base.html index 285407b..7b221db 100644 --- a/templates/base.html +++ b/templates/base.html @@ -1,6 +1,6 @@ {% extends "skeleton.html" %} {% block head_extra %} - + @@ -15,10 +15,10 @@ window.fetchEventSource = fetchEventSource; - - - - + + + + {% end %} {% block body %}
diff --git a/templates/cards/wanted_calls.html b/templates/cards/wanted_calls.html new file mode 100644 index 0000000..6998ead --- /dev/null +++ b/templates/cards/wanted_calls.html @@ -0,0 +1,18 @@ +
+
+
Wanted Calls
+
+ +
+ Enter a space- and/or comma-separated list of callsigns or partial callsigns. Any DX callsigns + that + match will be highlighted. +
+
+ +
+
+
+
\ No newline at end of file diff --git a/templates/conditions.html b/templates/conditions.html index cddeeea..cc12e92 100644 --- a/templates/conditions.html +++ b/templates/conditions.html @@ -284,7 +284,7 @@
- + diff --git a/templates/map.html b/templates/map.html index e599884..4566d93 100644 --- a/templates/map.html +++ b/templates/map.html @@ -20,8 +20,7 @@
- {% module Template("widgets/filters_display_data_buttons.html", web_ui_options=web_ui_options, - show_data_button=web_ui_options["qrz_enabled"] or web_ui_options["hamqth_enabled"]) %} + {% module Template("widgets/filters_display_data_buttons.html", web_ui_options=web_ui_options) %}
@@ -32,22 +31,17 @@
{% module Template("cards/bands.html", web_ui_options=web_ui_options) %} +
+ {% module Template("cards/dx_continent.html", web_ui_options=web_ui_options) %} +
+ {% module Template("cards/de_continent.html", web_ui_options=web_ui_options) %}
{% module Template("cards/sigs.html", web_ui_options=web_ui_options) %}
{% module Template("cards/sources.html", web_ui_options=web_ui_options) %} -
-
-
-
- {% module Template("cards/dx_continent.html", web_ui_options=web_ui_options) %} -
-
- {% module Template("cards/de_continent.html", web_ui_options=web_ui_options) %} -
-
+
{% module Template("cards/modes.html", web_ui_options=web_ui_options) %}
@@ -90,6 +84,9 @@ {% module Template("cards/hamqth.html", web_ui_options=web_ui_options) %} {% end %} +
+ {% module Template("cards/wanted_calls.html", web_ui_options=web_ui_options) %} +
@@ -112,8 +109,8 @@ - - + + diff --git a/templates/spots.html b/templates/spots.html index 9880008..9f6e567 100644 --- a/templates/spots.html +++ b/templates/spots.html @@ -25,8 +25,7 @@
{% module Template("widgets/search.html", web_ui_options=web_ui_options) %} - {% module Template("widgets/filters_display_data_buttons.html", web_ui_options=web_ui_options, - show_data_button=web_ui_options["qrz_enabled"] or web_ui_options["hamqth_enabled"]) %} + {% module Template("widgets/filters_display_data_buttons.html", web_ui_options=web_ui_options) %}
@@ -37,22 +36,17 @@
{% module Template("cards/bands.html", web_ui_options=web_ui_options) %} +
+ {% module Template("cards/dx_continent.html", web_ui_options=web_ui_options) %} +
+ {% module Template("cards/de_continent.html", web_ui_options=web_ui_options) %}
{% module Template("cards/sigs.html", web_ui_options=web_ui_options) %}
{% module Template("cards/sources.html", web_ui_options=web_ui_options) %} -
-
-
-
- {% module Template("cards/dx_continent.html", web_ui_options=web_ui_options) %} -
-
- {% module Template("cards/de_continent.html", web_ui_options=web_ui_options) %} -
-
+
{% module Template("cards/modes.html", web_ui_options=web_ui_options) %}
@@ -65,6 +59,8 @@
{% module Template("cards/time_zone.html", web_ui_options=web_ui_options) %} +
+ {% module Template("cards/audio.html", web_ui_options=web_ui_options) %}
{% module Template("cards/number_of_spots.html", web_ui_options=web_ui_options) %} @@ -76,9 +72,6 @@
{% module Template("cards/table_columns_spots.html", web_ui_options=web_ui_options) %}
-
- {% module Template("cards/audio.html", web_ui_options=web_ui_options) %} -
@@ -99,9 +92,11 @@ {% end %}
{% module Template("cards/location.html", web_ui_options=web_ui_options) %} +
+ {% module Template("cards/worked_calls.html", web_ui_options=web_ui_options) %}
- {% module Template("cards/worked_calls.html", web_ui_options=web_ui_options) %} + {% module Template("cards/wanted_calls.html", web_ui_options=web_ui_options) %}
@@ -118,8 +113,8 @@ - - + + diff --git a/templates/status.html b/templates/status.html index c84bdbc..06c74e3 100644 --- a/templates/status.html +++ b/templates/status.html @@ -86,7 +86,7 @@ - +