diff --git a/application/models/Dxcluster_model.php b/application/models/Dxcluster_model.php index d3bea2b1e..3033af399 100644 --- a/application/models/Dxcluster_model.php +++ b/application/models/Dxcluster_model.php @@ -563,18 +563,35 @@ class Dxcluster_model extends CI_Model { // Contest detection - use class property instead of creating array each time if (!$spot->dxcc_spotted->isContest) { - // Check for contest keywords using optimized strpbrk-like approach + // More strict contest detection - require clear indicators + + // Method 1: Explicit contest keywords with word boundaries foreach ($this->contestIndicators as $indicator) { - if (strpos($upperMessage, $indicator) !== false) { + // Use word boundary to avoid matching "CQ DX" in "CQ DX Americas" (which is just a CQ call) + if (preg_match('/\b' . preg_quote($indicator, '/') . '\b/', $upperMessage)) { + // Additional check: avoid false positives from generic "CQ" messages + if ($indicator === 'DX CONTEST' && preg_match('/^CQ\s+DX\s+[A-Z]+$/i', trim($message))) { + continue; // Skip "CQ DX " patterns + } $spot->dxcc_spotted->isContest = true; - return $spot; // Early exit once contest detected + $spot->dxcc_spotted->contestName = $indicator; + return $spot; } } - // Additional heuristic: Check for typical contest exchange patterns - // Match RST + serial number patterns OR zone/state exchanges in single regex - if (preg_match('/\b(?:(?:599|59|5NN)\s+[0-9A-Z]{2,4}|CQ\s+[0-9A-Z]{1,3})\b/', $upperMessage)) { - $spot->dxcc_spotted->isContest = true; + // Method 2: Contest exchange pattern - must have RST AND serial AND no conversational words + // Exclude spots with conversational indicators (TU, TNX, 73, GL, etc.) + $conversational = '/\b(TU|TNX|THANKS|73|GL|HI|FB|CUL|HPE|PSE|DE)\b/'; + + if (!preg_match($conversational, $upperMessage)) { + // Look for typical contest exchange: RST + number (but not just any 599) + // Must be followed by more structured exchange (not just "ur 599") + if (preg_match('/\b(?:599|5NN)\s+(?:TU\s+)?[0-9]{2,4}\b/', $upperMessage) && + !preg_match('/\bUR\s+599\b/', $upperMessage)) { + $spot->dxcc_spotted->isContest = true; + $spot->dxcc_spotted->contestName = 'CONTEST'; + return $spot; + } } } diff --git a/assets/css/bandmap_list.css b/assets/css/bandmap_list.css index 7b540bb33..ca6a14641 100644 --- a/assets/css/bandmap_list.css +++ b/assets/css/bandmap_list.css @@ -537,9 +537,51 @@ table tbody tr.cat-nearest-above td { margin: 0 0 0.5rem 0 !important; } +/* Override status bar wrapper constraints in fullscreen - keep it sharing row with search */ +.bandmap-fullscreen .menu-bar > div > div[style*="max-width: 70%"] { + max-width: none !important; + flex: 1 1 auto !important; + min-width: 400px !important; + display: flex !important; + align-items: center !important; +} + .bandmap-fullscreen .status-bar { flex: 0 0 auto; - margin: 0 0 0.5rem 0 !important; + margin: 0 !important; + width: 100% !important; + padding: 0.25rem 0.5rem !important; + display: flex; + align-items: center; + min-height: calc(1.5em + 0.5rem + 2px); + line-height: 1.5; +} + +/* Override parent container max-width in fullscreen */ +.bandmap-fullscreen .status-bar { + max-width: 100% !important; +} + +.bandmap-fullscreen .status-bar-inner { + display: flex; + align-items: center; + justify-content: space-between; + gap: 15px; + flex-wrap: nowrap; +} + +.bandmap-fullscreen .status-bar-left { + flex: 1 1 auto; + min-width: 0; + white-space: normal !important; + overflow: visible !important; + text-overflow: clip !important; +} + +.bandmap-fullscreen .status-bar-right { + flex: 0 0 auto; + min-width: 150px; + white-space: nowrap; } .bandmap-fullscreen .table-responsive { diff --git a/assets/js/sections/bandmap_list.js b/assets/js/sections/bandmap_list.js index 2502d66f9..e950006c1 100644 --- a/assets/js/sections/bandmap_list.js +++ b/assets/js/sections/bandmap_list.js @@ -1976,10 +1976,13 @@ data[0].push((single.dxcc_spotter && single.dxcc_spotter.cqz) ? single.dxcc_spot }); $("#clearFiltersButton").on("click", function() { + // Preserve current band selection if CAT Control is enabled + let currentBand = isCatTrackingEnabled ? $('#band').val() : null; + $('#cwnSelect').val(['All']); $('#decontSelect').val(['Any']); $('#continentSelect').val(['Any']); - $('#band').val(['All']); + $('#band').val(currentBand || ['All']); // Preserve band if CAT is enabled $('#mode').val(['All']); $('#additionalFlags').val(['All']); $('#requiredFlags').val([]); @@ -2001,17 +2004,23 @@ data[0].push((single.dxcc_spotter && single.dxcc_spotter.cqz) ? single.dxcc_spot updateFilterIcon(); applyFilters(true); $('#filterDropdown').dropdown('hide'); + + if (isCatTrackingEnabled && typeof showToast === 'function') { + showToast('Clear Filters', 'Band filter preserved (CAT Control is active)', 'bg-info text-white', 2000); + } }); // Clear Filters Quick Button (preserves De Continent) $("#clearFiltersButtonQuick").on("click", function() { // Preserve current De Continent selection let currentDecont = $('#decontSelect').val(); + // Preserve current band selection if CAT Control is enabled + let currentBand = isCatTrackingEnabled ? $('#band').val() : null; // Reset all other filters $('#cwnSelect').val(['All']).trigger('change'); $('#continentSelect').val(['Any']).trigger('change'); - $('#band').val(['All']).trigger('change'); + $('#band').val(currentBand || ['All']).trigger('change'); // Preserve band if CAT is enabled $('#mode').val(['All']).trigger('change'); $('#additionalFlags').val(['All']).trigger('change'); $('#requiredFlags').val([]).trigger('change'); @@ -2026,6 +2035,10 @@ data[0].push((single.dxcc_spotter && single.dxcc_spotter.cqz) ? single.dxcc_spot syncQuickFilterButtons(); updateFilterIcon(); applyFilters(false); // Don't refetch from server since De Continent is preserved + + if (isCatTrackingEnabled && typeof showToast === 'function') { + showToast('Clear Filters', 'Band filter preserved (CAT Control is active)', 'bg-info text-white', 2000); + } }); // Sync button states when dropdown is shown @@ -2065,27 +2078,27 @@ data[0].push((single.dxcc_spotter && single.dxcc_spotter.cqz) ? single.dxcc_spot $("#radio").on("change", function() { let selectedRadio = $(this).val(); - + // If "None" (value "0") is selected, automatically disable CAT Control if (selectedRadio === "0") { console.log('Radio set to None - automatically disabling CAT Control'); - + // If CAT Control is currently enabled, turn it off if (isCatTrackingEnabled) { let btn = $('#toggleCatTracking'); btn.removeClass('btn-success').addClass('btn-secondary'); isCatTrackingEnabled = false; window.isCatTrackingEnabled = false; - + // Hide radio status $('#radio_cat_state').remove(); - + // Re-enable band filter controls enableBandFilterControls(); - + // Unlock table sorting unlockTableSorting(); - + // Reset band filter to 'All' and fetch all bands const currentBands = $("#band").val() || []; if (currentBands.length !== 1 || currentBands[0] !== 'All') { @@ -2095,7 +2108,7 @@ data[0].push((single.dxcc_spotter && single.dxcc_spotter.cqz) ? single.dxcc_spot syncQuickFilterButtons(); applyFilters(true); // Force reload to fetch all bands } - + if (typeof showToast === 'function') { showToast('Radio', 'Radio set to None - CAT Control disabled', 'bg-info text-white', 3000); } @@ -3462,12 +3475,21 @@ data[0].push((single.dxcc_spotter && single.dxcc_spotter.cqz) ? single.dxcc_spot * Apply user favorites to band and mode filters */ function applyUserFavorites(favorites) { - // Apply bands - if (favorites.bands && favorites.bands.length > 0) { - $('#band').val(favorites.bands).trigger('change'); + // Apply bands - but preserve current band if CAT Control is enabled + if (isCatTrackingEnabled) { + // CAT Control is active - don't change band filter + console.log('CAT Control is active - skipping band filter change from favorites'); + if (typeof showToast === 'function') { + showToast('My Favorites', 'Modes applied. Band filter preserved (CAT Control is active)', 'bg-info text-white', 3000); + } } else { - // No active bands, set to All - $('#band').val(['All']).trigger('change'); + // CAT Control is off - apply favorite bands + if (favorites.bands && favorites.bands.length > 0) { + $('#band').val(favorites.bands).trigger('change'); + } else { + // No active bands, set to All + $('#band').val(['All']).trigger('change'); + } } // Apply modes