diff --git a/application/controllers/Widgets.php b/application/controllers/Widgets.php index e597d97b4..4ca159bbe 100644 --- a/application/controllers/Widgets.php +++ b/application/controllers/Widgets.php @@ -119,7 +119,15 @@ class Widgets extends CI_Controller { * @return void */ public function on_air($user_slug = "") { - // determine theme + // Check for nojs parameter (for QRZ.com compatibility) + $nojs = $this->input->get('nojs', TRUE) == '1'; + + if (!$nojs) { + $this->output->set_header('Content-Security-Policy: script-src \'self\' \'unsafe-inline\''); + $this->output->set_header('X-Frame-Options: ALLOWALL'); + $this->output->set_header('Feature-Policy: *'); + } + $this->load->model('themes_model'); $theme = $this->input->get('theme', TRUE); if ($theme != null) { @@ -132,12 +140,13 @@ class Widgets extends CI_Controller { $data['theme'] = $this->config->item('option_theme'); } - // determine text size $text_size = $this->input->get('text_size', true) ?? 1; if (empty($user_slug)) { $data['text_size_class'] = $this->prepare_text_size_css_class($text_size); $data['error'] = __("User slug not specified"); + $data['user_slug'] = ''; + $data['nojs'] = $nojs; $this->load->view('widgets/on_air', $data); return; } @@ -148,6 +157,8 @@ class Widgets extends CI_Controller { $data['text_size_class'] = $this->prepare_text_size_css_class($text_size); $data['error'] = __("User slug not specified"); $data['error'] = $e->getMessage(); + $data['user_slug'] = $user_slug; + $data['nojs'] = $nojs; $this->load->view('widgets/on_air', $data); return; } @@ -158,6 +169,8 @@ class Widgets extends CI_Controller { if ($widget_options->is_enabled === false) { $data['text_size_class'] = $this->prepare_text_size_css_class($text_size); $data['error'] = __("User has on-air widget disabled"); + $data['user_slug'] = $user_slug; + $data['nojs'] = $nojs; $this->load->view('widgets/on_air', $data); return; } @@ -165,7 +178,6 @@ class Widgets extends CI_Controller { $this->load->model('cat'); $query = $this->cat->status_for_user_id($user_id); - if ($query->num_rows() > 0) { $radio_timeout_seconds = $this->get_radio_timeout_seconds(); $cat_timeout_interval_minutes = floor($radio_timeout_seconds / 60); @@ -173,11 +185,9 @@ class Widgets extends CI_Controller { $last_seen_days_ago = 999; foreach ($query->result() as $radio_data) { - // There can be multiple radios online, we need to take into account all of them $radio_updated_ago_minutes = $this->calculate_radio_updated_ago_minutes($radio_data->timestamp); if ($radio_updated_ago_minutes > $cat_timeout_interval_minutes) { - // Radio was updated too long ago - calculate user's "last seen X days ago" value $mins_per_day = 1440; $radio_last_seen_days_ago = (int)floor($radio_updated_ago_minutes / $mins_per_day); $last_seen_days_ago = min($last_seen_days_ago, $radio_last_seen_days_ago); @@ -186,40 +196,123 @@ class Widgets extends CI_Controller { $radio_obj = new \stdClass; $radio_obj->updated_at = $radio_data->timestamp; $radio_obj->frequency_string = $this->prepare_frequency_string_for_widget($radio_data); + $radio_obj->mode = $radio_data->mode ?? ''; $radios_online[] = $radio_obj; } } if (count($radios_online) > 1 && $widget_options->display_only_most_recent_radio) { - // in case only most recent radio should be displayed, use only most recently updated radio as a result usort($radios_online, function($radio_a, $radio_b) { if ($radio_a->updated_at == $radio_b->updated_at) return 0; - return ($radio_a->updated_at > $radio_b->updated_at) ? -1 : 1; + return ($radio_a->updated_at > $radio_b->updated_at) ? -1 : 1; }); $radios_online = [$radios_online[0]]; } - // last seen text $last_seen_text = $widget_options->display_last_seen ? $this->prepare_last_seen_text($last_seen_days_ago) : null; $data['text_size_class'] = $this->prepare_text_size_css_class($text_size); + $data['user_slug'] = $user_slug; + $data['nojs'] = $nojs; - // prepare rest of the data for UI $data['user_callsign'] = strtoupper($user->user_callsign); $data['is_on_air'] = count($radios_online) > 0; $data['radios_online'] = $radios_online; $data['last_seen_text'] = $last_seen_text; $this->load->view('widgets/on_air', $data); - } else { $data['text_size_class'] = $this->prepare_text_size_css_class($text_size); - $data['user_callsign'] = strtoupper($user->user_callsign); + $data['user_slug'] = $user_slug; + $data['nojs'] = $nojs; $data['error'] = __("No CAT interfaced radios found. You need to have at least one radio interface configured."); + $data['user_callsign'] = strtoupper($user->user_callsign); + $data['is_on_air'] = false; + $data['radios_online'] = []; + $data['last_seen_text'] = null; $this->load->view('widgets/on_air', $data); + } + } + + public function on_air_ajax($user_slug = "") { + header('Content-Type: application/json'); + + if (empty($user_slug)) { + echo json_encode(['error' => 'User slug not specified']); return; } + + try { + $user = $this->get_user_by_slug($user_slug); + } catch (\Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + return; + } + + $user_id = $user->user_id; + $widget_options = $this->get_on_air_widget_options($user_id); + + if ($widget_options->is_enabled === false) { + echo json_encode(['error' => 'User has on-air widget disabled']); + return; + } + + $this->load->model('cat'); + $query = $this->cat->status_for_user_id($user_id); + + if ($query->num_rows() > 0) { + $radio_timeout_seconds = $this->get_radio_timeout_seconds(); + $cat_timeout_interval_minutes = floor($radio_timeout_seconds / 60); + $radios_online = []; + $last_seen_days_ago = 999; + + foreach ($query->result() as $radio_data) { + $radio_updated_ago_minutes = $this->calculate_radio_updated_ago_minutes($radio_data->timestamp); + + if ($radio_updated_ago_minutes > $cat_timeout_interval_minutes) { + $mins_per_day = 1440; + $radio_last_seen_days_ago = (int)floor($radio_updated_ago_minutes / $mins_per_day); + $last_seen_days_ago = min($last_seen_days_ago, $radio_last_seen_days_ago); + } else { + $radio_obj = new \stdClass; + $radio_obj->updated_at = $radio_data->timestamp; + $radio_obj->frequency_string = $this->prepare_frequency_string_for_widget($radio_data); + $radio_obj->mode = $radio_data->mode ?? ''; + $radios_online[] = $radio_obj; + } + } + + if (count($radios_online) > 1 && $widget_options->display_only_most_recent_radio) { + usort($radios_online, function($radio_a, $radio_b) { + if ($radio_a->updated_at == $radio_b->updated_at) return 0; + return ($radio_a->updated_at > $radio_b->updated_at) ? -1 : 1; + }); + $radios_online = [$radios_online[0]]; + } + + $last_seen_text = $widget_options->display_last_seen ? $this->prepare_last_seen_text($last_seen_days_ago) : null; + + $response = [ + 'success' => true, + 'user_callsign' => strtoupper($user->user_callsign), + 'is_on_air' => count($radios_online) > 0, + 'radios_online' => $radios_online, + 'last_seen_text' => $last_seen_text, + 'timestamp' => date('Y-m-d H:i:s') + ]; + + echo json_encode($response); + } else { + echo json_encode([ + 'success' => true, + 'user_callsign' => strtoupper($user->user_callsign), + 'is_on_air' => false, + 'radios_online' => [], + 'last_seen_text' => null, + 'timestamp' => date('Y-m-d H:i:s') + ]); + } } /** diff --git a/application/views/widgets/on_air.php b/application/views/widgets/on_air.php index 5e9c3998a..49cf85ee4 100644 --- a/application/views/widgets/on_air.php +++ b/application/views/widgets/on_air.php @@ -1,11 +1,15 @@ +For QRZ.com compatibility (using QRZ.com auto-refresh): + +The widget automatically detects the nojs=1 parameter and serves a JavaScript-free version that works in QRZ.com's sandbox environment. QRZ.com's lazyLoader will automatically refresh every 60 seconds using the data-refresh attribute. +--> @@ -14,11 +18,15 @@ To use this widget insert this Element: + + + + - <?= "Wavelog On-Air widget"; ?> + <?= "Wavelog Dynamic On-Air widget"; ?> + +
@@ -72,28 +141,100 @@ To use this widget insert this Element:
-

- -

+
+ + + + +
-
+
-

- frequency_string; ?> -

+
+ + frequency_string); ?> + +
+ + +
+ +
+ +
+ Updated: (auto-refreshed every 60s) +
+
+
+ +
+
+
+ + +
+
+
+
+ +
+
+ Updated: (auto-refreshed by QRZ.com every 60s) +
+
+
+ +
+ + + +
+
+ +
+ +
+
+
+ + + + +
+
+ 🔄 +
+
+
+ + +
+ + frequency_string); ?> + +
-

- +

+

+
+ Last updated: +
@@ -102,11 +243,105 @@ To use this widget insert this Element:

-

+

+ + + + +