mirror of
https://github.com/wavelog/wavelog.git
synced 2026-03-22 10:24:14 +00:00
Favorites
This commit is contained in:
@@ -71,4 +71,44 @@ class Bandmap extends CI_Controller {
|
||||
$this->load->view('bandmap/list',$pageData);
|
||||
$this->load->view('interface_assets/footer', $footerData);
|
||||
}
|
||||
|
||||
// Get user's favorite bands and modes (active ones)
|
||||
function get_user_favorites() {
|
||||
$this->load->model('bands');
|
||||
$this->load->model('usermodes');
|
||||
|
||||
// Get active bands
|
||||
$activeBands = $this->bands->get_user_bands_for_qso_entry(false); // false = only active
|
||||
$bandList = [];
|
||||
foreach ($activeBands as $group => $bands) {
|
||||
foreach ($bands as $band) {
|
||||
$bandList[] = $band;
|
||||
}
|
||||
}
|
||||
|
||||
// Get active modes (user-specific) and categorize them
|
||||
$activeModes = $this->usermodes->active();
|
||||
$modeCategories = [
|
||||
'cw' => false,
|
||||
'phone' => false,
|
||||
'digi' => false
|
||||
];
|
||||
|
||||
foreach ($activeModes as $mode) {
|
||||
$qrgmode = strtoupper($mode->qrgmode ?? '');
|
||||
if ($qrgmode === 'CW') {
|
||||
$modeCategories['cw'] = true;
|
||||
} elseif ($qrgmode === 'SSB') {
|
||||
$modeCategories['phone'] = true;
|
||||
} elseif ($qrgmode === 'DATA') {
|
||||
$modeCategories['digi'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode([
|
||||
'bands' => $bandList,
|
||||
'modes' => $modeCategories
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,50 +531,42 @@
|
||||
|
||||
<!-- Filters Section with darker background and rounded corners -->
|
||||
<div class="menu-bar">
|
||||
<!-- First Row: Band Filters, Mode Filters, and Continent Filters -->
|
||||
<div class="d-flex flex-wrap align-items-center gap-2 mb-2">
|
||||
<!-- First Row: Band Filters, Mode Filters, and Continent Filters -->
|
||||
<div class="d-flex flex-wrap align-items-center gap-2 mb-2">
|
||||
<!-- Favorites Button (left of band buttons) -->
|
||||
<div class="btn-group flex-shrink-0" role="group">
|
||||
<button class="btn btn-sm btn-success" type="button" id="toggleFavoritesFilter" title="<?= __("Apply your favorite bands and modes (configured in Band and Mode settings)"); ?>">
|
||||
<i class="fas fa-star"></i> <span class="d-none d-sm-inline"><?= __("My Favorites"); ?></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Band Filter Buttons -->
|
||||
<div class="d-flex flex-wrap gap-2 align-items-center">
|
||||
<?php
|
||||
// Generate band filter buttons grouped by band group
|
||||
// Keep MF and HF as individual buttons, group VHF/UHF/SHF together
|
||||
$vhfUhfShfButtons = [];
|
||||
|
||||
foreach ($bands as $key => $bandgroup) {
|
||||
$groupKey = strtoupper($key);
|
||||
|
||||
// Collect VHF, UHF, SHF for later grouping
|
||||
if (in_array($groupKey, ['VHF', 'UHF', 'SHF'])) {
|
||||
$vhfUhfShfButtons[$groupKey] = $groupKey;
|
||||
} else {
|
||||
// MF and HF bands get individual buttons in their own groups
|
||||
echo '<div class="btn-group flex-shrink-0" role="group">';
|
||||
foreach ($bandgroup as $band) {
|
||||
$bandId = str_replace('.', '', $band); // Remove dots for ID (e.g., 2.5mm -> 25mm)
|
||||
echo '<button class="btn btn-sm btn-primary" type="button" id="toggle' . $bandId . 'Filter" title="' . __("Toggle") . ' ' . $band . ' ' . __("band filter") . '">' . $band . '</button>';
|
||||
}
|
||||
echo '</div>' . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Output VHF/UHF/SHF as one button group
|
||||
if (!empty($vhfUhfShfButtons)) {
|
||||
echo '<div class="btn-group flex-shrink-0" role="group">';
|
||||
foreach ($vhfUhfShfButtons as $groupKey) {
|
||||
echo '<button class="btn btn-sm btn-primary" type="button" id="toggle' . $groupKey . 'Filter" title="' . __("Toggle") . ' ' . $groupKey . ' ' . __("bands filter") . '">' . $groupKey . '</button>';
|
||||
}
|
||||
echo '</div>' . "\n";
|
||||
}
|
||||
|
||||
// Add SAT button
|
||||
echo '<div class="btn-group flex-shrink-0" role="group">';
|
||||
echo '<button class="btn btn-sm btn-primary" type="button" id="toggleSATFilter" title="' . __("Toggle SAT band filter") . '">SAT</button>';
|
||||
echo '</div>' . "\n";
|
||||
?>
|
||||
</div> <!-- Spacer to push modes and continents to the right -->
|
||||
<div class="flex-grow-1"></div>
|
||||
|
||||
|
||||
<!-- MF Band -->
|
||||
<div class="btn-group flex-shrink-0" role="group">
|
||||
<button class="btn btn-sm btn-primary" type="button" id="toggle160mFilter" title="<?= __("Toggle 160m band filter"); ?>">160m</button>
|
||||
</div>
|
||||
<!-- HF Bands -->
|
||||
<div class="btn-group flex-shrink-0" role="group">
|
||||
<button class="btn btn-sm btn-primary" type="button" id="toggle80mFilter" title="<?= __("Toggle 80m band filter"); ?>">80m</button>
|
||||
<button class="btn btn-sm btn-primary" type="button" id="toggle40mFilter" title="<?= __("Toggle 40m band filter"); ?>">40m</button>
|
||||
<button class="btn btn-sm btn-primary" type="button" id="toggle20mFilter" title="<?= __("Toggle 20m band filter"); ?>">20m</button>
|
||||
<button class="btn btn-sm btn-primary" type="button" id="toggle15mFilter" title="<?= __("Toggle 15m band filter"); ?>">15m</button>
|
||||
<button class="btn btn-sm btn-primary" type="button" id="toggle10mFilter" title="<?= __("Toggle 10m band filter"); ?>">10m</button>
|
||||
</div>
|
||||
<!-- WARC Bands -->
|
||||
<div class="btn-group flex-shrink-0" role="group">
|
||||
<button class="btn btn-sm btn-primary" type="button" id="toggleWARCFilter" title="<?= __("Toggle WARC bands filter"); ?>">WARC</button>
|
||||
</div>
|
||||
<!-- VHF/UHF/SHF Bands -->
|
||||
<div class="btn-group flex-shrink-0" role="group">
|
||||
<button class="btn btn-sm btn-primary" type="button" id="toggleVHFFilter" title="<?= __("Toggle VHF bands filter"); ?>">VHF</button>
|
||||
<button class="btn btn-sm btn-primary" type="button" id="toggleUHFFilter" title="<?= __("Toggle UHF bands filter"); ?>">UHF</button>
|
||||
<button class="btn btn-sm btn-primary" type="button" id="toggleSHFFilter" title="<?= __("Toggle SHF bands filter"); ?>">SHF</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Spacer to push modes and continents to the right -->
|
||||
<div class="flex-grow-1"></div>
|
||||
<!-- Mode Filter Buttons -->
|
||||
<div class="d-flex flex-wrap gap-2 align-items-center">
|
||||
<div class="btn-group flex-shrink-0" role="group">
|
||||
@@ -689,21 +681,46 @@
|
||||
<label class="form-label d-block filter-label-small" for="band"><?= __("Band"); ?></label>
|
||||
<select id="band" class="form-select form-select-sm" name="band" multiple="multiple">
|
||||
<option value="All" selected><?= __("All"); ?></option>
|
||||
<?php foreach ($bands as $key => $bandgroup) {
|
||||
echo '<optgroup label="' . strtoupper($key) . '">';
|
||||
foreach ($bandgroup as $band) {
|
||||
echo '<option value="' . $band . '"';
|
||||
echo '>' . $band . '</option>' . "\n";
|
||||
}
|
||||
echo '</optgroup>';
|
||||
}
|
||||
?>
|
||||
<option value="SAT">SAT</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Buttons in popup -->
|
||||
<optgroup label="MF">
|
||||
<option value="160m">160m</option>
|
||||
</optgroup>
|
||||
<optgroup label="HF">
|
||||
<option value="80m">80m</option>
|
||||
<option value="60m">60m</option>
|
||||
<option value="40m">40m</option>
|
||||
<option value="30m">30m</option>
|
||||
<option value="20m">20m</option>
|
||||
<option value="17m">17m</option>
|
||||
<option value="15m">15m</option>
|
||||
<option value="12m">12m</option>
|
||||
<option value="10m">10m</option>
|
||||
</optgroup>
|
||||
<optgroup label="VHF">
|
||||
<option value="6m">6m</option>
|
||||
<option value="4m">4m</option>
|
||||
<option value="2m">2m</option>
|
||||
<option value="1.25m">1.25m</option>
|
||||
</optgroup>
|
||||
<optgroup label="UHF">
|
||||
<option value="70cm">70cm</option>
|
||||
<option value="33cm">33cm</option>
|
||||
<option value="23cm">23cm</option>
|
||||
</optgroup>
|
||||
<optgroup label="SHF">
|
||||
<option value="13cm">13cm</option>
|
||||
<option value="9cm">9cm</option>
|
||||
<option value="6cm">6cm</option>
|
||||
<option value="3cm">3cm</option>
|
||||
<option value="1.25cm">1.25cm</option>
|
||||
<option value="6mm">6mm</option>
|
||||
<option value="4mm">4mm</option>
|
||||
<option value="2.5mm">2.5mm</option>
|
||||
<option value="2mm">2mm</option>
|
||||
<option value="1mm">1mm</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
</div> <!-- Buttons in popup -->
|
||||
<div class="text-center mt-3">
|
||||
<button type="button" class="btn btn-sm btn-success me-2" id="applyFiltersButtonPopup">
|
||||
<i class="fas fa-check"></i> <?= __("Apply Filters"); ?>
|
||||
|
||||
@@ -179,9 +179,10 @@ $(function() {
|
||||
|
||||
// Band filter buttons - green if All, orange if specific band, blue if not selected
|
||||
// Always update colors, even when CAT Control is enabled (so users can see which band is active)
|
||||
let bandButtons = ['#toggle160mFilter', '#toggle80mFilter', '#toggle60mFilter', '#toggle40mFilter', '#toggle30mFilter',
|
||||
'#toggle20mFilter', '#toggle17mFilter', '#toggle15mFilter', '#toggle12mFilter', '#toggle10mFilter'];
|
||||
let bandIds = ['160m', '80m', '60m', '40m', '30m', '20m', '17m', '15m', '12m', '10m'];
|
||||
// Only include visible individual band buttons (excluding WARC bands and 60m)
|
||||
let bandButtons = ['#toggle160mFilter', '#toggle80mFilter', '#toggle40mFilter',
|
||||
'#toggle20mFilter', '#toggle15mFilter', '#toggle10mFilter'];
|
||||
let bandIds = ['160m', '80m', '40m', '20m', '15m', '10m'];
|
||||
|
||||
bandButtons.forEach((btnId, index) => {
|
||||
let $btn = $(btnId);
|
||||
@@ -195,12 +196,12 @@ $(function() {
|
||||
}
|
||||
});
|
||||
|
||||
// Band group buttons (VHF, UHF, SHF, SAT)
|
||||
// Band group buttons (VHF, UHF, SHF, WARC)
|
||||
let groupButtons = [
|
||||
{ id: '#toggleVHFFilter', group: 'VHF' },
|
||||
{ id: '#toggleUHFFilter', group: 'UHF' },
|
||||
{ id: '#toggleSHFFilter', group: 'SHF' },
|
||||
{ id: '#toggleSATFilter', band: 'SAT' }
|
||||
{ id: '#toggleWARCFilter', group: 'WARC' }
|
||||
];
|
||||
|
||||
groupButtons.forEach(btn => {
|
||||
@@ -210,17 +211,11 @@ $(function() {
|
||||
if (allBandsSelected) {
|
||||
$btn.addClass('btn-success');
|
||||
} else {
|
||||
let isActive = false;
|
||||
if (btn.group) {
|
||||
// Check if any band in the group is selected
|
||||
const groupBands = getBandsInGroup(btn.group);
|
||||
isActive = groupBands.some(b => bandValues.includes(b));
|
||||
} else if (btn.band) {
|
||||
// For SAT, check directly
|
||||
isActive = bandValues.includes(btn.band);
|
||||
}
|
||||
// Check if ALL bands in the group are selected (not just some)
|
||||
const groupBands = getBandsInGroup(btn.group);
|
||||
const allGroupBandsSelected = groupBands.every(b => bandValues.includes(b));
|
||||
|
||||
if (isActive) {
|
||||
if (allGroupBandsSelected) {
|
||||
$btn.addClass('btn-warning');
|
||||
} else {
|
||||
$btn.addClass('btn-primary');
|
||||
@@ -320,6 +315,11 @@ $(function() {
|
||||
}
|
||||
|
||||
updateFilterIcon();
|
||||
|
||||
// Sync button states when band, mode, or continent filters change
|
||||
if (selectId === 'band' || selectId === 'mode' || selectId === 'decontSelect' || selectId === 'continentSelect') {
|
||||
syncQuickFilterButtons();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -715,16 +715,20 @@ $(function() {
|
||||
}
|
||||
if (!passesCwnFilter) return;
|
||||
|
||||
// Apply band filter (client-side for multi-select)
|
||||
let passesBandFilter = bands.includes('All');
|
||||
if (!passesBandFilter) {
|
||||
// Check if spot has band field (for SAT), otherwise determine from frequency
|
||||
let spot_band = single.band || getBandFromFrequency(single.frequency);
|
||||
passesBandFilter = bands.includes(spot_band);
|
||||
}
|
||||
if (!passesBandFilter) return;
|
||||
// Apply band filter (client-side for multi-select)
|
||||
let passesBandFilter = bands.includes('All');
|
||||
if (!passesBandFilter) {
|
||||
// Check if spot has band field set, otherwise determine from frequency
|
||||
let spot_band = single.band;
|
||||
|
||||
// Apply de continent filter (which continent the spotter is in)
|
||||
// If no band field, try to determine from frequency
|
||||
if (!spot_band) {
|
||||
spot_band = getBandFromFrequency(single.frequency);
|
||||
}
|
||||
|
||||
passesBandFilter = bands.includes(spot_band);
|
||||
}
|
||||
if (!passesBandFilter) return; // Apply de continent filter (which continent the spotter is in)
|
||||
// When multiple de continents are selected, fetch 'Any' from backend and filter client-side
|
||||
let passesDeContFilter = deContinent.includes('Any');
|
||||
if (!passesDeContFilter && single.dxcc_spotter && single.dxcc_spotter.cont) {
|
||||
@@ -1014,29 +1018,35 @@ $(function() {
|
||||
let modeCounts = { cw: 0, digi: 0, phone: 0 };
|
||||
let totalSpots = 0;
|
||||
|
||||
cachedSpotData.forEach((spot) => {
|
||||
// Count by band
|
||||
let freq_khz = spot.frequency;
|
||||
let band = spot.band || getBandFromFrequency(freq_khz);
|
||||
if (band) {
|
||||
bandCounts[band] = (bandCounts[band] || 0) + 1;
|
||||
totalSpots++;
|
||||
}
|
||||
cachedSpotData.forEach((spot) => {
|
||||
// Count by band
|
||||
let freq_khz = spot.frequency;
|
||||
let band = spot.band;
|
||||
|
||||
// Count by mode
|
||||
let modeCategory = getModeCategory(spot.mode);
|
||||
if (modeCategory && modeCounts.hasOwnProperty(modeCategory)) {
|
||||
modeCounts[modeCategory]++;
|
||||
}
|
||||
});
|
||||
// If no band field, try to determine from frequency
|
||||
if (!band) {
|
||||
band = getBandFromFrequency(freq_khz);
|
||||
}
|
||||
|
||||
// Count band groups (VHF, UHF, SHF, SAT)
|
||||
let groupCounts = {
|
||||
'VHF': 0,
|
||||
'UHF': 0,
|
||||
'SHF': 0,
|
||||
'SAT': 0
|
||||
};
|
||||
if (band) {
|
||||
bandCounts[band] = (bandCounts[band] || 0) + 1;
|
||||
totalSpots++;
|
||||
}
|
||||
|
||||
// Count by mode
|
||||
let modeCategory = getModeCategory(spot.mode);
|
||||
if (modeCategory && modeCounts.hasOwnProperty(modeCategory)) {
|
||||
modeCounts[modeCategory]++;
|
||||
}
|
||||
});
|
||||
|
||||
// Count band groups (VHF, UHF, SHF, WARC)
|
||||
let groupCounts = {
|
||||
'VHF': 0,
|
||||
'UHF': 0,
|
||||
'SHF': 0,
|
||||
'WARC': 0
|
||||
};
|
||||
|
||||
Object.keys(bandCounts).forEach(band => {
|
||||
let group = getBandGroup(band);
|
||||
@@ -1045,10 +1055,9 @@ $(function() {
|
||||
}
|
||||
});
|
||||
|
||||
// Update individual MF/HF band button badges
|
||||
// Update individual MF/HF band button badges (excluding WARC and 60m which are grouped/hidden)
|
||||
const mfHfBands = [
|
||||
'160m', '80m', '60m', '40m', '30m', '20m',
|
||||
'17m', '15m', '12m', '10m'
|
||||
'160m', '80m', '40m', '20m', '15m', '10m'
|
||||
];
|
||||
|
||||
mfHfBands.forEach(band => {
|
||||
@@ -1063,8 +1072,8 @@ $(function() {
|
||||
}
|
||||
});
|
||||
|
||||
// Update band group button badges (VHF, UHF, SHF, SAT)
|
||||
['VHF', 'UHF', 'SHF', 'SAT'].forEach(group => {
|
||||
// Update band group button badges (VHF, UHF, SHF, WARC)
|
||||
['VHF', 'UHF', 'SHF', 'WARC'].forEach(group => {
|
||||
let count = groupCounts[group] || 0;
|
||||
let $badge = $('#toggle' + group + 'Filter .band-count-badge');
|
||||
if ($badge.length === 0) {
|
||||
@@ -1237,26 +1246,27 @@ $(function() {
|
||||
return 'All';
|
||||
}
|
||||
|
||||
// Map individual bands to their band groups (VHF, UHF, SHF)
|
||||
// Map individual bands to their band groups (VHF, UHF, SHF, WARC)
|
||||
function getBandGroup(band) {
|
||||
const VHF_BANDS = ['6m', '4m', '2m'];
|
||||
const UHF_BANDS = ['1.25m', '70cm', '33cm', '23cm'];
|
||||
const VHF_BANDS = ['6m', '4m', '2m', '1.25m'];
|
||||
const UHF_BANDS = ['70cm', '33cm', '23cm'];
|
||||
const SHF_BANDS = ['13cm', '9cm', '6cm', '3cm', '1.25cm', '6mm', '4mm', '2.5mm', '2mm', '1mm'];
|
||||
const WARC_BANDS = ['30m', '17m', '12m'];
|
||||
|
||||
if (VHF_BANDS.includes(band)) return 'VHF';
|
||||
if (UHF_BANDS.includes(band)) return 'UHF';
|
||||
if (SHF_BANDS.includes(band)) return 'SHF';
|
||||
if (band === 'SAT') return 'SAT';
|
||||
if (WARC_BANDS.includes(band)) return 'WARC';
|
||||
return null; // MF/HF bands don't have groups
|
||||
}
|
||||
|
||||
// Get all bands in a band group
|
||||
function getBandsInGroup(group) {
|
||||
const BAND_GROUPS = {
|
||||
'VHF': ['6m', '4m', '2m'],
|
||||
'UHF': ['1.25m', '70cm', '33cm', '23cm'],
|
||||
'VHF': ['6m', '4m', '2m', '1.25m'],
|
||||
'UHF': ['70cm', '33cm', '23cm'],
|
||||
'SHF': ['13cm', '9cm', '6cm', '3cm', '1.25cm', '6mm', '4mm', '2.5mm', '2mm', '1mm'],
|
||||
'SAT': ['SAT']
|
||||
'WARC': ['30m', '17m', '12m']
|
||||
};
|
||||
return BAND_GROUPS[group] || [];
|
||||
}
|
||||
@@ -2166,14 +2176,22 @@ $(function() {
|
||||
applyFilters(false);
|
||||
});
|
||||
|
||||
$('#toggleSATFilter').on('click', function() {
|
||||
$('#toggleWARCFilter').on('click', function() {
|
||||
let currentValues = $('#band').val() || [];
|
||||
if (currentValues.includes('All')) currentValues = currentValues.filter(v => v !== 'All');
|
||||
if (currentValues.includes('SAT')) {
|
||||
currentValues = currentValues.filter(v => v !== 'SAT');
|
||||
|
||||
const warcBands = getBandsInGroup('WARC');
|
||||
const hasAllWARC = warcBands.every(b => currentValues.includes(b));
|
||||
|
||||
if (hasAllWARC) {
|
||||
// Remove all WARC bands
|
||||
currentValues = currentValues.filter(v => !warcBands.includes(v));
|
||||
if (currentValues.length === 0) currentValues = ['All'];
|
||||
} else {
|
||||
currentValues.push('SAT');
|
||||
// Add all WARC bands
|
||||
warcBands.forEach(b => {
|
||||
if (!currentValues.includes(b)) currentValues.push(b);
|
||||
});
|
||||
}
|
||||
$('#band').val(currentValues).trigger('change');
|
||||
syncQuickFilterButtons();
|
||||
@@ -2450,6 +2468,48 @@ $(function() {
|
||||
applyFilters(false);
|
||||
});
|
||||
|
||||
// Toggle Favorites filter - applies user's active bands and modes
|
||||
$('#toggleFavoritesFilter').on('click', function() {
|
||||
// Fetch user's active bands and modes
|
||||
let base_url = dxcluster_provider.replace('/dxcluster', '');
|
||||
$.ajax({
|
||||
url: base_url + '/bandmap/get_user_favorites',
|
||||
method: 'GET',
|
||||
dataType: 'json',
|
||||
success: function(favorites) {
|
||||
// Apply 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
|
||||
let activeModes = [];
|
||||
if (favorites.modes.cw) activeModes.push('cw');
|
||||
if (favorites.modes.phone) activeModes.push('phone');
|
||||
if (favorites.modes.digi) activeModes.push('digi');
|
||||
|
||||
if (activeModes.length > 0) {
|
||||
$('#mode').val(activeModes).trigger('change');
|
||||
} else {
|
||||
// No active modes, filter out everything (or set to All if you prefer)
|
||||
$('#mode').val(['All']).trigger('change');
|
||||
}
|
||||
|
||||
// Sync button states and apply filters
|
||||
syncQuickFilterButtons();
|
||||
applyFilters(false);
|
||||
|
||||
showToast('My Favorites', 'Applied your favorite bands and modes', 'bg-success text-white', 3000);
|
||||
},
|
||||
error: function() {
|
||||
showToast('My Favorites', 'Failed to load favorites', 'bg-danger text-white', 3000);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ========================================
|
||||
// CAT CONTROL - BAND FILTER LOCK
|
||||
// ========================================
|
||||
|
||||
Reference in New Issue
Block a user