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 (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(`
`);
});
// 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/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 @@