diff --git a/application/views/bandmap/list.php b/application/views/bandmap/list.php
index e3cfd5ceb..bb88466ab 100644
--- a/application/views/bandmap/list.php
+++ b/application/views/bandmap/list.php
@@ -113,6 +113,9 @@
var lang_bandmap_spot = "= __("spot"); ?>";
var lang_bandmap_spotters = "= __("spotters"); ?>";
+ // QSO preparation debounce messages
+ var lang_bandmap_please_wait = "= __("Please Wait"); ?>";
+ var lang_bandmap_wait_before_send = "= __("Please wait %s seconds before sending another callsign to the QSO form"); ?>";
// DataTables messages
var lang_bandmap_loading_spots = "= __("Loading spots..."); ?>";
@@ -518,7 +521,6 @@
"> |
"> |
">= __("Entity"); ?> |
- "> |
">= __("de"); ?> |
"> |
"> |
diff --git a/assets/css/bandmap_list.css b/assets/css/bandmap_list.css
index 5ee5a46c5..fbfc4580b 100644
--- a/assets/css/bandmap_list.css
+++ b/assets/css/bandmap_list.css
@@ -342,22 +342,21 @@ table tbody tr.cat-nearest-above td {
/* Column widths - consolidated selectors */
.spottable th:nth-child(1), .spottable td:nth-child(1) { width: 50px; } /* Age (minutes) */
-.spottable th:nth-child(2), .spottable td:nth-child(2) { width: 53px; } /* Band */
+.spottable th:nth-child(2), .spottable td:nth-child(2) { width: 75px; } /* Band */
.spottable th:nth-child(3), .spottable td:nth-child(3) { width: 90px; } /* Frequency */
-.spottable th:nth-child(4), .spottable td:nth-child(4) { width: 60px; } /* Mode */
-.spottable th:nth-child(5), .spottable td:nth-child(5) { width: 70px; } /* Submode */
-.spottable th:nth-child(6), .spottable td:nth-child(6) { width: 115px; } /* Callsign (reduced by 5px) */
+.spottable th:nth-child(4), .spottable td:nth-child(4) { width: 70px; } /* Mode */
+.spottable th:nth-child(5), .spottable td:nth-child(5) { width: 60px; } /* Submode */
+.spottable th:nth-child(6), .spottable td:nth-child(6) { width: 115px; } /* Callsign */
.spottable th:nth-child(7), .spottable td:nth-child(7) { width: 40px; } /* Continent */
.spottable th:nth-child(8), .spottable td:nth-child(8) { width: 50px; } /* CQ Zone */
.spottable th:nth-child(9), .spottable td:nth-child(9) { width: 50px; } /* Flag */
.spottable th:nth-child(10), .spottable td:nth-child(10) { width: 150px; } /* Entity (DXCC name) */
-.spottable th:nth-child(11), .spottable td:nth-child(11) { width: 60px; } /* DXCC Number */
-.spottable th:nth-child(12), .spottable td:nth-child(12) { width: 115px; } /* de Callsign (Spotter) (reduced by 5px) */
-.spottable th:nth-child(13), .spottable td:nth-child(13) { width: 50px; } /* de Cont */
-.spottable th:nth-child(14), .spottable td:nth-child(14) { width: 50px; } /* de CQZ */
-.spottable th:nth-child(15), .spottable td:nth-child(15) { width: 95px; } /* Last QSO */
-.spottable th:nth-child(16), .spottable td:nth-child(16) { width: 120px; } /* Special (LoTW, POTA, etc) (increased by 10px) */
-.spottable th:nth-child(17), .spottable td:nth-child(17) { min-width: 70px; width: 100%; } /* Message - fills remaining space */
+.spottable th:nth-child(11), .spottable td:nth-child(11) { width: 115px; } /* de Callsign (Spotter) */
+.spottable th:nth-child(12), .spottable td:nth-child(12) { width: 50px; } /* de Cont */
+.spottable th:nth-child(13), .spottable td:nth-child(13) { width: 50px; } /* de CQZ */
+.spottable th:nth-child(14), .spottable td:nth-child(14) { width: 100px; } /* Last QSO */
+.spottable th:nth-child(15), .spottable td:nth-child(15) { width: 135px; } /* Special (LoTW, POTA, etc) */
+.spottable th:nth-child(16), .spottable td:nth-child(16) { min-width: 70px; width: 100%; } /* Message - fills remaining space */
/* Hidden class for responsive columns (controlled by JavaScript) */
.spottable .column-hidden {
diff --git a/assets/js/sections/bandmap_list.js b/assets/js/sections/bandmap_list.js
index cf0854d1e..767fda665 100644
--- a/assets/js/sections/bandmap_list.js
+++ b/assets/js/sections/bandmap_list.js
@@ -16,6 +16,7 @@
// ========================================
const SPOT_REFRESH_INTERVAL = 60; // Auto-refresh interval in seconds
+const QSO_SEND_DEBOUNCE_MS = 3000; // Debounce for sending callsign to QSO form (milliseconds)
// Mode display capitalization lookup (API returns lowercase)
const MODE_CAPITALIZATION = { 'phone': 'Phone', 'cw': 'CW', 'digi': 'Digi' };
@@ -130,7 +131,7 @@ $(function() {
// Also log which row/column caused the issue
if (message.indexOf('parameter') !== -1) {
console.error('This usually means the data array has wrong number of columns');
- console.error('Expected columns: 16 (Age, Band, Freq, Mode, Spotted, Cont, CQZ, Flag, Entity, DXCC#, Spotter, de Cont, de CQZ, Last QSO, Special, Message)');
+ console.error('Expected columns: 16 (Age, Band, Freq, Mode, Submode, Spotted, Cont, CQZ, Flag, Entity, Spotter, de Cont, de CQZ, Last QSO, Special, Message)');
}
};
} else {
@@ -488,7 +489,7 @@ $(function() {
}
},
{
- 'targets': [5, 6, 9, 16], // Submode, Cont, Flag, Message - disable sorting
+ 'targets': [4, 6, 8, 15], // Submode, Cont, Flag, Message - disable sorting
'orderable': false
}
],
@@ -1123,11 +1124,6 @@ $(function() {
data[0].push(entity_colored);
}
- // DXCC Number column: show ADIF DXCC entity number with color coding
- let dxcc_id_value = (single.dxcc_spotted && single.dxcc_spotted.dxcc_id) ? single.dxcc_spotted.dxcc_id : '';
- let dxcc_number = dxcc_id_value ? ((dxcc_wked_info != '' ? '' : '') + dxcc_id_value + (dxcc_wked_info != '' ? '' : '')) : '';
- data[0].push(dxcc_number);
-
// de Callsign column (Spotter) - clickable callstats link
let spotterCallstatsLink = '' + single.spotter + '';
data[0].push(spotterCallstatsLink);
@@ -1155,17 +1151,26 @@ $(function() {
// Special column: combine medals, LoTW and activity badges
let flags_column = medals + lotw_badge + activity_flags;
- data[0].push(flags_column); // Message column
- data[0].push(single.message || '');
+ data[0].push(flags_column);
- // Debug: Validate data array has exactly 17 columns
- if (data[0].length !== 17) {
- console.error('INVALID DATA ARRAY LENGTH:', data[0].length, 'Expected: 17');
+ // Message column: add tooltip with full message text
+ let message = single.message || '';
+ let messageDisplay = message;
+ if (message) {
+ // Escape HTML for tooltip to prevent XSS
+ let messageTooltip = message.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''');
+ messageDisplay = '' + message + '';
+ }
+ data[0].push(messageDisplay);
+
+ // Debug: Validate data array has exactly 16 columns
+ if (data[0].length !== 16) {
+ console.error('INVALID DATA ARRAY LENGTH:', data[0].length, 'Expected: 16');
console.error('Spot:', single.spotted, 'Frequency:', single.frequency);
console.error('Data array:', data[0]);
- console.error('Missing columns:', 17 - data[0].length);
+ console.error('Missing columns:', 16 - data[0].length);
// Pad array with empty strings to prevent DataTables error
- while (data[0].length < 17) {
+ while (data[0].length < 16) {
data[0].push('');
}
}
@@ -1245,33 +1250,34 @@ $(function() {
$(this).attr('title', lang_click_to_prepare_logging);
});
- // Initialize tooltips with error handling
- try {
- $('[data-bs-toggle="tooltip"]').each(function() {
- if (!this || !$(this).attr('title')) return;
+ // Initialize tooltips with error handling
+ try {
+ $('[data-bs-toggle="tooltip"]').each(function() {
+ if (!this || !$(this).attr('title')) return;
- try {
- // Dispose existing tooltip instance if it exists
- const existingTooltip = bootstrap.Tooltip.getInstance(this);
- if (existingTooltip) {
- existingTooltip.dispose();
- }
-
- // Create new tooltip instance
- new bootstrap.Tooltip(this, {
- boundary: 'window',
- trigger: 'hover',
- sanitize: false
- });
- } catch (err) {
- // Skip if tooltip fails to initialize
+ try {
+ // Dispose existing tooltip instance if it exists
+ const existingTooltip = bootstrap.Tooltip.getInstance(this);
+ if (existingTooltip) {
+ existingTooltip.dispose();
}
- });
- } catch (e) {
- // Fallback if tooltip initialization fails
- }
- let displayedCount = spots2render || 0;
+ // Create new tooltip instance with proper configuration
+ new bootstrap.Tooltip(this, {
+ boundary: 'window',
+ trigger: 'hover',
+ sanitize: false,
+ html: false,
+ animation: true,
+ delay: { show: 100, hide: 100 }
+ });
+ } catch (err) {
+ // Skip if tooltip fails to initialize
+ }
+ });
+ } catch (e) {
+ // Fallback if tooltip initialization fails
+ } let displayedCount = spots2render || 0;
// Update band count badges after rendering
updateBandCountBadges();
@@ -2113,7 +2119,27 @@ $(function() {
}
}
+ // Track last QSO send time for debouncing
+ let lastQsoSendTime = 0;
+
function prepareLogging(call, qrg, mode, spotData) {
+ // Debounce check - prevent sending too quickly
+ const now = Date.now();
+ const timeSinceLastSend = now - lastQsoSendTime;
+
+ if (timeSinceLastSend < QSO_SEND_DEBOUNCE_MS) {
+ const remainingSeconds = Math.ceil((QSO_SEND_DEBOUNCE_MS - timeSinceLastSend) / 1000);
+ // Use translation with placeholder replacement
+ const message = lang_bandmap_wait_before_send.replace('%s', remainingSeconds);
+ if (typeof showToast === 'function') {
+ showToast(lang_bandmap_please_wait, message, 'bg-warning text-dark', 3000);
+ }
+ return; // Don't proceed with sending
+ }
+
+ // Update last send time
+ lastQsoSendTime = now;
+
let ready_listener = true;
// If CAT Control is enabled, tune the radio to the spot frequency
@@ -3092,8 +3118,8 @@ $(function() {
$('.spottable').removeClass('cat-sorting-locked');
// Re-enable sorting on all columns that were originally sortable
- // Based on columnDefs: columns 5, 6, 9, 16 are not sortable (Submode, Cont, Flag, Message)
- const nonSortableColumns = [5, 6, 9, 16];
+ // Based on columnDefs: columns 4, 6, 8, 15 are not sortable (Submode, Cont, Flag, Message)
+ const nonSortableColumns = [4, 6, 8, 15];
table.settings()[0].aoColumns.forEach(function(col, index) {
if (!nonSortableColumns.includes(index)) {
@@ -3343,41 +3369,37 @@ $(function() {
$('.spottable th:nth-child(7), .spottable td:nth-child(7)').addClass('column-hidden'); // Continent
$('.spottable th:nth-child(8), .spottable td:nth-child(8)').addClass('column-hidden'); // CQZ
$('.spottable th:nth-child(9), .spottable td:nth-child(9)').addClass('column-hidden'); // Flag
- $('.spottable th:nth-child(11), .spottable td:nth-child(11)').addClass('column-hidden'); // DXCC
- $('.spottable th:nth-child(12), .spottable td:nth-child(12)').addClass('column-hidden'); // de Callsign
- $('.spottable th:nth-child(13), .spottable td:nth-child(13)').addClass('column-hidden'); // de Cont
- $('.spottable th:nth-child(14), .spottable td:nth-child(14)').addClass('column-hidden'); // de CQZ
- $('.spottable th:nth-child(15), .spottable td:nth-child(15)').addClass('column-hidden'); // Last QSO
- $('.spottable th:nth-child(16), .spottable td:nth-child(16)').addClass('column-hidden'); // Special
- $('.spottable th:nth-child(17), .spottable td:nth-child(17)').addClass('column-hidden'); // Message
+ $('.spottable th:nth-child(11), .spottable td:nth-child(11)').addClass('column-hidden'); // de Callsign
+ $('.spottable th:nth-child(12), .spottable td:nth-child(12)').addClass('column-hidden'); // de Cont
+ $('.spottable th:nth-child(13), .spottable td:nth-child(13)').addClass('column-hidden'); // de CQZ
+ $('.spottable th:nth-child(14), .spottable td:nth-child(14)').addClass('column-hidden'); // Last QSO
+ $('.spottable th:nth-child(15), .spottable td:nth-child(15)').addClass('column-hidden'); // Special
+ $('.spottable th:nth-child(16), .spottable td:nth-child(16)').addClass('column-hidden'); // Message
} else if (containerWidth <= 1024) {
- // Hide: DXCC, CQZ, de CQZ, Last QSO, Submode, Band, Cont, de Cont, Flag
+ // Hide: CQZ, de CQZ, Last QSO, Submode, Band, Cont, de Cont, Flag
$('.spottable th:nth-child(2), .spottable td:nth-child(2)').addClass('column-hidden'); // Band
$('.spottable th:nth-child(5), .spottable td:nth-child(5)').addClass('column-hidden'); // Submode
$('.spottable th:nth-child(7), .spottable td:nth-child(7)').addClass('column-hidden'); // Continent
$('.spottable th:nth-child(8), .spottable td:nth-child(8)').addClass('column-hidden'); // CQZ
$('.spottable th:nth-child(9), .spottable td:nth-child(9)').addClass('column-hidden'); // Flag
- $('.spottable th:nth-child(11), .spottable td:nth-child(11)').addClass('column-hidden'); // DXCC
- $('.spottable th:nth-child(13), .spottable td:nth-child(13)').addClass('column-hidden'); // de Cont
- $('.spottable th:nth-child(14), .spottable td:nth-child(14)').addClass('column-hidden'); // de CQZ
- $('.spottable th:nth-child(15), .spottable td:nth-child(15)').addClass('column-hidden'); // Last QSO
+ $('.spottable th:nth-child(12), .spottable td:nth-child(12)').addClass('column-hidden'); // de Cont
+ $('.spottable th:nth-child(13), .spottable td:nth-child(13)').addClass('column-hidden'); // de CQZ
+ $('.spottable th:nth-child(14), .spottable td:nth-child(14)').addClass('column-hidden'); // Last QSO
} else if (containerWidth <= 1294) {
- // Hide: DXCC, CQZ, de CQZ, Last QSO, Submode, Band, Cont, de Cont
+ // Hide: CQZ, de CQZ, Last QSO, Submode, Band, Cont, de Cont
$('.spottable th:nth-child(2), .spottable td:nth-child(2)').addClass('column-hidden'); // Band
$('.spottable th:nth-child(5), .spottable td:nth-child(5)').addClass('column-hidden'); // Submode
$('.spottable th:nth-child(7), .spottable td:nth-child(7)').addClass('column-hidden'); // Continent
$('.spottable th:nth-child(8), .spottable td:nth-child(8)').addClass('column-hidden'); // CQZ
- $('.spottable th:nth-child(11), .spottable td:nth-child(11)').addClass('column-hidden'); // DXCC
- $('.spottable th:nth-child(13), .spottable td:nth-child(13)').addClass('column-hidden'); // de Cont
- $('.spottable th:nth-child(14), .spottable td:nth-child(14)').addClass('column-hidden'); // de CQZ
- $('.spottable th:nth-child(15), .spottable td:nth-child(15)').addClass('column-hidden'); // Last QSO
+ $('.spottable th:nth-child(12), .spottable td:nth-child(12)').addClass('column-hidden'); // de Cont
+ $('.spottable th:nth-child(13), .spottable td:nth-child(13)').addClass('column-hidden'); // de CQZ
+ $('.spottable th:nth-child(14), .spottable td:nth-child(14)').addClass('column-hidden'); // Last QSO
} else if (containerWidth <= 1374) {
- // Hide: DXCC, CQZ, de CQZ, Last QSO, Submode
+ // Hide: CQZ, de CQZ, Last QSO, Submode
$('.spottable th:nth-child(5), .spottable td:nth-child(5)').addClass('column-hidden'); // Submode
$('.spottable th:nth-child(8), .spottable td:nth-child(8)').addClass('column-hidden'); // CQZ
- $('.spottable th:nth-child(11), .spottable td:nth-child(11)').addClass('column-hidden'); // DXCC
- $('.spottable th:nth-child(14), .spottable td:nth-child(14)').addClass('column-hidden'); // de CQZ
- $('.spottable th:nth-child(15), .spottable td:nth-child(15)').addClass('column-hidden'); // Last QSO
+ $('.spottable th:nth-child(13), .spottable td:nth-child(13)').addClass('column-hidden'); // de CQZ
+ $('.spottable th:nth-child(14), .spottable td:nth-child(14)').addClass('column-hidden'); // Last QSO
}
// else: containerWidth > 1374 - show all columns (already reset above)
diff --git a/assets/js/sections/qso.js b/assets/js/sections/qso.js
index 0efdb4eaf..02d78c743 100644
--- a/assets/js/sections/qso.js
+++ b/assets/js/sections/qso.js
@@ -660,83 +660,132 @@ bc_bandmap.onmessage = function (ev) {
}
// Store pending references from bandmap to populate AFTER callsign lookup completes
-var pendingReferences = null;
+// Map structure: callsign -> {seq, refs, timestamp, populated}
+var pendingReferencesMap = new Map();
+var referenceSequence = 0;
// Track last lookup to prevent duplicate calls
var lastLookupCallsign = null;
var lookupInProgress = false;
// Helper function to populate reference fields after callsign lookup completes
-function populatePendingReferences(refsToPopulate) {
- // Use provided references or fall back to global pendingReferences
- var refs = refsToPopulate || pendingReferences;
+// Uses Map-based storage to prevent race conditions
+function populatePendingReferences(callsign, expectedSeq) {
+ // Handle legacy call without parameters
+ if (!callsign) {
+ callsign = $('#callsign').val();
+ }
- if (!refs) {
+ const entry = pendingReferencesMap.get(callsign);
+
+ if (!entry) {
+ // No references for this callsign - this is normal for non-POTA/SOTA/WWFF spots
return;
}
- // POTA - uses selectize
+ // Validate sequence only if expectedSeq was provided
+ // This prevents stale data from being populated
+ if (expectedSeq !== null && expectedSeq !== undefined && entry.seq !== expectedSeq) {
+ console.warn('Sequence mismatch - ignoring stale references', {
+ callsign: callsign,
+ expected: expectedSeq,
+ actual: entry.seq
+ });
+ return;
+ }
+
+ // Check if already populated - prevent double-population for same instance
+ if (entry.populated) {
+ return;
+ }
+ entry.populated = true;
+
+ const refs = entry.refs;
+
+ // POTA - set without triggering change initially (silent = true)
if (refs.pota_ref && $('#pota_ref').length) {
try {
var $select = $('#pota_ref').selectize();
if ($select.length && $select[0].selectize) {
var selectize = $select[0].selectize;
selectize.addOption({name: refs.pota_ref});
- selectize.setValue(refs.pota_ref, false);
- $('#pota_ref').trigger('change');
+ selectize.setValue(refs.pota_ref, true); // Silent = true
+ // Manually show icon since onChange doesn't fire in silent mode
+ if (refs.pota_ref.indexOf(',') === -1) {
+ $('#pota_info').show();
+ $('#pota_info').html('
');
+ $('#pota_info').attr('title', lang_qso_lookup_reference_info.replace('%s', refs.pota_ref).replace('%s', 'pota.co'));
+ }
}
} catch (e) {
console.warn('Could not set POTA reference:', e);
}
}
- // SOTA - uses selectize
+ // SOTA - set without triggering change initially (silent = true)
if (refs.sota_ref && $('#sota_ref').length) {
try {
var $select = $('#sota_ref').selectize();
if ($select.length && $select[0].selectize) {
var selectize = $select[0].selectize;
selectize.addOption({name: refs.sota_ref});
- selectize.setValue(refs.sota_ref, false);
- $('#sota_ref').trigger('change');
+ selectize.setValue(refs.sota_ref, true); // Silent = true
+ // Manually show icon since onChange doesn't fire in silent mode
+ $('#sota_info').show();
+ $('#sota_info').html('
');
+ $('#sota_info').attr('title', lang_qso_lookup_summit_info.replace('%s', refs.sota_ref).replace('%s', 'sota.org.uk'));
}
} catch (e) {
console.warn('Could not set SOTA reference:', e);
}
}
- // WWFF - uses selectize
+ // WWFF - set without triggering change initially (silent = true)
if (refs.wwff_ref && $('#wwff_ref').length) {
try {
var $select = $('#wwff_ref').selectize();
if ($select.length && $select[0].selectize) {
var selectize = $select[0].selectize;
selectize.addOption({name: refs.wwff_ref});
- selectize.setValue(refs.wwff_ref, false);
- $('#wwff_ref').trigger('change');
+ selectize.setValue(refs.wwff_ref, true); // Silent = true
+ // Manually show icon since onChange doesn't fire in silent mode
+ $('#wwff_info').show();
+ $('#wwff_info').html('
');
+ $('#wwff_info').attr('title', lang_qso_lookup_reference_info.replace('%s', refs.wwff_ref).replace('%s', 'cqgma.org'));
}
} catch (e) {
console.warn('Could not set WWFF reference:', e);
}
}
- // IOTA - regular select dropdown (not selectize)
+ // IOTA - set silently (no change trigger yet)
if (refs.iota_ref && $('#iota_ref').length) {
try {
let $iotaSelect = $('#iota_ref');
if ($iotaSelect.find('option[value="' + refs.iota_ref + '"]').length === 0) {
$iotaSelect.append(new Option(refs.iota_ref, refs.iota_ref));
}
- $iotaSelect.val(refs.iota_ref).trigger('change');
+ $iotaSelect.val(refs.iota_ref); // Don't trigger change yet
} catch (e) {
console.warn('Could not set IOTA reference:', e);
}
}
- // Only clear global pendingReferences if we used it (not a captured copy)
- if (!refsToPopulate && pendingReferences) {
- pendingReferences = null;
- }
+ // NOW trigger gridsquare lookup ONLY ONCE for the highest priority reference
+ // Priority: POTA > SOTA > WWFF (most commonly used)
+ // This prevents multiple simultaneous AJAX gridsquare lookups that can race
+ setTimeout(function() {
+ if (refs.pota_ref && $('#pota_ref').length) {
+ $('#pota_ref').trigger('change');
+ } else if (refs.sota_ref && $('#sota_ref').length) {
+ $('#sota_ref').trigger('change');
+ } else if (refs.wwff_ref && $('#wwff_ref').length) {
+ $('#wwff_ref').trigger('change');
+ }
+
+ // Cleanup immediately after triggering - we're done with these references
+ pendingReferencesMap.delete(callsign);
+ }, 100); // Small delay to let form settle
}
var bc = new BroadcastChannel('qso_wish');
@@ -751,21 +800,35 @@ bc.onmessage = function (ev) {
} else {
// Always process frequency, callsign, and reference data from bandmap
// (regardless of manual mode - bandmap should control the form)
+ const callsign = ev.data.call;
+ const seq = ++referenceSequence;
let delay = 0;
// Only reset if callsign is different from what we're about to set
- if ($("#callsign").val() != "" && $("#callsign").val() != ev.data.call) {
+ if ($("#callsign").val() != "" && $("#callsign").val() != callsign) {
reset_fields();
delay = 600;
}
- // Store references for later population (after callsign lookup completes)
- pendingReferences = {
- pota_ref: ev.data.pota_ref,
- sota_ref: ev.data.sota_ref,
- wwff_ref: ev.data.wwff_ref,
- iota_ref: ev.data.iota_ref
- };
+ // Store references with metadata in Map (prevents race conditions)
+ pendingReferencesMap.set(callsign, {
+ seq: seq,
+ refs: {
+ pota_ref: ev.data.pota_ref,
+ sota_ref: ev.data.sota_ref,
+ wwff_ref: ev.data.wwff_ref,
+ iota_ref: ev.data.iota_ref
+ },
+ timestamp: Date.now(),
+ populated: false
+ });
+
+ // Cleanup old entries (> 30 seconds)
+ for (let [key, value] of pendingReferencesMap) {
+ if (Date.now() - value.timestamp > 30000) {
+ pendingReferencesMap.delete(key);
+ }
+ }
setTimeout(() => {
if (ev.data.frequency != null) {
@@ -780,7 +843,11 @@ bc.onmessage = function (ev) {
if (ev.data.mode) {
$("#mode").val(ev.data.mode);
}
- $("#callsign").val(ev.data.call);
+
+ // Store sequence for validation in populatePendingReferences
+ $("#callsign").data('expected-refs-seq', seq);
+
+ $("#callsign").val(callsign);
$("#callsign").focusout();
$("#callsign").blur();
}, delay);
@@ -1062,9 +1129,9 @@ function reset_to_default() {
/* Function: reset_fields is used to reset the fields on the QSO page */
function reset_fields() {
- // we set the pendingReferences to null to avoid they get prefilled in the next QSO after clear
+ // Clear all pending references to avoid they get prefilled in the next QSO after clear
// we do this first to avoid race conditions for slow javascript
- pendingReferences = null;
+ pendingReferencesMap.clear();
$('#locator_info').text("");
$('#comment').val("");
@@ -1216,13 +1283,10 @@ $("#callsign").on("focusout", function () {
lastLookupCallsign = currentCallsign;
lookupInProgress = true;
- // Capture pendingReferences for THIS lookup (before it gets overwritten by another click)
- // If pendingReferences exists, use it; otherwise set to null to prevent old references
- // from being populated when user manually types a different callsign
- var capturedReferences = pendingReferences ? Object.assign({}, pendingReferences) : null;
-
- // Clear pendingReferences immediately after capturing to prevent reuse on next manual lookup
- pendingReferences = null;
+ // Check if we have pending references from bandmap for this callsign
+ // If yes, get the sequence; if no, we'll populate without sequence validation
+ var hasPendingRefs = pendingReferencesMap.has(currentCallsign);
+ var expectedSeq = hasPendingRefs ? pendingReferencesMap.get(currentCallsign).seq : null;
// Disable Save QSO button and show fetch status
$('#saveQso').prop('disabled', true);
@@ -1782,9 +1846,9 @@ $("#callsign").on("focusout", function () {
// Populate pending references from bandmap (after all lookup logic completes)
// Small delay to ensure DOM is fully updated
- // Use the captured references from when THIS lookup started
+ // Use the Map-based approach with the current callsign and expected sequence
setTimeout(function() {
- populatePendingReferences(capturedReferences);
+ populatePendingReferences(currentCallsign, expectedSeq);
}, 100);
}