Fix for ref population

This commit is contained in:
Szymon Porwolik
2025-11-20 16:48:42 +01:00
parent 28c317551d
commit 4c4f4e2c64

View File

@@ -655,83 +655,121 @@ 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;
if (!refs) {
return;
// Uses Map-based storage with sequence validation to prevent race conditions
function populatePendingReferences(callsign, expectedSeq) {
// Handle legacy call without parameters
if (!callsign) {
callsign = $('#callsign').val();
expectedSeq = $('#callsign').data('expected-refs-seq');
}
// POTA - uses selectize
const entry = pendingReferencesMap.get(callsign);
if (!entry) {
console.log('No pending references for callsign:', callsign);
return;
}
// Validate sequence to prevent stale data
if (expectedSeq && entry.seq !== expectedSeq) {
console.warn('Sequence mismatch - ignoring stale references', {
callsign: callsign,
expected: expectedSeq,
actual: entry.seq
});
return;
}
// Mark as populated to prevent double-population
if (entry.populated) {
console.warn('References already populated for', callsign);
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
}
} 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
}
} 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
}
} 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');
}
}, 100); // Small delay to let form settle
// Cleanup after successful population
setTimeout(function() {
pendingReferencesMap.delete(callsign);
}, 5000); // Keep for 5 seconds in case of retry
}
var bc = new BroadcastChannel('qso_wish');
@@ -746,21 +784,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) {
@@ -775,7 +827,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);
@@ -1057,9 +1113,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("");