mirror of
https://github.com/wavelog/wavelog.git
synced 2026-03-22 10:24:14 +00:00
Merge pull request #2607 from szporwolik/dev_fix_dxcluster_favs_and_layout
[DX Cluster] UI improvements post 2.2 release
This commit is contained in:
@@ -1,129 +1,82 @@
|
||||
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
class Bandmap extends CI_Controller {
|
||||
|
||||
function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->load->model('user_model');
|
||||
if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); }
|
||||
$this->load->model('bands');
|
||||
}
|
||||
|
||||
function index() {
|
||||
$this->load->model('cat');
|
||||
$this->load->model('bands');
|
||||
$data['radios'] = $this->cat->radios(true);
|
||||
$data['bands'] = $this->bands->get_user_bands_for_qso_entry();
|
||||
|
||||
$footerData = [];
|
||||
$footerData['scripts'] = [
|
||||
'assets/js/highcharts/highcharts.js',
|
||||
'assets/js/highcharts/timeline.js',
|
||||
'assets/js/highcharts/exporting.js',
|
||||
'assets/js/highcharts/accessibility.js',
|
||||
'assets/js/sections/bandmap.js',
|
||||
];
|
||||
|
||||
$data['page_title'] = __("DXCluster");
|
||||
$this->load->view('interface_assets/header', $data);
|
||||
$this->load->view('bandmap/index');
|
||||
$this->load->view('interface_assets/footer', $footerData);
|
||||
}
|
||||
|
||||
function list() {
|
||||
$this->load->model('cat');
|
||||
$this->load->model('bands');
|
||||
$data['radios'] = $this->cat->radios();
|
||||
$data['radio_last_updated'] = $this->cat->last_updated()->row();
|
||||
$data['bands'] = $this->bands->get_user_bands_for_qso_entry();
|
||||
|
||||
$footerData = [];
|
||||
$footerData['scripts'] = [
|
||||
'assets/js/moment.min.js',
|
||||
'assets/js/datetime-moment.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/datetime-moment.js")),
|
||||
'assets/js/cat.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/cat.js")),
|
||||
'assets/js/leaflet/leaflet.geodesic.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/leaflet/leaflet.geodesic.js")),
|
||||
'assets/js/leaflet.polylineDecorator.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/leaflet.polylineDecorator.js")),
|
||||
'assets/js/leaflet/L.Terminator.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/leaflet/L.Terminator.js")),
|
||||
'assets/js/sections/callstats.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/callstats.js")),
|
||||
'assets/js/sections/bandmap_list.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/bandmap_list.js")),
|
||||
];
|
||||
|
||||
// Get Date format
|
||||
if($this->session->userdata('user_date_format')) {
|
||||
// If Logged in and session exists
|
||||
$pageData['custom_date_format'] = $this->session->userdata('user_date_format');
|
||||
} else {
|
||||
// Get Default date format from /config/wavelog.php
|
||||
$pageData['custom_date_format'] = $this->config->item('qso_date_format');
|
||||
}
|
||||
|
||||
switch ($pageData['custom_date_format']) {
|
||||
case "d/m/y": $pageData['custom_date_format'] = 'DD/MM/YY'; break;
|
||||
case "d/m/Y": $pageData['custom_date_format'] = 'DD/MM/YYYY'; break;
|
||||
case "m/d/y": $pageData['custom_date_format'] = 'MM/DD/YY'; break;
|
||||
case "m/d/Y": $pageData['custom_date_format'] = 'MM/DD/YYYY'; break;
|
||||
case "d.m.Y": $pageData['custom_date_format'] = 'DD.MM.YYYY'; break;
|
||||
case "y/m/d": $pageData['custom_date_format'] = 'YY/MM/DD'; break;
|
||||
case "Y-m-d": $pageData['custom_date_format'] = 'YYYY-MM-DD'; break;
|
||||
case "M d, Y": $pageData['custom_date_format'] = 'MMM DD, YYYY'; break;
|
||||
case "M d, y": $pageData['custom_date_format'] = 'MMM DD, YY'; break;
|
||||
default: $pageData['custom_date_format'] = 'DD/MM/YYYY';
|
||||
}
|
||||
|
||||
$data['page_title'] = __("DXCluster");
|
||||
$this->load->view('interface_assets/header', $data);
|
||||
$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() {
|
||||
session_write_close();
|
||||
|
||||
$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 = [];
|
||||
|
||||
if (is_array($activeBands)) {
|
||||
foreach ($activeBands as $group => $bands) {
|
||||
if (is_array($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
|
||||
];
|
||||
|
||||
if ($activeModes) {
|
||||
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
|
||||
]);
|
||||
}
|
||||
}
|
||||
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
class Bandmap extends CI_Controller {
|
||||
|
||||
function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->load->model('user_model');
|
||||
if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); }
|
||||
$this->load->model('bands');
|
||||
}
|
||||
|
||||
function index() {
|
||||
$this->load->model('cat');
|
||||
$this->load->model('bands');
|
||||
$data['radios'] = $this->cat->radios(true);
|
||||
$data['bands'] = $this->bands->get_user_bands_for_qso_entry();
|
||||
|
||||
$footerData = [];
|
||||
$footerData['scripts'] = [
|
||||
'assets/js/highcharts/highcharts.js',
|
||||
'assets/js/highcharts/timeline.js',
|
||||
'assets/js/highcharts/exporting.js',
|
||||
'assets/js/highcharts/accessibility.js',
|
||||
'assets/js/sections/bandmap.js',
|
||||
];
|
||||
|
||||
$data['page_title'] = __("DXCluster");
|
||||
$this->load->view('interface_assets/header', $data);
|
||||
$this->load->view('bandmap/index');
|
||||
$this->load->view('interface_assets/footer', $footerData);
|
||||
}
|
||||
|
||||
function list() {
|
||||
$this->load->model('cat');
|
||||
$this->load->model('bands');
|
||||
$data['radios'] = $this->cat->radios();
|
||||
$data['radio_last_updated'] = $this->cat->last_updated()->row();
|
||||
$data['bands'] = $this->bands->get_user_bands_for_qso_entry();
|
||||
|
||||
$footerData = [];
|
||||
$footerData['scripts'] = [
|
||||
'assets/js/moment.min.js',
|
||||
'assets/js/datetime-moment.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/datetime-moment.js")),
|
||||
'assets/js/cat.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/cat.js")),
|
||||
'assets/js/leaflet/leaflet.geodesic.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/leaflet/leaflet.geodesic.js")),
|
||||
'assets/js/leaflet.polylineDecorator.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/leaflet.polylineDecorator.js")),
|
||||
'assets/js/leaflet/L.Terminator.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/leaflet/L.Terminator.js")),
|
||||
'assets/js/sections/callstats.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/callstats.js")),
|
||||
'assets/js/sections/bandmap_list.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/bandmap_list.js")),
|
||||
];
|
||||
|
||||
// Get Date format
|
||||
if($this->session->userdata('user_date_format')) {
|
||||
// If Logged in and session exists
|
||||
$pageData['custom_date_format'] = $this->session->userdata('user_date_format');
|
||||
} else {
|
||||
// Get Default date format from /config/wavelog.php
|
||||
$pageData['custom_date_format'] = $this->config->item('qso_date_format');
|
||||
}
|
||||
|
||||
switch ($pageData['custom_date_format']) {
|
||||
case "d/m/y": $pageData['custom_date_format'] = 'DD/MM/YY'; break;
|
||||
case "d/m/Y": $pageData['custom_date_format'] = 'DD/MM/YYYY'; break;
|
||||
case "m/d/y": $pageData['custom_date_format'] = 'MM/DD/YY'; break;
|
||||
case "m/d/Y": $pageData['custom_date_format'] = 'MM/DD/YYYY'; break;
|
||||
case "d.m.Y": $pageData['custom_date_format'] = 'DD.MM.YYYY'; break;
|
||||
case "y/m/d": $pageData['custom_date_format'] = 'YY/MM/DD'; break;
|
||||
case "Y-m-d": $pageData['custom_date_format'] = 'YYYY-MM-DD'; break;
|
||||
case "M d, Y": $pageData['custom_date_format'] = 'MMM DD, YYYY'; break;
|
||||
case "M d, y": $pageData['custom_date_format'] = 'MMM DD, YY'; break;
|
||||
default: $pageData['custom_date_format'] = 'DD/MM/YYYY';
|
||||
}
|
||||
|
||||
$data['page_title'] = __("DXCluster");
|
||||
$this->load->view('interface_assets/header', $data);
|
||||
$this->load->view('bandmap/list',$pageData);
|
||||
$this->load->view('interface_assets/footer', $footerData);
|
||||
}
|
||||
|
||||
// Get user's active bands and modes/submodes
|
||||
}
|
||||
|
||||
@@ -1,71 +1,186 @@
|
||||
<?php
|
||||
|
||||
class User_Options extends CI_Controller {
|
||||
|
||||
function __construct() {
|
||||
parent::__construct();
|
||||
$this->load->model('user_model');
|
||||
$this->load->model('user_options_model');
|
||||
if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); }
|
||||
}
|
||||
|
||||
public function add_edit_fav() {
|
||||
$obj = json_decode(file_get_contents("php://input"), true);
|
||||
foreach($obj as $option_key => $option_value) {
|
||||
$obj[$option_key]=$this->security->xss_clean($option_value);
|
||||
}
|
||||
if ($obj['sat_name'] ?? '' != '') {
|
||||
$option_name=$obj['sat_name'].'/'.$obj['mode'];
|
||||
} else {
|
||||
$option_name=$obj['band'].'/'.$obj['mode'];
|
||||
}
|
||||
$this->user_options_model->set_option('Favourite',$option_name, $obj);
|
||||
$jsonout['success']=1;
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($jsonout);
|
||||
}
|
||||
|
||||
public function get_fav() {
|
||||
$result=$this->user_options_model->get_options('Favourite');
|
||||
$jsonout=[];
|
||||
foreach($result->result() as $options) {
|
||||
$jsonout[$options->option_name][$options->option_key]=$options->option_value;
|
||||
}
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($jsonout);
|
||||
}
|
||||
|
||||
public function del_fav() {
|
||||
$result=$this->user_options_model->get_options('Favourite');
|
||||
$obj = json_decode(file_get_contents("php://input"), true);
|
||||
if ($obj['option_name'] ?? '' != '') {
|
||||
$option_name=$this->security->xss_clean($obj['option_name']);
|
||||
$this->user_options_model->del_option('Favourite',$option_name);
|
||||
}
|
||||
$jsonout['success']=1;
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($jsonout);
|
||||
}
|
||||
|
||||
public function dismissVersionDialog() {
|
||||
$this->user_options_model->set_option('version_dialog', 'confirmed', array('boolean' => 'true'));
|
||||
}
|
||||
|
||||
public function get_qrg_units() {
|
||||
|
||||
$qrg_units = [];
|
||||
|
||||
foreach($this->session->get_userdata() as $key => $value) {
|
||||
if (strpos($key, 'qrgunit_') === 0) {
|
||||
$band = str_replace('qrgunit_', '', $key);
|
||||
$qrg_units[$band] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($qrg_units);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
<?php
|
||||
|
||||
class User_Options extends CI_Controller {
|
||||
|
||||
function __construct() {
|
||||
parent::__construct();
|
||||
$this->load->model('user_model');
|
||||
$this->load->model('user_options_model');
|
||||
if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); }
|
||||
}
|
||||
|
||||
public function add_edit_fav() {
|
||||
$obj = json_decode(file_get_contents("php://input"), true);
|
||||
foreach($obj as $option_key => $option_value) {
|
||||
$obj[$option_key]=$this->security->xss_clean($option_value);
|
||||
}
|
||||
if ($obj['sat_name'] ?? '' != '') {
|
||||
$option_name=$obj['sat_name'].'/'.$obj['mode'];
|
||||
} else {
|
||||
$option_name=$obj['band'].'/'.$obj['mode'];
|
||||
}
|
||||
$this->user_options_model->set_option('Favourite',$option_name, $obj);
|
||||
$jsonout['success']=1;
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($jsonout);
|
||||
}
|
||||
|
||||
public function get_fav() {
|
||||
$result=$this->user_options_model->get_options('Favourite');
|
||||
$jsonout=[];
|
||||
foreach($result->result() as $options) {
|
||||
$jsonout[$options->option_name][$options->option_key]=$options->option_value;
|
||||
}
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($jsonout);
|
||||
}
|
||||
|
||||
public function del_fav() {
|
||||
$result=$this->user_options_model->get_options('Favourite');
|
||||
$obj = json_decode(file_get_contents("php://input"), true);
|
||||
if ($obj['option_name'] ?? '' != '') {
|
||||
$option_name=$this->security->xss_clean($obj['option_name']);
|
||||
$this->user_options_model->del_option('Favourite',$option_name);
|
||||
}
|
||||
$jsonout['success']=1;
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($jsonout);
|
||||
}
|
||||
|
||||
public function dismissVersionDialog() {
|
||||
$this->user_options_model->set_option('version_dialog', 'confirmed', array('boolean' => 'true'));
|
||||
}
|
||||
|
||||
/**
|
||||
* DX Cluster Filter Favorites
|
||||
*/
|
||||
public function add_edit_dxcluster_fav() {
|
||||
$obj = json_decode(file_get_contents("php://input"), true);
|
||||
if (!$obj || !isset($obj['fav_name']) || trim($obj['fav_name']) === '') {
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => 0, 'error' => 'Invalid data']);
|
||||
return;
|
||||
}
|
||||
|
||||
// Sanitize all input
|
||||
foreach($obj as $option_key => $option_value) {
|
||||
if (is_array($option_value)) {
|
||||
$obj[$option_key] = array_map([$this->security, 'xss_clean'], $option_value);
|
||||
} else {
|
||||
$obj[$option_key] = $this->security->xss_clean($option_value);
|
||||
}
|
||||
}
|
||||
|
||||
$option_name = $obj['fav_name'];
|
||||
unset($obj['fav_name']); // Don't store the name as a value
|
||||
|
||||
// Convert arrays to JSON for storage
|
||||
foreach($obj as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$obj[$key] = json_encode($value);
|
||||
}
|
||||
}
|
||||
|
||||
$this->user_options_model->set_option('DXClusterFavourite', $option_name, $obj);
|
||||
$jsonout['success'] = 1;
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($jsonout);
|
||||
}
|
||||
|
||||
public function del_dxcluster_fav() {
|
||||
$obj = json_decode(file_get_contents("php://input"), true);
|
||||
if ($obj['option_name'] ?? '' != '') {
|
||||
$option_name = $this->security->xss_clean($obj['option_name']);
|
||||
$this->user_options_model->del_option('DXClusterFavourite', $option_name);
|
||||
}
|
||||
$jsonout['success'] = 1;
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($jsonout);
|
||||
}
|
||||
|
||||
public function get_qrg_units() {
|
||||
|
||||
$qrg_units = [];
|
||||
|
||||
foreach($this->session->get_userdata() as $key => $value) {
|
||||
if (strpos($key, 'qrgunit_') === 0) {
|
||||
$band = str_replace('qrgunit_', '', $key);
|
||||
$qrg_units[$band] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($qrg_units);
|
||||
}
|
||||
|
||||
/**
|
||||
* Combined endpoint: DX Cluster favorites + user bands/modes settings
|
||||
* Returns both favorites and user configuration in a single request
|
||||
*/
|
||||
public function get_dxcluster_user_favs_and_settings() {
|
||||
session_write_close();
|
||||
|
||||
// Get DX Cluster favorites
|
||||
$result = $this->user_options_model->get_options('DXClusterFavourite');
|
||||
$favorites = [];
|
||||
foreach($result->result() as $options) {
|
||||
$value = $options->option_value;
|
||||
if (is_string($value) && (strpos($value, '[') === 0 || strpos($value, '{') === 0)) {
|
||||
$decoded = json_decode($value, true);
|
||||
if (json_last_error() === JSON_ERROR_NONE) {
|
||||
$value = $decoded;
|
||||
}
|
||||
}
|
||||
$favorites[$options->option_name][$options->option_key] = $value;
|
||||
}
|
||||
|
||||
// Get user bands and modes
|
||||
$this->load->model('bands');
|
||||
$this->load->model('usermodes');
|
||||
|
||||
$activeBands = $this->bands->get_user_bands_for_qso_entry(false);
|
||||
$bandList = [];
|
||||
if (is_array($activeBands)) {
|
||||
foreach ($activeBands as $group => $bands) {
|
||||
if (is_array($bands)) {
|
||||
foreach ($bands as $band) {
|
||||
$bandList[] = $band;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$activeModes = $this->usermodes->active();
|
||||
$modeCategories = ['cw' => false, 'phone' => false, 'digi' => false];
|
||||
$submodes = [];
|
||||
|
||||
if ($activeModes) {
|
||||
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;
|
||||
}
|
||||
$submode = !empty($mode->submode) ? $mode->submode : $mode->mode;
|
||||
if (!empty($submode) && !in_array($submode, $submodes)) {
|
||||
$submodes[] = $submode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode([
|
||||
'favorites' => $favorites,
|
||||
'userConfig' => [
|
||||
'bands' => $bandList,
|
||||
'modes' => $modeCategories,
|
||||
'submodes' => $submodes
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
var lang_bandmap_cat_required = "<?= __("CAT Connection Required"); ?>";
|
||||
var lang_bandmap_enable_cat = "<?= __("Enable CAT connection to tune the radio"); ?>";
|
||||
var lang_bandmap_clear_filters = "<?= __("Clear Filters"); ?>";
|
||||
var lang_bandmap_band_preserved = "<?= __("Band filter preserved (CAT connection is active)"); ?>";
|
||||
var lang_bandmap_band_preserved = "<?= __("Band filter preserved (band lock is active)"); ?>";
|
||||
var lang_bandmap_radio = "<?= __("Radio"); ?>";
|
||||
var lang_bandmap_radio_none = "<?= __("Radio set to None - CAT connection disabled"); ?>";
|
||||
var lang_bandmap_radio_tuned = "<?= __("Radio Tuned"); ?>";
|
||||
@@ -28,9 +28,12 @@
|
||||
var lang_bandmap_sent_to_form = "<?= __("sent to logging form"); ?>";
|
||||
var lang_bandmap_cat_control = "<?= __("CAT Connection"); ?>";
|
||||
var lang_bandmap_cat_off = "<?= __("Click to enable CAT connection"); ?>";
|
||||
var lang_bandmap_cat_on = "<?= __("CAT following radio | Click for frequency marker | Double-click to disable"); ?>";
|
||||
var lang_bandmap_cat_marker = "<?= __("Frequency marker active | Click to disable marker | Double-click to disable CAT"); ?>";
|
||||
var lang_bandmap_freq_changed = "<?= __("Frequency filter changed to"); ?>";
|
||||
var lang_bandmap_cat_on = "<?= __("CAT following radio - Click to disable"); ?>";
|
||||
var lang_bandmap_cat_lock_off = "<?= __("Click to enable band lock (requires CAT connection)"); ?>";
|
||||
var lang_bandmap_cat_lock_on = "<?= __("Band lock active - Click to disable"); ?>";
|
||||
var lang_bandmap_band_lock = "<?= __("Band Lock"); ?>";
|
||||
var lang_bandmap_band_lock_enabled = "<?= __("Band lock enabled - band filter will track radio band"); ?>";
|
||||
var lang_bandmap_freq_changed = "<?= __("Band filter changed to"); ?>";
|
||||
var lang_bandmap_by_transceiver = "<?= __("by transceiver"); ?>";
|
||||
var lang_bandmap_freq_filter_set = "<?= __("Frequency filter set to"); ?>";
|
||||
var lang_bandmap_freq_outside = "<?= __("Frequency outside known bands - showing all bands"); ?>";
|
||||
@@ -40,6 +43,30 @@
|
||||
var lang_bandmap_modes_applied = "<?= __("Modes applied. Band filter preserved (CAT connection is active)"); ?>";
|
||||
var lang_bandmap_favorites_applied = "<?= __("Applied your favorite bands and modes"); ?>";
|
||||
|
||||
// My Submodes filter translations
|
||||
var lang_bandmap_my_submodes = "<?= __("My Submodes"); ?>";
|
||||
var lang_bandmap_submodes_filter_enabled = "<?= __("Submode filter enabled"); ?>";
|
||||
var lang_bandmap_submodes_filter_disabled = "<?= __("Submode filter disabled - showing all"); ?>";
|
||||
var lang_bandmap_required_submodes = "<?= __("Required submodes"); ?>";
|
||||
var lang_bandmap_submodes_settings_hint = "<?= __("Configure in User Settings - Modes"); ?>";
|
||||
var lang_bandmap_no_submodes_configured = "<?= __("No submodes configured - configure in User Settings - Modes"); ?>";
|
||||
var lang_bandmap_no_submodes_warning = "<?= __("No submodes enabled in settings - showing all spots"); ?>";
|
||||
var lang_bandmap_mode_disabled_no_submode = "<?= __("Disabled - no submodes enabled for this mode in User Settings"); ?>";
|
||||
var lang_bandmap_toggle_cw = "<?= __("Toggle CW mode filter"); ?>";
|
||||
var lang_bandmap_toggle_digi = "<?= __("Toggle Digital mode filter"); ?>";
|
||||
var lang_bandmap_toggle_phone = "<?= __("Toggle Phone mode filter"); ?>";
|
||||
|
||||
// DX Cluster Filter Favorites translations
|
||||
var lang_bandmap_filter_favorites = "<?= __("Favorites"); ?>";
|
||||
var lang_bandmap_save_filters = "<?= __("Save Current Filters..."); ?>";
|
||||
var lang_bandmap_filter_preset_name = "<?= __("Enter a name for this filter preset:"); ?>";
|
||||
var lang_bandmap_filter_preset_saved = "<?= __("Filter preset saved"); ?>";
|
||||
var lang_bandmap_filter_preset_loaded = "<?= __("Filter preset loaded"); ?>";
|
||||
var lang_bandmap_filter_preset_deleted = "<?= __("Filter preset deleted"); ?>";
|
||||
var lang_bandmap_delete_filter_confirm = "<?= __("Are you sure to delete this filter preset?"); ?>";
|
||||
var lang_bandmap_no_filter_presets = "<?= __("No saved filter presets"); ?>";
|
||||
var lang_bandmap_preset_limit_reached = "<?= __("Maximum of 20 filter presets reached. Please delete some before adding new ones."); ?>";
|
||||
|
||||
// Bandmap filter status messages
|
||||
var lang_bandmap_loading_data = "<?= __("Loading data from DX Cluster"); ?>";
|
||||
var lang_bandmap_last_fetched = "<?= __("Last fetched for"); ?>";
|
||||
@@ -140,8 +167,8 @@
|
||||
var lang_bandmap_mode = "<?= __("Mode"); ?>";
|
||||
var lang_bandmap_band = "<?= __("Band"); ?>";
|
||||
|
||||
// Enable ultra-compact radio status display for bandmap page (tooltip only)
|
||||
window.CAT_COMPACT_MODE = 'ultra-compact';
|
||||
// Enable icon-only radio status display for bandmap page (just icon with tooltip)
|
||||
window.CAT_COMPACT_MODE = 'icon-only';
|
||||
|
||||
// Map configuration (matches QSO map settings)
|
||||
var map_tile_server = '<?php echo $this->optionslib->get_option('option_map_tile_server');?>';
|
||||
@@ -180,6 +207,9 @@
|
||||
<a href="https://github.com/wavelog/wavelog/wiki/DXCluster" target="_blank" title="<?= __("DX Cluster Help"); ?>" style="cursor: pointer; padding: 0.5rem; margin: -0.5rem; color: var(--bs-body-color); text-decoration: none; display: inline-flex; align-items: center;">
|
||||
<i class="fas fa-question-circle" style="font-size: 1.2rem;"></i>
|
||||
</a>
|
||||
<button type="button" class="btn btn-sm" id="compactModeToggle" title="<?= __("Compact Mode - Hide/Show Menu"); ?>" style="background: none; border: none; padding: 0.5rem; margin: -0.5rem; color: var(--bs-body-color);">
|
||||
<i class="fas fa-compress-alt" id="compactModeIcon" style="font-size: 1.2rem;"></i>
|
||||
</button>
|
||||
<div id="fullscreenToggleWrapper" style="cursor: pointer; padding: 0.5rem; margin: -0.5rem;">
|
||||
<button type="button" class="btn btn-sm" id="fullscreenToggle" title="<?= __("Toggle Fullscreen"); ?>" style="background: none; border: none; padding: 0.5rem;">
|
||||
<i class="fas fa-expand" id="fullscreenIcon" style="font-size: 1.2rem;"></i>
|
||||
@@ -192,15 +222,20 @@
|
||||
<!-- Filters Section with darker background and rounded corners -->
|
||||
<div class="menu-bar">
|
||||
<!-- Row 1: CAT Connection, Radio Selector, Radio Status (left) | de Continents (right) -->
|
||||
<div class="d-flex flex-wrap align-items-center gap-2 mb-2">
|
||||
<!-- Left: CAT Connection Button -->
|
||||
<button class="btn btn-sm btn-secondary flex-shrink-0" type="button" id="toggleCatTracking" data-bs-toggle="tooltip" data-bs-placement="bottom">
|
||||
<i class="fas fa-radio"></i> <span class="d-none d-sm-inline"><?= __("CAT Connection"); ?></span> <i class="fas fa-info-circle text-muted" style="font-size: 0.75rem;"></i>
|
||||
</button>
|
||||
<div class="d-flex flex-wrap align-items-center gap-2 mb-2 compactable-row">
|
||||
<!-- Left: CAT Connection + Lock Buttons -->
|
||||
<div class="btn-group flex-shrink-0" role="group">
|
||||
<button class="btn btn-sm btn-secondary" type="button" id="toggleCatTracking" data-bs-toggle="tooltip" data-bs-placement="bottom" title="<?= __("Click to enable CAT connection"); ?>">
|
||||
<i class="fas fa-radio"></i> <span class="d-none d-sm-inline"><?= __("CAT Connection"); ?></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-secondary" type="button" id="toggleCatLock" data-bs-toggle="tooltip" data-bs-placement="bottom" title="<?= __("Click to enable band lock (requires CAT connection)"); ?>" disabled>
|
||||
<i class="fas fa-lock-open"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Radio Selector Dropdown -->
|
||||
<small class="text-muted me-1 flex-shrink-0 d-none d-md-inline"><?= __("TRX:"); ?></small>
|
||||
<select class="form-select form-select-sm radios flex-shrink-0" id="radio" name="radio" style="width: auto; min-width: 150px;">
|
||||
<select class="form-select form-select-sm radios flex-shrink-0" id="radio" name="radio" style="width: auto;">
|
||||
<option value="0" selected="selected"><?= __("None"); ?></option>
|
||||
<option value="ws"<?php if ($this->session->userdata('radio') == 'ws') { echo ' selected="selected"'; } ?>><?= __("Live - ") . __("WebSocket (Requires WLGate>=1.1.10)"); ?></option>
|
||||
<?php foreach ($radios->result() as $row) { ?>
|
||||
@@ -215,7 +250,7 @@
|
||||
<div class="d-flex flex-wrap gap-2 align-items-center">
|
||||
<small class="text-muted me-1 flex-shrink-0"><?= __("de:"); ?></small>
|
||||
<div class="btn-group flex-shrink-0" role="group">
|
||||
<button class="btn btn-sm btn-secondary" type="button" id="toggleAllContinentsFilter" title="<?= __("Select all continents"); ?>"><?= __("World"); ?></button>
|
||||
<button class="btn btn-sm btn-secondary" type="button" id="toggleAllContinentsFilter" title="<?= __("Select all continents"); ?>"><i class="fas fa-globe"></i> <span class="d-none d-sm-inline"><?= __("World"); ?></span></button>
|
||||
<button class="btn btn-sm btn-secondary" type="button" id="toggleAfricaFilter" title="<?= __("Toggle Africa continent filter"); ?>">AF</button>
|
||||
<button class="btn btn-sm btn-secondary" type="button" id="toggleAntarcticaFilter" title="<?= __("Toggle Antarctica continent filter"); ?>">AN</button>
|
||||
<button class="btn btn-sm btn-secondary" type="button" id="toggleAsiaFilter" title="<?= __("Toggle Asia continent filter"); ?>">AS</button>
|
||||
@@ -228,7 +263,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Row 2: Advanced Filters, Favorites, Clear Filters | Band Filters (left) and Mode Filters (right) -->
|
||||
<div class="d-flex flex-wrap align-items-center gap-2 mb-2">
|
||||
<div class="d-flex flex-wrap align-items-center gap-2 mb-2 compactable-row">
|
||||
<!-- Left: Advanced Filters, Favorites, Clear Filters, and Band Filter Buttons -->
|
||||
<div class="d-flex flex-wrap gap-2 align-items-center">
|
||||
<!-- Button Group: Advanced Filters + Favorites + Clear Filters -->
|
||||
@@ -276,6 +311,7 @@
|
||||
<label class="form-label d-block filter-label-small" for="requiredFlags"><?= __("Required Flags"); ?></label>
|
||||
<select id="requiredFlags" class="form-select form-select-sm filter-short" name="required_flags" multiple="multiple">
|
||||
<option value="None" selected><?= __("None"); ?></option>
|
||||
<option value="mysubmodes"><?= __("My Submodes"); ?></option>
|
||||
<option value="lotw"><?= __("LoTW User"); ?></option>
|
||||
<option value="newcontinent"><?= __("New Continent"); ?></option>
|
||||
<option value="newcountry"><?= __("New Country"); ?></option>
|
||||
@@ -378,15 +414,22 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Favorites Button (part of button group) -->
|
||||
<button class="btn btn-sm btn-secondary" type="button" id="toggleFavoritesFilter" title="<?= __("Apply your favorite bands and modes (configured in Band and Mode settings)"); ?>" style="display: none;">
|
||||
<i class="fas fa-star text-warning"></i>
|
||||
</button>
|
||||
<!-- Clear Filters Button (part of button group) -->
|
||||
<button class="btn btn-sm btn-secondary" type="button" id="clearFiltersButtonQuick" title="<?= __("Clear all filters except De Continent"); ?>">
|
||||
<i class="fas fa-filter-circle-xmark text-danger"></i>
|
||||
</button>
|
||||
</div>
|
||||
<!-- DX Cluster Filter Favorites Dropdown -->
|
||||
<div class="dropdown flex-shrink-0">
|
||||
<button class="btn btn-sm btn-secondary dropdown-toggle" type="button" id="dxclusterFavDropdown" data-bs-toggle="dropdown" aria-expanded="false" title="<?= __("Filter Favorites"); ?>">
|
||||
<i class="fas fa-star text-warning"></i> <span class="d-none d-md-inline"><?= __("Favorites"); ?></span>
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dxclusterFavDropdown" style="min-width: 200px;">
|
||||
<a class="dropdown-item" href="#" id="dxcluster_fav_add"><i class="fas fa-plus-circle text-success me-2"></i><?= __("Save Current Filters..."); ?></a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<div id="dxcluster_fav_menu"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Clear Filters Button -->
|
||||
<button class="btn btn-sm btn-secondary flex-shrink-0" type="button" id="clearFiltersButtonQuick" title="<?= __("Clear all filters except De Continent"); ?>">
|
||||
<i class="fas fa-filter-circle-xmark text-danger"></i>
|
||||
</button>
|
||||
|
||||
<!-- MF Band -->
|
||||
<div class="btn-group flex-shrink-0" role="group">
|
||||
@@ -404,6 +447,10 @@
|
||||
<button class="btn btn-sm btn-secondary" type="button" id="toggle12mFilter" title="<?= __("Toggle 12m band filter"); ?>">12m</button>
|
||||
<button class="btn btn-sm btn-secondary" type="button" id="toggle10mFilter" title="<?= __("Toggle 10m band filter"); ?>">10m</button>
|
||||
</div>
|
||||
<!-- 6m Band -->
|
||||
<div class="btn-group flex-shrink-0" role="group">
|
||||
<button class="btn btn-sm btn-secondary" type="button" id="toggle6mFilter" title="<?= __("Toggle 6m band filter"); ?>">6m</button>
|
||||
</div>
|
||||
<!-- VHF/UHF/SHF Bands -->
|
||||
<div class="btn-group flex-shrink-0" role="group">
|
||||
<button class="btn btn-sm btn-secondary" type="button" id="toggleVHFFilter" title="<?= __("Toggle VHF bands filter"); ?>">VHF</button>
|
||||
@@ -418,15 +465,19 @@
|
||||
<!-- Right: Mode Filter Buttons -->
|
||||
<div class="d-flex flex-wrap gap-2 align-items-center">
|
||||
<div class="btn-group flex-shrink-0" role="group">
|
||||
<button class="btn btn-sm btn-secondary" type="button" id="toggleCwFilter" title="<?= __("Toggle CW mode filter"); ?>">CW</button>
|
||||
<button class="btn btn-sm btn-secondary" type="button" id="toggleDigiFilter" title="<?= __("Toggle Digital mode filter"); ?>">Digi</button>
|
||||
<button class="btn btn-sm btn-secondary" type="button" id="togglePhoneFilter" title="<?= __("Toggle Phone mode filter"); ?>">Phone</button>
|
||||
<button class="btn btn-sm btn-secondary" type="button" id="toggleCwFilter" title="<?= __("Toggle CW mode filter"); ?>"><i class="fas fa-wave-square"></i> <span class="d-none d-sm-inline">CW</span></button>
|
||||
<button class="btn btn-sm btn-secondary" type="button" id="toggleDigiFilter" title="<?= __("Toggle Digital mode filter"); ?>"><i class="fas fa-keyboard"></i> <span class="d-none d-sm-inline">Digi</span></button>
|
||||
<button class="btn btn-sm btn-secondary" type="button" id="togglePhoneFilter" title="<?= __("Toggle Phone mode filter"); ?>"><i class="fas fa-microphone"></i> <span class="d-none d-sm-inline">Phone</span></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Row 3: Quick Filters -->
|
||||
<div class="d-flex flex-wrap align-items-center gap-2 mb-2">
|
||||
<div class="d-flex flex-wrap align-items-center gap-2 mb-2 compactable-row">
|
||||
<!-- My Submodes Filter Toggle -->
|
||||
<button class="btn btn-sm btn-secondary flex-shrink-0" type="button" id="toggleMySubmodesFilter" title="<?= __("Loading submodes..."); ?>">
|
||||
<i class="fas fa-bookmark"></i> <span class="d-none d-lg-inline"><?= __("My Submodes"); ?></span>
|
||||
</button>
|
||||
<!-- LoTW Users Button (separate) -->
|
||||
<div class="btn-group flex-shrink-0" role="group">
|
||||
<button class="btn btn-sm btn-secondary" type="button" id="toggleLotwFilter" title="<?= __("Toggle LoTW User filter"); ?>">
|
||||
@@ -471,8 +522,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Row 5: Status Bar (70%) and Search (30%) -->
|
||||
<div class="d-flex flex-wrap align-items-center gap-2 mb-2">
|
||||
<!-- Row 5: Status Bar and Search - always stay together -->
|
||||
<div class="d-flex flex-wrap align-items-center gap-2 mb-2 status-search-row">
|
||||
<!-- Status Bar - 70% -->
|
||||
<div style="flex: 1 1 0; min-width: 300px;">
|
||||
<div class="status-bar">
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
236
assets/js/cat.js
236
assets/js/cat.js
@@ -81,9 +81,37 @@ $(document).ready(function() {
|
||||
};
|
||||
|
||||
// Global setting for radio status display mode (can be set by pages like bandmap)
|
||||
// Options: false (card wrapper), 'compact' (no card), 'ultra-compact' (tooltip only)
|
||||
// Options: false (card wrapper), 'compact' (no card), 'ultra-compact' (icon+name+tooltip), 'icon-only' (icon+tooltip)
|
||||
window.CAT_COMPACT_MODE = window.CAT_COMPACT_MODE || false;
|
||||
|
||||
/**
|
||||
* Safely dispose of a Bootstrap tooltip without triggering _isWithActiveTrigger errors
|
||||
* This works around a known Bootstrap bug where disposing during hide animation causes errors
|
||||
* @param {Element} element - The DOM element with the tooltip
|
||||
*/
|
||||
function safeDisposeTooltip(element) {
|
||||
try {
|
||||
var tooltipInstance = bootstrap.Tooltip.getInstance(element);
|
||||
if (tooltipInstance) {
|
||||
// Set _activeTrigger to empty object to prevent _isWithActiveTrigger error
|
||||
if (tooltipInstance._activeTrigger) {
|
||||
tooltipInstance._activeTrigger = {};
|
||||
}
|
||||
// Clear any pending timeouts
|
||||
if (tooltipInstance._timeout) {
|
||||
clearTimeout(tooltipInstance._timeout);
|
||||
tooltipInstance._timeout = null;
|
||||
}
|
||||
// Dispose without calling hide first
|
||||
tooltipInstance.dispose();
|
||||
}
|
||||
} catch(e) {
|
||||
// Silently ignore any remaining errors
|
||||
}
|
||||
}
|
||||
// Expose globally for other modules
|
||||
window.safeDisposeTooltip = safeDisposeTooltip;
|
||||
|
||||
function initializeWebSocketConnection() {
|
||||
try {
|
||||
// Note: Browser will log WebSocket connection errors to console if server is unreachable
|
||||
@@ -153,14 +181,19 @@ $(document).ready(function() {
|
||||
if (typeof window.isCatTrackingEnabled !== 'undefined') {
|
||||
if (!window.isCatTrackingEnabled) {
|
||||
// CAT Control is OFF - show offline status and skip processing
|
||||
if (window.CAT_COMPACT_MODE === 'ultra-compact') {
|
||||
if (window.CAT_COMPACT_MODE === 'ultra-compact' || window.CAT_COMPACT_MODE === 'icon-only') {
|
||||
displayOfflineStatus('cat_disabled');
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
data.updated_minutes_ago = Math.floor((Date.now() - data.timestamp) / 60000);
|
||||
// Calculate age from timestamp, defaulting to 0 (fresh) if timestamp is missing
|
||||
if (data.timestamp) {
|
||||
data.updated_minutes_ago = Math.floor((Date.now() - data.timestamp) / 60000);
|
||||
} else {
|
||||
data.updated_minutes_ago = 0; // Assume fresh if no timestamp
|
||||
}
|
||||
// Cache the radio data
|
||||
updateCATui(data);
|
||||
}
|
||||
@@ -379,8 +412,8 @@ $(document).ready(function() {
|
||||
* @param {string} reason - Optional reason: 'no_radio' (default) or 'cat_disabled'
|
||||
*/
|
||||
function displayOfflineStatus(reason) {
|
||||
// Display "Working offline" message with tooltip in ultra-compact mode
|
||||
if (window.CAT_COMPACT_MODE !== 'ultra-compact') {
|
||||
// Display "Working offline" message with tooltip in ultra-compact/icon-only modes
|
||||
if (window.CAT_COMPACT_MODE !== 'ultra-compact' && window.CAT_COMPACT_MODE !== 'icon-only') {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -390,11 +423,20 @@ $(document).ready(function() {
|
||||
// Use translation variable if available, fallback to English
|
||||
var offlineText = typeof lang_cat_working_offline !== 'undefined' ? lang_cat_working_offline : 'Working without CAT connection';
|
||||
|
||||
const offlineHtml = '<span id="radio_cat_state" class="text-body" style="display: inline-flex; align-items: center; font-size: 0.875rem;">' +
|
||||
'<i class="fas fa-unlink text-warning" style="margin-right: 5px;"></i>' +
|
||||
'<span style="margin-right: 5px;">' + offlineText + '</span>' +
|
||||
'<i id="radio-status-icon" class="fas fa-info-circle text-muted" style="cursor: help;" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom"></i>' +
|
||||
'</span>';
|
||||
var offlineHtml;
|
||||
if (window.CAT_COMPACT_MODE === 'icon-only') {
|
||||
// Icon-only mode: just the icon with tooltip, styled as button for consistent height
|
||||
offlineHtml = '<span id="radio_cat_state" class="btn btn-sm btn-secondary" style="display: inline-flex; align-items: center; justify-content: center; cursor: help;">' +
|
||||
'<i id="radio-status-icon" class="fas fa-unlink text-warning" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom"></i>' +
|
||||
'</span>';
|
||||
} else {
|
||||
// Ultra-compact mode: icon + text + info icon
|
||||
offlineHtml = '<span id="radio_cat_state" class="text-body" style="display: inline-flex; align-items: center; font-size: 0.875rem;">' +
|
||||
'<i class="fas fa-unlink text-warning" style="margin-right: 5px;"></i>' +
|
||||
'<span style="margin-right: 5px;">' + offlineText + '</span>' +
|
||||
'<i id="radio-status-icon" class="fas fa-info-circle text-muted" style="cursor: help;" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom"></i>' +
|
||||
'</span>';
|
||||
}
|
||||
|
||||
let tooltipContent;
|
||||
if (reason === 'cat_disabled') {
|
||||
@@ -418,11 +460,15 @@ $(document).ready(function() {
|
||||
// Initialize tooltip
|
||||
var tooltipElement = document.querySelector('#radio_status [data-bs-toggle="tooltip"]');
|
||||
if (tooltipElement) {
|
||||
new bootstrap.Tooltip(tooltipElement, {
|
||||
title: tooltipContent,
|
||||
html: true,
|
||||
placement: 'bottom'
|
||||
});
|
||||
try {
|
||||
new bootstrap.Tooltip(tooltipElement, {
|
||||
title: tooltipContent,
|
||||
html: true,
|
||||
placement: 'bottom'
|
||||
});
|
||||
} catch(e) {
|
||||
// Ignore tooltip initialization errors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,15 +479,16 @@ $(document).ready(function() {
|
||||
* CAT_COMPACT_MODE options:
|
||||
* false - Standard mode with card wrapper
|
||||
* 'compact' - Compact mode without card wrapper
|
||||
* 'ultra-compact' - Ultra-compact mode showing only tooltip with info
|
||||
* 'ultra-compact' - Ultra-compact mode showing icon, radio name, and tooltip
|
||||
* 'icon-only' - Icon-only mode showing just icon with tooltip (for bandmap)
|
||||
*/
|
||||
function displayRadioStatus(state, data) {
|
||||
// On bandmap page, only show radio status when CAT Control is enabled
|
||||
if (typeof window.isCatTrackingEnabled !== 'undefined') {
|
||||
if (!window.isCatTrackingEnabled) {
|
||||
// CAT Control is OFF on bandmap
|
||||
// In ultra-compact mode, show "Working offline" with CAT disabled message
|
||||
if (window.CAT_COMPACT_MODE === 'ultra-compact') {
|
||||
// In ultra-compact/icon-only mode, show "Working offline" with CAT disabled message
|
||||
if (window.CAT_COMPACT_MODE === 'ultra-compact' || window.CAT_COMPACT_MODE === 'icon-only') {
|
||||
// Check if a radio is selected
|
||||
var selectedRadio = $('.radios option:selected').val();
|
||||
if (selectedRadio && selectedRadio !== '0') {
|
||||
@@ -548,7 +595,90 @@ $(document).ready(function() {
|
||||
var html = baseStyle + icon + content + '</div>';
|
||||
|
||||
// Update DOM based on global CAT_COMPACT_MODE setting
|
||||
if (window.CAT_COMPACT_MODE === 'ultra-compact') {
|
||||
if (window.CAT_COMPACT_MODE === 'icon-only') {
|
||||
// Icon-only mode: show just radio icon with tooltip containing all info
|
||||
var tooltipContent = '';
|
||||
|
||||
if (state === 'success') {
|
||||
var radioName = $('select.radios option:selected').text();
|
||||
var connectionType = $(".radios option:selected").val() == 'ws' ? lang_cat_live : lang_cat_polling;
|
||||
tooltipContent = '<b>' + radioName + '</b> (' + connectionType + ')';
|
||||
|
||||
// Ensure frequency_formatted exists
|
||||
var freqFormatted = data.frequency_formatted;
|
||||
if (!freqFormatted || freqFormatted === 'undefined' || freqFormatted === 'nullkHz') {
|
||||
freqFormatted = format_frequency(data.frequency);
|
||||
}
|
||||
|
||||
// Add frequency info
|
||||
if(data.frequency_rx && data.frequency_rx != 0 && data.frequency_rx !== 'undefined') {
|
||||
// Split operation: show TX and RX separately
|
||||
if (freqFormatted && freqFormatted !== 'undefined') {
|
||||
tooltipContent += '<br><b>' + lang_cat_tx + ':</b> ' + freqFormatted;
|
||||
}
|
||||
var rxFormatted = format_frequency(data.frequency_rx);
|
||||
if (rxFormatted && rxFormatted !== 'undefined') {
|
||||
tooltipContent += '<br><b>' + lang_cat_rx + ':</b> ' + rxFormatted;
|
||||
}
|
||||
} else {
|
||||
// Simplex operation: show TX/RX combined
|
||||
if (freqFormatted && freqFormatted !== 'undefined') {
|
||||
tooltipContent += '<br><b>' + lang_cat_tx_rx + ':</b> ' + freqFormatted;
|
||||
}
|
||||
}
|
||||
|
||||
if(data.mode != null) {
|
||||
tooltipContent += '<br><b>' + lang_cat_mode + ':</b> ' + data.mode;
|
||||
}
|
||||
if(data.power != null && data.power != 0) {
|
||||
tooltipContent += '<br><b>' + lang_cat_power + ':</b> ' + data.power + 'W';
|
||||
}
|
||||
if ($(".radios option:selected").val() != 'ws') {
|
||||
tooltipContent += '<br><br><i>' + lang_cat_polling_tooltip + '</i>';
|
||||
}
|
||||
} else if (state === 'error') {
|
||||
var radioName = typeof data === 'string' ? data : $('select.radios option:selected').text();
|
||||
tooltipContent = lang_cat_connection_error + ': <b>' + radioName + '</b><br>' + lang_cat_connection_lost;
|
||||
} else if (state === 'timeout') {
|
||||
var radioName = typeof data === 'string' ? data : $('select.radios option:selected').text();
|
||||
tooltipContent = lang_cat_connection_timeout + ': <b>' + radioName + '</b><br>' + lang_cat_data_stale;
|
||||
} else if (state === 'not_logged_in') {
|
||||
tooltipContent = lang_cat_not_logged_in;
|
||||
}
|
||||
|
||||
var iconOnlyHtml = '<span id="radio_cat_state" class="btn btn-sm btn-secondary" style="display: inline-flex; align-items: center; justify-content: center; cursor: help;">' +
|
||||
'<i id="radio-status-icon" class="fas fa-radio ' + iconClass + '" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom"></i>' +
|
||||
'</span>';
|
||||
|
||||
if (!$('#radio_cat_state').length) {
|
||||
$('#radio_status').append(iconOnlyHtml);
|
||||
} else {
|
||||
$('#radio_cat_state [data-bs-toggle="tooltip"]').each(function() {
|
||||
safeDisposeTooltip(this);
|
||||
});
|
||||
$('#radio_cat_state').replaceWith(iconOnlyHtml);
|
||||
}
|
||||
|
||||
var tooltipElement = document.querySelector('#radio_status [data-bs-toggle="tooltip"]');
|
||||
if (tooltipElement) {
|
||||
try {
|
||||
new bootstrap.Tooltip(tooltipElement, {
|
||||
title: tooltipContent,
|
||||
html: true,
|
||||
placement: 'bottom'
|
||||
});
|
||||
} catch(e) {
|
||||
// Ignore tooltip initialization errors
|
||||
}
|
||||
}
|
||||
|
||||
// Add blink animation on update
|
||||
$('#radio_status .fa-radio').addClass('blink-once');
|
||||
setTimeout(function() {
|
||||
$('#radio_status .fa-radio').removeClass('blink-once');
|
||||
}, 600);
|
||||
|
||||
} else if (window.CAT_COMPACT_MODE === 'ultra-compact') {
|
||||
// Ultra-compact mode: show radio icon, radio name, and question mark with tooltip
|
||||
var tooltipContent = '';
|
||||
var radioName = '';
|
||||
@@ -562,17 +692,30 @@ $(document).ready(function() {
|
||||
connectionType = lang_cat_live;
|
||||
} else {
|
||||
connectionType = lang_cat_polling;
|
||||
} tooltipContent = '<b>' + radioName + '</b> (' + connectionType + ')';
|
||||
}
|
||||
tooltipContent = '<b>' + radioName + '</b> (' + connectionType + ')';
|
||||
|
||||
// Ensure frequency_formatted exists
|
||||
var freqFormatted = data.frequency_formatted;
|
||||
if (!freqFormatted || freqFormatted === 'undefined' || freqFormatted === 'nullkHz') {
|
||||
freqFormatted = format_frequency(data.frequency);
|
||||
}
|
||||
|
||||
// Add frequency info
|
||||
if(data.frequency_rx != null && data.frequency_rx != 0) {
|
||||
tooltipContent += '<br><b>' + lang_cat_tx + ':</b> ' + data.frequency_formatted;
|
||||
data.frequency_rx_formatted = format_frequency(data.frequency_rx);
|
||||
if (data.frequency_rx_formatted) {
|
||||
tooltipContent += '<br><b>' + lang_cat_rx + ':</b> ' + data.frequency_rx_formatted;
|
||||
if(data.frequency_rx && data.frequency_rx != 0 && data.frequency_rx !== 'undefined') {
|
||||
// Split operation: show TX and RX separately
|
||||
if (freqFormatted && freqFormatted !== 'undefined') {
|
||||
tooltipContent += '<br><b>' + lang_cat_tx + ':</b> ' + freqFormatted;
|
||||
}
|
||||
var rxFormatted = format_frequency(data.frequency_rx);
|
||||
if (rxFormatted && rxFormatted !== 'undefined') {
|
||||
tooltipContent += '<br><b>' + lang_cat_rx + ':</b> ' + rxFormatted;
|
||||
}
|
||||
} else {
|
||||
tooltipContent += '<br><b>' + lang_cat_tx_rx + ':</b> ' + data.frequency_formatted;
|
||||
// Simplex operation: show TX/RX combined
|
||||
if (freqFormatted && freqFormatted !== 'undefined') {
|
||||
tooltipContent += '<br><b>' + lang_cat_tx_rx + ':</b> ' + freqFormatted;
|
||||
}
|
||||
}
|
||||
|
||||
// Add mode
|
||||
@@ -611,10 +754,7 @@ $(document).ready(function() {
|
||||
} else {
|
||||
// Dispose of existing tooltips before updating content
|
||||
$('#radio_cat_state [data-bs-toggle="tooltip"]').each(function() {
|
||||
var tooltipInstance = bootstrap.Tooltip.getInstance(this);
|
||||
if (tooltipInstance) {
|
||||
tooltipInstance.dispose();
|
||||
}
|
||||
safeDisposeTooltip(this);
|
||||
});
|
||||
$('#radio_cat_state').replaceWith(ultraCompactHtml);
|
||||
}
|
||||
@@ -622,11 +762,15 @@ $(document).ready(function() {
|
||||
// Initialize tooltip with dynamic content
|
||||
var tooltipElement = document.querySelector('#radio_status [data-bs-toggle="tooltip"]');
|
||||
if (tooltipElement) {
|
||||
new bootstrap.Tooltip(tooltipElement, {
|
||||
title: tooltipContent,
|
||||
html: true,
|
||||
placement: 'bottom'
|
||||
});
|
||||
try {
|
||||
new bootstrap.Tooltip(tooltipElement, {
|
||||
title: tooltipContent,
|
||||
html: true,
|
||||
placement: 'bottom'
|
||||
});
|
||||
} catch(e) {
|
||||
// Ignore tooltip initialization errors
|
||||
}
|
||||
}
|
||||
|
||||
// Add blink animation to radio icon on update
|
||||
@@ -643,10 +787,7 @@ $(document).ready(function() {
|
||||
} else {
|
||||
// Dispose of existing tooltips before updating content
|
||||
$('#radio_cat_state [data-bs-toggle="tooltip"]').each(function() {
|
||||
var tooltipInstance = bootstrap.Tooltip.getInstance(this);
|
||||
if (tooltipInstance) {
|
||||
tooltipInstance.dispose();
|
||||
}
|
||||
safeDisposeTooltip(this);
|
||||
});
|
||||
$('#radio_cat_state').html(html);
|
||||
}
|
||||
@@ -658,18 +799,15 @@ $(document).ready(function() {
|
||||
} else {
|
||||
// Dispose of existing tooltips before updating content
|
||||
$('#radio_cat_state [data-bs-toggle="tooltip"]').each(function() {
|
||||
var tooltipInstance = bootstrap.Tooltip.getInstance(this);
|
||||
if (tooltipInstance) {
|
||||
tooltipInstance.dispose();
|
||||
}
|
||||
safeDisposeTooltip(this);
|
||||
});
|
||||
// Update existing panel content
|
||||
$('#radio_cat_state .card-body').html(html);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize Bootstrap tooltips for any new tooltip elements in the radio panel (except ultra-compact which handles its own)
|
||||
if (window.CAT_COMPACT_MODE !== 'ultra-compact') {
|
||||
// Initialize Bootstrap tooltips for any new tooltip elements in the radio panel (except ultra-compact/icon-only which handle their own)
|
||||
if (window.CAT_COMPACT_MODE !== 'ultra-compact' && window.CAT_COMPACT_MODE !== 'icon-only') {
|
||||
$('#radio_cat_state [data-bs-toggle="tooltip"]').each(function() {
|
||||
new bootstrap.Tooltip(this);
|
||||
});
|
||||
@@ -1007,8 +1145,8 @@ $(document).ready(function() {
|
||||
$('#toggleCatTracking').prop('disabled', false).removeClass('disabled');
|
||||
// Always initialize WebSocket connection
|
||||
initializeWebSocketConnection();
|
||||
// In ultra-compact mode, show offline status if CAT Control is disabled
|
||||
if (window.CAT_COMPACT_MODE === 'ultra-compact' && typeof window.isCatTrackingEnabled !== 'undefined' && !window.isCatTrackingEnabled) {
|
||||
// In ultra-compact/icon-only mode, show offline status if CAT Control is disabled
|
||||
if ((window.CAT_COMPACT_MODE === 'ultra-compact' || window.CAT_COMPACT_MODE === 'icon-only') && typeof window.isCatTrackingEnabled !== 'undefined' && !window.isCatTrackingEnabled) {
|
||||
displayOfflineStatus('cat_disabled');
|
||||
}
|
||||
} else {
|
||||
@@ -1020,8 +1158,8 @@ $(document).ready(function() {
|
||||
$('#toggleCatTracking').prop('disabled', false).removeClass('disabled');
|
||||
// Always start polling
|
||||
CATInterval=setInterval(updateFromCAT, CAT_CONFIG.POLL_INTERVAL);
|
||||
// In ultra-compact mode, show offline status if CAT Control is disabled
|
||||
if (window.CAT_COMPACT_MODE === 'ultra-compact' && typeof window.isCatTrackingEnabled !== 'undefined' && !window.isCatTrackingEnabled) {
|
||||
// In ultra-compact/icon-only mode, show offline status if CAT Control is disabled
|
||||
if ((window.CAT_COMPACT_MODE === 'ultra-compact' || window.CAT_COMPACT_MODE === 'icon-only') && typeof window.isCatTrackingEnabled !== 'undefined' && !window.isCatTrackingEnabled) {
|
||||
displayOfflineStatus('cat_disabled');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ const SIGNAL_BANDWIDTHS = {
|
||||
const BAND_GROUPS = {
|
||||
'MF': ['160m'],
|
||||
'HF': ['80m', '60m', '40m', '30m', '20m', '17m', '15m', '12m', '10m'],
|
||||
'VHF': ['6m', '4m', '2m', '1.25m'],
|
||||
'VHF': ['4m', '2m', '1.25m'], // Note: 6m has its own separate button in DX Cluster
|
||||
'UHF': ['70cm', '33cm', '23cm'],
|
||||
'SHF': ['13cm', '9cm', '6cm', '3cm', '1.25cm', '6mm', '4mm', '2.5mm', '2mm', '1mm']
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user