From 22705228f2f7fa8cacf5af3df1cee0b237303e22 Mon Sep 17 00:00:00 2001 From: phl0 Date: Fri, 18 Aug 2023 00:53:41 +0200 Subject: [PATCH 01/60] Fix lookup of LoTW data (LoTW hints were empty in advanced logbook) --- src/QSLManager/QSO.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/QSLManager/QSO.php b/src/QSLManager/QSO.php index 97c98d26..f488fdc2 100644 --- a/src/QSLManager/QSO.php +++ b/src/QSLManager/QSO.php @@ -202,8 +202,8 @@ class QSO } else { $this->end = null; } - $this->callsign = ($data['callsign'] ?? null === null) ? '' :$data['callsign']; - $this->lastupload = ($data['lastupload'] ?? null === null) ? '' : date($custom_date_format . " H:i", strtotime($data['lastupload'] ?? null)); + $this->callsign = (($data['callsign'] ?? null) === null) ? '' : $data['callsign']; + $this->lastupload = (($data['lastupload'] ?? null) === null) ? '' : date($custom_date_format . " H:i", strtotime($data['lastupload'] ?? null)); $this->lotw_hint = $this->getLotwHint($data['lastupload'] ?? null); } From 0320acbefdb42c3ea605211b32dec27f73bf1a14 Mon Sep 17 00:00:00 2001 From: phl0 Date: Fri, 18 Aug 2023 01:00:39 +0200 Subject: [PATCH 02/60] Make LoTW hint clickable and show last upload from LoTW page --- application/views/qso/index.php | 2 +- application/views/view_log/partial/log_ajax.php | 2 +- assets/js/sections/logbookadvanced.js | 4 ++-- assets/js/sections/qso.js | 6 ++++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/application/views/qso/index.php b/application/views/qso/index.php index 39dfc123..e4185389 100755 --- a/application/views/qso/index.php +++ b/application/views/qso/index.php @@ -65,7 +65,7 @@
optionslib->get_option('dxcache_url') != '') { ?>  - +
diff --git a/application/views/view_log/partial/log_ajax.php b/application/views/view_log/partial/log_ajax.php index e0afda10..5eece060 100644 --- a/application/views/view_log/partial/log_ajax.php +++ b/application/views/view_log/partial/log_ajax.php @@ -112,7 +112,7 @@ function echoQrbCalcLink($mygrid, $grid, $vucc) { } elseif ($diff > 7) { $lotw_hint = ' lotw_info_yellow'; } - $timestamp = strtotime($row->lastupload); echo ($row->callsign == '' ? '' : ' L'); + $timestamp = strtotime($row->lastupload); echo ($row->callsign == '' ? '' : ' L'); } ?> diff --git a/assets/js/sections/logbookadvanced.js b/assets/js/sections/logbookadvanced.js index 6b393de5..63f92de5 100644 --- a/assets/js/sections/logbookadvanced.js +++ b/assets/js/sections/logbookadvanced.js @@ -26,7 +26,7 @@ function updateRow(qso) { let c = 1; cells.eq(c++).text(qso.qsoDateTime); cells.eq(c++).text(qso.de); - cells.eq(c++).html(''+qso.dx+'' + (qso.callsign == '' ? '' : ' L') + ' Lookup ' + qso.dx + ' on QRZ.com Lookup ' + qso.dx + ' on HamQTH'); + cells.eq(c++).html(''+qso.dx+'' + (qso.callsign == '' ? '' : ' L') + ' Lookup ' + qso.dx + ' on QRZ.com Lookup ' + qso.dx + ' on HamQTH'); cells.eq(c++).text(qso.mode); cells.eq(c++).text(qso.rstS); cells.eq(c++).text(qso.rstR); @@ -81,7 +81,7 @@ function loadQSOTable(rows) { data.push('
'); data.push(qso.qsoDateTime); data.push(qso.de); - data.push(''+qso.dx+'' + (qso.callsign == '' ? '' : ' L') + ' Lookup ' + qso.dx + ' on QRZ.com Lookup ' + qso.dx + ' on HamQTH'); + data.push(''+qso.dx+'' + (qso.callsign == '' ? '' : ' L') + ' Lookup ' + qso.dx + ' on QRZ.com Lookup ' + qso.dx + ' on HamQTH'); data.push(qso.mode); data.push(qso.rstS); data.push(qso.rstR); diff --git a/assets/js/sections/qso.js b/assets/js/sections/qso.js index 3ad082e5..23909736 100644 --- a/assets/js/sections/qso.js +++ b/assets/js/sections/qso.js @@ -495,8 +495,10 @@ $("#callsign").focusout(function() { } else if (result.lotw_days > 7) { $('#lotw_info').addClass('lotw_info_yellow'); } + $('#lotw_link').attr('href',"https://lotw.arrl.org/lotwuser/act?act="+find_callsign); + $('#lotw_link').attr('target',"_blank"); $('#lotw_info').attr('data-toggle',"tooltip"); - $('#lotw_info').attr('data-original-title',"LoTW User. Last upload was "+result.lotw_days+" days ago"); + $('#lotw_info').attr('data-original-title',"BLABLA LoTW User. Last upload was "+result.lotw_days+" days ago"); $('[data-toggle="tooltip"]').tooltip(); } $('#qrz_info').html(''); @@ -867,4 +869,4 @@ function closeModal() { container.removeChild(backdrop) container.removeChild(modal) }, 200) -} \ No newline at end of file +} From 807061da3355a389a81cf36937f1bea6d6bd9cfb Mon Sep 17 00:00:00 2001 From: phl0 Date: Fri, 18 Aug 2023 07:01:22 +0200 Subject: [PATCH 03/60] Remove debug stuff --- assets/js/sections/qso.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/js/sections/qso.js b/assets/js/sections/qso.js index 23909736..a558465b 100644 --- a/assets/js/sections/qso.js +++ b/assets/js/sections/qso.js @@ -498,7 +498,7 @@ $("#callsign").focusout(function() { $('#lotw_link').attr('href',"https://lotw.arrl.org/lotwuser/act?act="+find_callsign); $('#lotw_link').attr('target',"_blank"); $('#lotw_info').attr('data-toggle',"tooltip"); - $('#lotw_info').attr('data-original-title',"BLABLA LoTW User. Last upload was "+result.lotw_days+" days ago"); + $('#lotw_info').attr('data-original-title',"LoTW User. Last upload was "+result.lotw_days+" days ago"); $('[data-toggle="tooltip"]').tooltip(); } $('#qrz_info').html(''); From aa599f38fc2a906dd49421a0ae5836c2ac7c660e Mon Sep 17 00:00:00 2001 From: int2001 Date: Fri, 18 Aug 2023 08:40:09 +0000 Subject: [PATCH 04/60] Changed MaxZoom from 9 to 12 - so 6-character-grids are visible --- application/views/interface_assets/footer.php | 4 ++-- assets/js/leaflet/leafembed.js | 2 +- assets/js/sections/gridmap.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/application/views/interface_assets/footer.php b/application/views/interface_assets/footer.php index 27ecf041..262abec5 100644 --- a/application/views/interface_assets/footer.php +++ b/application/views/interface_assets/footer.php @@ -583,7 +583,7 @@ function newpath(latlng1, latlng2, locator1, locator2) { var osmUrl='optionslib->get_option('option_map_tile_server');?>'; var osmAttrib='Map data © OpenStreetMap contributors'; - var osm = new L.TileLayer(osmUrl, {minZoom: 1, maxZoom: 9, attribution: osmAttrib}); + var osm = new L.TileLayer(osmUrl, {minZoom: 1, maxZoom: 12, attribution: osmAttrib}); var redIcon = L.icon({ iconUrl: icon_dot_url, @@ -637,7 +637,7 @@ function showActivatorsMap(call, count, grids) { var osmUrl='optionslib->get_option('option_map_tile_server');?>'; var osmAttrib='Map data © OpenStreetMap contributors'; - var osm = new L.TileLayer(osmUrl, {minZoom: 1, maxZoom: 9, attribution: osmAttrib}); + var osm = new L.TileLayer(osmUrl, {minZoom: 1, maxZoom: 12, attribution: osmAttrib}); map.addLayer(osm); } diff --git a/assets/js/leaflet/leafembed.js b/assets/js/leaflet/leafembed.js index c0ece429..5b8e556e 100644 --- a/assets/js/leaflet/leafembed.js +++ b/assets/js/leaflet/leafembed.js @@ -25,7 +25,7 @@ function initmap(ShowGrid = 'No', MapTag = 'map') { // create the tile layer with correct attribution var osmAttrib='Map data © OpenStreetMap contributors'; - var osm = new L.TileLayer(osmUrl, {minZoom: 1, maxZoom: 9, attribution: osmAttrib}); + var osm = new L.TileLayer(osmUrl, {minZoom: 1, maxZoom: 12, attribution: osmAttrib}); var printer = L.easyPrint({ tileLayer: osm, diff --git a/assets/js/sections/gridmap.js b/assets/js/sections/gridmap.js index b8ab1687..922397e9 100644 --- a/assets/js/sections/gridmap.js +++ b/assets/js/sections/gridmap.js @@ -51,7 +51,7 @@ function gridPlot(form) { grid_four_confirmed = data.grid_4char_confirmed; grid_six_confirmed = data.grid_6char_confirmed; var layer = L.tileLayer(jslayer, { - maxZoom: 9, + maxZoom: 12, attribution: jsattribution, id: 'mapbox.streets' }); From 2891cf09c8d8f8760ed2fdc906124e0eec13267f Mon Sep 17 00:00:00 2001 From: int2001 Date: Fri, 18 Aug 2023 12:48:31 +0000 Subject: [PATCH 05/60] save QRG/Mode/Band as Favourite --- assets/js/sections/qso.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/assets/js/sections/qso.js b/assets/js/sections/qso.js index a558465b..4e04d580 100644 --- a/assets/js/sections/qso.js +++ b/assets/js/sections/qso.js @@ -1,5 +1,30 @@ $( document ).ready(function() { + $('#start_time').click(function (event) { + save_fav(); + }); + + function save_fav() { + var payload={}; + payload.sat_name=$('#sat_name').val(); + payload.sat_mode=$('#sat_name').val(); + payload.band_rx=$('#band_rx').val(); + payload.band=$('#band').val(); + payload.frequency_tx=$('#frequency_rx').val(); + payload.frequency=$('#frequency').val(); + payload.prop_mode=$('#prop_mode').val(); + payload.mode=$('#mode').val(); + $.ajax({ + url: base_url+'index.php/user_options/set_options', + method: 'POST', + dataType: 'json', + contentType: "application/json; charset=utf-8", + data: JSON.stringify(payload), + success: function(result) { + } + }); + } + var bc_bandmap = new BroadcastChannel('qso_window'); bc_bandmap.onmessage = function (ev) { From 5dc5adb4bbd0537e1c0d276f74b6708cda2849cd Mon Sep 17 00:00:00 2001 From: int2001 Date: Fri, 18 Aug 2023 12:49:12 +0000 Subject: [PATCH 06/60] Model for User-options --- application/models/User_options.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 application/models/User_options.php diff --git a/application/models/User_options.php b/application/models/User_options.php new file mode 100644 index 00000000..ea375bc3 --- /dev/null +++ b/application/models/User_options.php @@ -0,0 +1,22 @@ +db->where('user_id', $this->session->userdata('user_id')); + $this->db->where('option_type', $option_type); + return $this->db->get('user_options'); + } + + public function set_option($option_type, $option_array) { + $uid=$this->session->userdata('user_id'); + $sql='insert into user_options (user_id,option_type,option_key,option_value) values (?,?,?,?) ON DUPLICATE KEY UPDATE option_value=?'; + $query = $this->db->query($sql); + foreach ($option_array() as $one_option) { + $query = $this->db->query($sql, array($uid, $option_type, $option_key, $option_value, $option_value)); + } + } + +} + +?> From 1bf2840e27b6b9761692e4eef859708e3815bf6b Mon Sep 17 00:00:00 2001 From: int2001 Date: Fri, 18 Aug 2023 13:16:01 +0000 Subject: [PATCH 07/60] Saving works now --- application/controllers/User_options.php | 19 +++++++++++++++++++ ...ser_options.php => User_options_model.php} | 5 ++--- assets/js/sections/qso.js | 2 +- 3 files changed, 22 insertions(+), 4 deletions(-) create mode 100755 application/controllers/User_options.php rename application/models/{User_options.php => User_options_model.php} (82%) diff --git a/application/controllers/User_options.php b/application/controllers/User_options.php new file mode 100755 index 00000000..c021dfb0 --- /dev/null +++ b/application/controllers/User_options.php @@ -0,0 +1,19 @@ +load->model('user_model'); + $this->load->model('user_options_model'); + if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('notice', 'You\'re not allowed to do that!'); redirect('dashboard'); } + } + + public function add_edit_fav() { + $obj = json_decode(file_get_contents("php://input"), true); + $this->user_options_model->set_option('Favourite',$obj); + } +} + + +?> diff --git a/application/models/User_options.php b/application/models/User_options_model.php similarity index 82% rename from application/models/User_options.php rename to application/models/User_options_model.php index ea375bc3..68e07816 100644 --- a/application/models/User_options.php +++ b/application/models/User_options_model.php @@ -1,6 +1,6 @@ db->where('user_id', $this->session->userdata('user_id')); @@ -11,8 +11,7 @@ class User_options extends CI_Model public function set_option($option_type, $option_array) { $uid=$this->session->userdata('user_id'); $sql='insert into user_options (user_id,option_type,option_key,option_value) values (?,?,?,?) ON DUPLICATE KEY UPDATE option_value=?'; - $query = $this->db->query($sql); - foreach ($option_array() as $one_option) { + foreach($option_array as $option_key => $option_value) { $query = $this->db->query($sql, array($uid, $option_type, $option_key, $option_value, $option_value)); } } diff --git a/assets/js/sections/qso.js b/assets/js/sections/qso.js index 4e04d580..02acf4fc 100644 --- a/assets/js/sections/qso.js +++ b/assets/js/sections/qso.js @@ -15,7 +15,7 @@ $( document ).ready(function() { payload.prop_mode=$('#prop_mode').val(); payload.mode=$('#mode').val(); $.ajax({ - url: base_url+'index.php/user_options/set_options', + url: base_url+'index.php/user_options/add_edit_fav', method: 'POST', dataType: 'json', contentType: "application/json; charset=utf-8", From 59f81279e32ebbe33bd14edb30a1d27d23209188 Mon Sep 17 00:00:00 2001 From: int2001 Date: Fri, 18 Aug 2023 13:30:04 +0000 Subject: [PATCH 08/60] Added option_name to table --- application/controllers/User_options.php | 7 ++++++- application/models/User_options_model.php | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/application/controllers/User_options.php b/application/controllers/User_options.php index c021dfb0..c5360590 100755 --- a/application/controllers/User_options.php +++ b/application/controllers/User_options.php @@ -11,7 +11,12 @@ class User_Options extends CI_Controller { public function add_edit_fav() { $obj = json_decode(file_get_contents("php://input"), true); - $this->user_options_model->set_option('Favourite',$obj); + if ($obj['sat_name'] ?? '' != '') { + $option_name=$obj['sat_name']; + } else { + $option_name=$obj['band'].'/'.$obj['mode']; + } + $this->user_options_model->set_option('Favourite',$option_name, $obj); } } diff --git a/application/models/User_options_model.php b/application/models/User_options_model.php index 68e07816..1304abd0 100644 --- a/application/models/User_options_model.php +++ b/application/models/User_options_model.php @@ -8,11 +8,11 @@ class User_options_model extends CI_Model return $this->db->get('user_options'); } - public function set_option($option_type, $option_array) { + public function set_option($option_type, $option_name, $option_array) { $uid=$this->session->userdata('user_id'); - $sql='insert into user_options (user_id,option_type,option_key,option_value) values (?,?,?,?) ON DUPLICATE KEY UPDATE option_value=?'; + $sql='insert into user_options (user_id,option_type,option_name,option_key,option_value) values (?,?,?,?,?) ON DUPLICATE KEY UPDATE option_value=?'; foreach($option_array as $option_key => $option_value) { - $query = $this->db->query($sql, array($uid, $option_type, $option_key, $option_value, $option_value)); + $query = $this->db->query($sql, array($uid, $option_type, $option_name, $option_key, $option_value, $option_value)); } } From e86b0a2f8673f1ba8142e56f6b977a95523bbddd Mon Sep 17 00:00:00 2001 From: int2001 Date: Fri, 18 Aug 2023 14:42:04 +0000 Subject: [PATCH 09/60] get_fav implemented --- application/controllers/User_options.php | 11 ++++++++++- application/models/User_options_model.php | 14 ++++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/application/controllers/User_options.php b/application/controllers/User_options.php index c5360590..1967349e 100755 --- a/application/controllers/User_options.php +++ b/application/controllers/User_options.php @@ -16,7 +16,16 @@ class User_Options extends CI_Controller { } else { $option_name=$obj['band'].'/'.$obj['mode']; } - $this->user_options_model->set_option('Favourite',$option_name, $obj); + return $this->user_options_model->set_option('Favourite',$option_name, $obj); + } + + public function get_favs() { + $result=$this->user_options_model->get_options('Favourite'); + foreach($result->result() as $options) { + $jsonout[$options->option_name][$options->option_key]=$options->option_value; + } + header('Content-Type: application/json'); + echo json_encode($jsonout); } } diff --git a/application/models/User_options_model.php b/application/models/User_options_model.php index 1304abd0..e37b8151 100644 --- a/application/models/User_options_model.php +++ b/application/models/User_options_model.php @@ -1,7 +1,7 @@ db->where('user_id', $this->session->userdata('user_id')); $this->db->where('option_type', $option_type); @@ -12,8 +12,14 @@ class User_options_model extends CI_Model $uid=$this->session->userdata('user_id'); $sql='insert into user_options (user_id,option_type,option_name,option_key,option_value) values (?,?,?,?,?) ON DUPLICATE KEY UPDATE option_value=?'; foreach($option_array as $option_key => $option_value) { - $query = $this->db->query($sql, array($uid, $option_type, $option_name, $option_key, $option_value, $option_value)); - } + $query = $this->db->query($sql, array($uid, $option_type, $option_name, $option_key, $option_value, $option_value)); + } + } + + public function get_options($option_type) { + $uid=$this->session->userdata('user_id'); + $sql='select option_name,option_key,option_value from user_options where user_id=? and option_type=?'; + return $this->db->query($sql, array($uid, $option_type)); } } From baa3724da9051a499d89d6d74821aaf326ef4155 Mon Sep 17 00:00:00 2001 From: int2001 Date: Fri, 18 Aug 2023 14:58:27 +0000 Subject: [PATCH 10/60] impemented del_fav --- application/controllers/User_options.php | 15 ++++++++++++++- application/models/User_options_model.php | 6 ++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/application/controllers/User_options.php b/application/controllers/User_options.php index 1967349e..864bc090 100755 --- a/application/controllers/User_options.php +++ b/application/controllers/User_options.php @@ -11,6 +11,9 @@ class User_Options extends CI_Controller { 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']; } else { @@ -19,7 +22,7 @@ class User_Options extends CI_Controller { return $this->user_options_model->set_option('Favourite',$option_name, $obj); } - public function get_favs() { + public function get_fav() { $result=$this->user_options_model->get_options('Favourite'); foreach($result->result() as $options) { $jsonout[$options->option_name][$options->option_key]=$options->option_value; @@ -27,6 +30,16 @@ class User_Options extends CI_Controller { 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); + } + return; + } } diff --git a/application/models/User_options_model.php b/application/models/User_options_model.php index e37b8151..9a383338 100644 --- a/application/models/User_options_model.php +++ b/application/models/User_options_model.php @@ -22,6 +22,12 @@ class User_options_model extends CI_Model { return $this->db->query($sql, array($uid, $option_type)); } + public function del_option($option_type, $option_name) { + $uid=$this->session->userdata('user_id'); + $sql='delete from user_options where user_id=? and option_type=? and option_name=?'; + return $this->db->query($sql, array($uid, $option_type,$option_name)); + } + } ?> From c29b1f3c802e5154baa092f8972957f1785ee267 Mon Sep 17 00:00:00 2001 From: int2001 Date: Fri, 18 Aug 2023 15:00:40 +0000 Subject: [PATCH 11/60] example-calls for get/set/del Favs --- assets/js/sections/qso.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/assets/js/sections/qso.js b/assets/js/sections/qso.js index 02acf4fc..067d72a1 100644 --- a/assets/js/sections/qso.js +++ b/assets/js/sections/qso.js @@ -4,6 +4,34 @@ $( document ).ready(function() { save_fav(); }); + $('#start_date').click(function (event) { + get_fav(); + }); + + function del_fav(name) { + $.ajax({ + url: base_url+'index.php/user_options/del_fav', + method: 'GET', + dataType: 'json', + contentType: "application/json; charset=utf-8", + data: { "option_name": name }, + success: function(result) { + } + }); + } + + function get_fav() { + $.ajax({ + url: base_url+'index.php/user_options/get_fav', + method: 'GET', + dataType: 'json', + contentType: "application/json; charset=utf-8", + success: function(result) { + console.log(result); + } + }); + } + function save_fav() { var payload={}; payload.sat_name=$('#sat_name').val(); From 8fc412a1af511179433f93257cb912a082974b3d Mon Sep 17 00:00:00 2001 From: int2001 Date: Fri, 18 Aug 2023 16:54:50 +0000 Subject: [PATCH 12/60] Added Prototype UI and Migrationscript --- application/config/migration.php | 2 +- application/controllers/User_options.php | 2 +- application/language/english/qso_lang.php | 1 + application/language/german/qso_lang.php | 2 ++ application/views/qso/index.php | 12 ++++++++- assets/js/sections/qso.js | 31 ++++++++++++++++++----- 6 files changed, 40 insertions(+), 10 deletions(-) diff --git a/application/config/migration.php b/application/config/migration.php index 70bc112e..51eebc64 100644 --- a/application/config/migration.php +++ b/application/config/migration.php @@ -22,7 +22,7 @@ $config['migration_enabled'] = TRUE; | */ -$config['migration_version'] = 137; +$config['migration_version'] = 138; /* |-------------------------------------------------------------------------- diff --git a/application/controllers/User_options.php b/application/controllers/User_options.php index 864bc090..77fc477c 100755 --- a/application/controllers/User_options.php +++ b/application/controllers/User_options.php @@ -15,7 +15,7 @@ class User_Options extends CI_Controller { $obj[$option_key]=$this->security->xss_clean($option_value); } if ($obj['sat_name'] ?? '' != '') { - $option_name=$obj['sat_name']; + $option_name=$obj['sat_name'].'/'.$obj['mode']; } else { $option_name=$obj['band'].'/'.$obj['mode']; } diff --git a/application/language/english/qso_lang.php b/application/language/english/qso_lang.php index 3b27929f..c8acea22 100644 --- a/application/language/english/qso_lang.php +++ b/application/language/english/qso_lang.php @@ -32,3 +32,4 @@ $lang['qso_btn_edit_qso'] = 'Edit QSO'; // QSO Details $lang['qso_details'] = 'QSO Details'; +$lang['fav_add'] = 'Add Band/Mode to Favs'; diff --git a/application/language/german/qso_lang.php b/application/language/german/qso_lang.php index 0f1b0949..d7dfd357 100644 --- a/application/language/german/qso_lang.php +++ b/application/language/german/qso_lang.php @@ -32,3 +32,5 @@ $lang['qso_btn_edit_qso'] = 'Editiere QSO'; // QSO Details $lang['qso_details'] = 'QSO Details'; + +$lang['fav_add'] = 'Band/Mode zu Favoriten hinzufügen'; diff --git a/application/views/qso/index.php b/application/views/qso/index.php index 4a8ac031..3b5ae78c 100755 --- a/application/views/qso/index.php +++ b/application/views/qso/index.php @@ -34,7 +34,17 @@ - + + + +
diff --git a/assets/js/sections/qso.js b/assets/js/sections/qso.js index 067d72a1..b914ee9a 100644 --- a/assets/js/sections/qso.js +++ b/assets/js/sections/qso.js @@ -1,13 +1,25 @@ $( document ).ready(function() { - $('#start_time').click(function (event) { +var favs={}; + get_fav(); + + $('#fav_add').click(function (event) { save_fav(); }); - $('#start_date').click(function (event) { - get_fav(); + $(document).on("click", "#fav_recall", function (event) { + console.log(favs[this.innerText]); + $('#sat_name').val(favs[this.innerText].sat_name); + $('#sat_mode').val(favs[this.innerText].sat_mode); + $('#band_rx').val(favs[this.innerText].band_rx); + $('#band').val(favs[this.innerText].band); + $('#frequency_rx').val(favs[this.innerText].frequency_rx); + $('#frequency').val(favs[this.innerText].frequency); + $('#selectPropagation').val(favs[this.innerText].prop_mode); + $('#mode').val(favs[this.innerText].mode); }); + function del_fav(name) { $.ajax({ url: base_url+'index.php/user_options/del_fav', @@ -27,7 +39,11 @@ $( document ).ready(function() { dataType: 'json', contentType: "application/json; charset=utf-8", success: function(result) { - console.log(result); + $("#fav_menu").empty(); + for (const key in result) { + $("#fav_menu").append(''+key+''); + } + favs=result; } }); } @@ -35,12 +51,12 @@ $( document ).ready(function() { function save_fav() { var payload={}; payload.sat_name=$('#sat_name').val(); - payload.sat_mode=$('#sat_name').val(); + payload.sat_mode=$('#sat_mode').val(); payload.band_rx=$('#band_rx').val(); payload.band=$('#band').val(); - payload.frequency_tx=$('#frequency_rx').val(); + payload.frequency_rx=$('#frequency_rx').val(); payload.frequency=$('#frequency').val(); - payload.prop_mode=$('#prop_mode').val(); + payload.prop_mode=$('#selectPropagation').val(); payload.mode=$('#mode').val(); $.ajax({ url: base_url+'index.php/user_options/add_edit_fav', @@ -49,6 +65,7 @@ $( document ).ready(function() { contentType: "application/json; charset=utf-8", data: JSON.stringify(payload), success: function(result) { + get_fav(); } }); } From 389d9fe06b59c88a940139a774e674b1a0165532 Mon Sep 17 00:00:00 2001 From: Andreas <6977712+AndreasK79@users.noreply.github.com> Date: Fri, 18 Aug 2023 20:02:47 +0200 Subject: [PATCH 13/60] [Advanced Logbook] Added map that uses the same filters as the search --- application/controllers/Logbookadvanced.php | 129 ++++ application/models/Logbookadvanced_model.php | 19 +- application/views/logbookadvanced/index.php | 647 ++++++++++--------- assets/css/general.css | 5 + assets/js/sections/logbookadvanced.js | 214 ++++++ 5 files changed, 707 insertions(+), 307 deletions(-) diff --git a/application/controllers/Logbookadvanced.php b/application/controllers/Logbookadvanced.php index f25fe68f..87a54e92 100644 --- a/application/controllers/Logbookadvanced.php +++ b/application/controllers/Logbookadvanced.php @@ -233,4 +233,133 @@ class Logbookadvanced extends CI_Controller { $data['qslimages'] = $this->logbookadvanced_model->getQslsForQsoIds($cleanids); $this->load->view('logbookadvanced/qslcarousel', $data); } + + public function mapQsos() { + $this->load->model('logbookadvanced_model'); + + $searchCriteria = array( + 'user_id' => (int)$this->session->userdata('user_id'), + 'dateFrom' => xss_clean($this->input->post('dateFrom')), + 'dateTo' => xss_clean($this->input->post('dateTo')), + 'de' => xss_clean($this->input->post('de')), + 'dx' => xss_clean($this->input->post('dx')), + 'mode' => xss_clean($this->input->post('mode')), + 'band' => xss_clean($this->input->post('band')), + 'qslSent' => xss_clean($this->input->post('qslSent')), + 'qslReceived' => xss_clean($this->input->post('qslReceived')), + 'iota' => xss_clean($this->input->post('iota')), + 'dxcc' => xss_clean($this->input->post('dxcc')), + 'propmode' => xss_clean($this->input->post('propmode')), + 'gridsquare' => xss_clean($this->input->post('gridsquare')), + 'state' => xss_clean($this->input->post('state')), + 'cqzone' => xss_clean($this->input->post('cqzone')), + 'qsoresults' => xss_clean($this->input->post('qsoresults')), + 'sats' => xss_clean($this->input->post('sats')), + 'lotwSent' => xss_clean($this->input->post('lotwSent')), + 'lotwReceived' => xss_clean($this->input->post('lotwReceived')), + 'eqslSent' => xss_clean($this->input->post('eqslSent')), + 'eqslReceived' => xss_clean($this->input->post('eqslReceived')), + 'qslvia' => xss_clean($this->input->post('qslvia')), + 'sota' => xss_clean($this->input->post('sota')), + 'pota' => xss_clean($this->input->post('pota')), + 'wwff' => xss_clean($this->input->post('wwff')), + 'qslimages' => xss_clean($this->input->post('qslimages')), + ); + + if ($this->session->userdata('user_measurement_base') == NULL) { + $measurement_base = $this->config->item('measurement_base'); + } + else { + $measurement_base = $this->session->userdata('user_measurement_base'); + } + + $CI =& get_instance(); + // Get Date format + if($CI->session->userdata('user_date_format')) { + // If Logged in and session exists + $custom_date_format = $CI->session->userdata('user_date_format'); + } else { + // Get Default date format from /config/cloudlog.php + $custom_date_format = $CI->config->item('qso_date_format'); + } + + switch ($measurement_base) { + case 'M': + $var_dist = " miles"; + break; + case 'N': + $var_dist = " nautic miles"; + break; + case 'K': + $var_dist = " kilometers"; + break; + } + + $mappedcoordinates = array(); + foreach ($this->logbookadvanced_model->searchDb($searchCriteria) as $qso) { + if (!empty($qso['COL_MY_GRIDSQUARE']) || !empty($qso['COL_MY_VUCC_GRIDS'])) { + if (!empty($qso['COL_GRIDSQUARE']) || !empty($qso['COL_VUCC_GRIDS'])) { + $mappedcoordinates[] = $this->calculate($qso, ($qso['COL_MY_GRIDSQUARE'] ?? '') == '' ? $qso['COL_MY_VUCC_GRIDS'] : $qso['COL_MY_GRIDSQUARE'], ($qso['COL_GRIDSQUARE'] ?? '') == '' ? $qso['COL_VUCC_GRIDS'] : $qso['COL_GRIDSQUARE'], $measurement_base, $var_dist, $custom_date_format); + } else { + if (!empty($qso['lat']) || !empty($qso['long'])) { + $mappedcoordinates[] = $this->calculateCoordinates($qso, $qso['lat'], $qso['long'], ($qso['COL_MY_GRIDSQUARE'] ?? '') == '' ? $qso['COL_MY_VUCC_GRIDS'] : $qso['COL_MY_GRIDSQUARE'], $measurement_base, $var_dist, $custom_date_format); + } + } + } + } + + header("Content-Type: application/json"); + print json_encode($mappedcoordinates); + } + + public function calculate($qso, $locator1, $locator2, $measurement_base, $var_dist, $custom_date_format) { + $this->load->library('Qra'); + + $data['distance'] = $this->qra->distance($locator1, $locator2, $measurement_base) . $var_dist; + $data['bearing'] = $this->qra->get_bearing($locator1, $locator2) . "º"; + $latlng1 = $this->qra->qra2latlong($locator1); + $latlng2 = $this->qra->qra2latlong($locator2); + $latlng1[0] = number_format((float)$latlng1[0], 3, '.', '');; + $latlng1[1] = number_format((float)$latlng1[1], 3, '.', '');; + $latlng2[0] = number_format((float)$latlng2[0], 3, '.', '');; + $latlng2[1] = number_format((float)$latlng2[1], 3, '.', '');; + + $data['latlng1'] = $latlng1; + $data['latlng2'] = $latlng2; + + $data['callsign'] = $qso['COL_CALL']; + $data['band'] = $qso['COL_BAND']; + $data['mode'] = $qso['COL_MODE']; + $data['gridsquare'] = $locator2; + $data['mygridsquare'] = $locator1; + $data['mycallsign'] = $qso['station_callsign']; + $data['datetime'] = date($custom_date_format, strtotime($qso['COL_TIME_ON'])). date(' H:i',strtotime($qso['COL_TIME_ON'])); + $data['satname'] = $qso['COL_SAT_NAME']; + + return $data; + } + + public function calculateCoordinates($qso, $lat, $long, $mygrid, $measurement_base, $var_dist, $custom_date_format) { + $this->load->library('Qra'); + + $latlng1 = $this->qra->qra2latlong($mygrid); + $latlng2[0] = $lat; + $latlng2[1] = $long; + $latlng1[0] = number_format((float)$latlng1[0], 3, '.', '');; + $latlng1[1] = number_format((float)$latlng1[1], 3, '.', '');; + $latlng2[0] = number_format((float)$latlng2[0], 3, '.', '');; + $latlng2[1] = number_format((float)$latlng2[1], 3, '.', '');; + + $data['latlng1'] = $latlng1; + $data['latlng2'] = $latlng2; + $data['callsign'] = $qso['COL_CALL']; + $data['band'] = $qso['COL_BAND']; + $data['mode'] = $qso['COL_MODE']; + $data['mygridsquare'] = $mygrid; + $data['mycallsign'] = $qso['station_callsign']; + $data['datetime'] = date($custom_date_format, strtotime($qso['COL_TIME_ON'])). date(' H:i',strtotime($qso['COL_TIME_ON'])); + $data['satname'] = $qso['COL_SAT_NAME']; + + return $data; + } } diff --git a/application/models/Logbookadvanced_model.php b/application/models/Logbookadvanced_model.php index de032084..988e574d 100644 --- a/application/models/Logbookadvanced_model.php +++ b/application/models/Logbookadvanced_model.php @@ -2,11 +2,8 @@ use Cloudlog\QSLManager\QSO; class Logbookadvanced_model extends CI_Model { - /* - * @param array $searchCriteria - * @return array - */ - public function searchQsos($searchCriteria) : array { + + public function searchDb($searchCriteria) { $conditions = []; $binding = [$searchCriteria['user_id']]; @@ -202,12 +199,22 @@ class Logbookadvanced_model extends CI_Model { $results = $data->result('array'); + return $results; + } + + /* + * @param array $searchCriteria + * @return array + */ + public function searchQsos($searchCriteria) : array { + $results = $this->searchDb($searchCriteria); + $qsos = []; foreach ($results as $data) { $qsos[] = new QSO($data); } - return $qsos; + return $qsos; } public function getQsosForAdif($ids, $user_id, $sortorder = null) : object { diff --git a/application/views/logbookadvanced/index.php b/application/views/logbookadvanced/index.php index 49d63ce3..bd7fee3b 100644 --- a/application/views/logbookadvanced/index.php +++ b/application/views/logbookadvanced/index.php @@ -1,63 +1,93 @@ +
- session->flashdata('message')) { ?> - -
-

session->flashdata('message'); ?>

-
- -
+ session->flashdata('message')) { ?> + +
+

session->flashdata('message'); ?>

+
+ +
-
" method="post"> -
-
-
- -
- -
-
-
-
-
-
- -
- -
-
-
-
-
-
- - +
+
+
+
+
+
+ +
+ +
+
+
+
+
+
+ + -
-
- - -
-
- - +
+
+ + -
-
- - + + tag; echo '>' . $iota->tag . ' - ' . $iota->name . ''; } ?> - -
-
- - -
-
- - -
-
- - +
+
+ + +
+
+ + -
-
- - + + - -
- -
- - -
-
- - + + + + + + + + + + + + + + + + + + + + +
+
+ + -
-
- - -
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - - - - - - - - -
-
- - -
-
-
+ ?> + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + + + + + + + + +
+
+ + +
+
+
-
-
- With selected: - - - - - - - - - - - - - - - -
-
-
-
- Quick search with selected: - - - - - - - - - - - -
-
- +
+
+ With selected: + + + + + + + + + + + + + + + +
+
+
+
+ Quick search with selected: + + + + + + + + + + + +
+
-
- - - - - - - +
+ + + + + + + + + +
-
- - - - - - - - - - - - - - - - - session->userdata('user_eqsl_name') != ""){ +
Date/TimeDeDxModeRST (S)RST (R)BandMy RefsRefsNameQSL ViaQSL
+ + + + + + + + + + + + + + + + session->userdata('user_eqsl_name') != ""){ echo ''; } ?> - session->userdata('user_lotw_name') != ""){ + session->userdata('user_lotw_name') != ""){ echo ''; } ?> - - - - - - - - - -
+
+
Date/TimeDeDxModeRST (S)RST (R)BandMy RefsRefsNameQSL ViaQSLeQSLLoTWQSL MsgDXCCStateCQ ZoneIOTA
+ QSL Msg + DXCC + State + CQ Zone + IOTA + + + + + diff --git a/assets/css/general.css b/assets/css/general.css index a4705e96..b9ad60e1 100644 --- a/assets/css/general.css +++ b/assets/css/general.css @@ -515,4 +515,9 @@ div#station_logbooks_linked_table_paginate { .previous-qsos table { margin-bottom: 0px; +} + +#advancedmap { + height: calc(100vh - 280px) !important; + max-height: 1000px !important; } \ No newline at end of file diff --git a/assets/js/sections/logbookadvanced.js b/assets/js/sections/logbookadvanced.js index 63f92de5..d91c4f98 100644 --- a/assets/js/sections/logbookadvanced.js +++ b/assets/js/sections/logbookadvanced.js @@ -167,6 +167,17 @@ $(document).ready(function () { }); $('#searchForm').submit(function (e) { + var container = L.DomUtil.get('advancedmap'); + + if(container != null){ + container._leaflet_id = null; + container.remove(); + } + + $("#qsoList").attr("Hidden", false); + $("#qsoList_wrapper").attr("Hidden", false); + $("#qsoList_info").attr("Hidden", false); + $('#searchButton').prop("disabled", true); $.ajax({ @@ -675,3 +686,206 @@ function printlabel() { }); } +function mapQsos(form) { + $('#mapButton').prop("disabled", true); + + $("#qsoList").attr("Hidden", true); + $("#qsoList_wrapper").attr("Hidden", true); + $("#qsoList_info").attr("Hidden", true); + + var amap = $('#advancedmap').val(); + if (amap == undefined) { + $(".qso_manager").append('
'); + } + + $.ajax({ + url: base_url + 'index.php/logbookadvanced/mapQsos', + type: 'post', + data: { + dateFrom: this.dateFrom.value, + dateTo: this.dateTo.value, + de: this.de.value, + dx: this.dx.value, + mode: this.mode.value, + band: this.band.value, + qslSent: this.qslSent.value, + qslReceived: this.qslReceived.value, + iota: this.iota.value, + dxcc: this.dxcc.value, + propmode: this.selectPropagation.value, + gridsquare: this.gridsquare.value, + state: this.state.value, + qsoresults: this.qsoResults.value, + sats: this.sats.value, + cqzone: this.cqzone.value, + lotwSent: this.lotwSent.value, + lotwReceived: this.lotwReceived.value, + eqslSent: this.eqslSent.value, + eqslReceived: this.eqslReceived.value, + qslvia: $('[name="qslviainput"]').val(), + sota: this.sota.value, + pota: this.pota.value, + wwff: this.wwff.value, + qslimages: this.qslimages.value, + }, + success: function(data) { + loadMap(data); + }, + error: function() { + $('#mapButton').prop("disabled", false); + }, + }); + +}; + +function loadMap(data) { + $('#mapButton').prop("disabled", false); + var osmUrl='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; + var osmAttrib='Map data © OpenStreetMap contributors'; + // If map is already initialized + var container = L.DomUtil.get('advancedmap'); + + if(container != null){ + container._leaflet_id = null; + container.remove(); + $(".qso_manager").append('
'); + } + + var map = new L.Map('advancedmap', { + fullscreenControl: true, + fullscreenControlOptions: { + position: 'topleft' + }, + }); + + L.tileLayer( + osmUrl, + { + attribution: '© OpenStreetMap contributors, CC-BY-SA', + maxZoom: 18, + zoom: 3, + minZoom: 2, + } + ).addTo(map); + + map.setView([30, 0], 1.5); + + var maidenhead = L.maidenheadqrb().addTo(map); + + var osm = new L.TileLayer(osmUrl, {minZoom: 1, maxZoom: 9, attribution: osmAttrib}); + + map.addLayer(osm); + + var redIcon = L.icon({ + iconUrl: icon_dot_url, + iconSize: [10, 10], // size of the icon + }); + + var counter = 0; + + $.each(data, function(k, v) { + counter++; + // Need to fix so that marker is placed at same place as end of line, but this only needs to be done when longitude is < -170 + if (this.latlng2[1] < -170) { + this.latlng2[1] = parseFloat(this.latlng2[1])+360; + } + if (this.latlng1[1] < -170) { + this.latlng1[1] = parseFloat(this.latlng1[1])+360; + } + + var popupmessage = createContentMessage(this); + var popupmessage2 = createContentMessageDx(this); + + var marker = L.marker([this.latlng1[0], this.latlng1[1]], {icon: redIcon}, {closeOnClick: false, autoClose: false}).addTo(map).bindPopup(popupmessage); + marker.on('mouseover',function(ev) { + ev.target.openPopup(); + }); + + var marker2 = L.marker([this.latlng2[0], this.latlng2[1]], {icon: redIcon},{closeOnClick: false, autoClose: false}).addTo(map).bindPopup(popupmessage2);; + marker2.on('mouseover',function(ev) { + ev.target.openPopup(); + }); + + const multiplelines = []; + multiplelines.push( + new L.LatLng(this.latlng1[0], this.latlng1[1]), + new L.LatLng(this.latlng2[0], this.latlng2[1]) + ) + + const geodesic = L.geodesic(multiplelines, { + weight: 1, + opacity: 1, + color: 'red', + wrap: false, + steps: 100 + }).addTo(map); + }); + + /*Legend specific*/ + var legend = L.control({ position: "topright" }); + + legend.onAdd = function(map) { + var div = L.DomUtil.create("div", "legend"); + div.innerHTML += "

" + counter + " QSOs plotted

"; + return div; + }; + + legend.addTo(map); +} + + function createContentMessage(qso) { + var table = '' + + '' + + '" + + '' + + '"; + return (table += "
' + + 'Station callsign: ' + qso.mycallsign + + "
' + + 'Gridsquare: ' + qso.mygridsquare + + "
"); + } + + function createContentMessageDx(qso) { + var table = '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + ''; + if (qso.satname != "") { + table += '' + + '' + + '' + + ''; + } else { + table += '' + + '' + + '' + + ''; + } + table += '' + + '' + + '' + + ''; + if (qso.gridsquare != undefined) { + table += '' + + '' + + ''; + } + if (qso.distance != undefined) { + table += '' + + '' + + ''; + } + if (qso.bearing != undefined) { + table += '' + + '' + + ''; + } + return (table += '
Callsign' + qso.callsign + '
Date/time' + qso.datetime + '
Band' + qso.satname + '
Band' + qso.band + '
Mode' + qso.mode + '
Gridsquare' + qso.gridsquare + '
Distance' + qso.distance + '
Bearing' + qso.bearing + '
'); + } From a75257d70674eea4035f55699af9283a58f6a74c Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Fri, 18 Aug 2023 21:38:34 +0100 Subject: [PATCH 14/60] [LoTW] Remove unneeded margin at the bottom of the table --- assets/css/general.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/assets/css/general.css b/assets/css/general.css index a4705e96..ac8ef98f 100644 --- a/assets/css/general.css +++ b/assets/css/general.css @@ -515,4 +515,8 @@ div#station_logbooks_linked_table_paginate { .previous-qsos table { margin-bottom: 0px; +} + +.lotw-cert-list table { + margin-bottom: 0px; } \ No newline at end of file From b56c39db6fa455e80aba6e4da5542429509d5d26 Mon Sep 17 00:00:00 2001 From: int2001 Date: Sat, 19 Aug 2023 04:11:41 +0000 Subject: [PATCH 15/60] Reload-favs after save --- application/controllers/User_options.php | 9 +++++++-- assets/js/sections/qso.js | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/application/controllers/User_options.php b/application/controllers/User_options.php index 77fc477c..46d1150d 100755 --- a/application/controllers/User_options.php +++ b/application/controllers/User_options.php @@ -19,7 +19,10 @@ class User_Options extends CI_Controller { } else { $option_name=$obj['band'].'/'.$obj['mode']; } - return $this->user_options_model->set_option('Favourite',$option_name, $obj); + $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() { @@ -38,7 +41,9 @@ class User_Options extends CI_Controller { $option_name=$this->security->xss_clean($obj['option_name']); $this->user_options_model->del_option('Favourite',$option_name); } - return; + $jsonout['success']=1; + header('Content-Type: application/json'); + echo json_encode($jsonout); } } diff --git a/assets/js/sections/qso.js b/assets/js/sections/qso.js index b914ee9a..dc2fa377 100644 --- a/assets/js/sections/qso.js +++ b/assets/js/sections/qso.js @@ -23,11 +23,12 @@ var favs={}; function del_fav(name) { $.ajax({ url: base_url+'index.php/user_options/del_fav', - method: 'GET', + method: 'POST', dataType: 'json', contentType: "application/json; charset=utf-8", data: { "option_name": name }, success: function(result) { + get_fav(); } }); } From aca01fabb5e5335b144e2bf47c21725a8da95e9e Mon Sep 17 00:00:00 2001 From: int2001 Date: Sat, 19 Aug 2023 04:50:18 +0000 Subject: [PATCH 16/60] Now delete is working, too --- assets/js/sections/qso.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/assets/js/sections/qso.js b/assets/js/sections/qso.js index dc2fa377..24015e57 100644 --- a/assets/js/sections/qso.js +++ b/assets/js/sections/qso.js @@ -7,6 +7,10 @@ var favs={}; save_fav(); }); + $(document).on("click", "#fav_del", function (event) { + del_fav($(this).attr('name')); + }); + $(document).on("click", "#fav_recall", function (event) { console.log(favs[this.innerText]); $('#sat_name').val(favs[this.innerText].sat_name); @@ -26,7 +30,7 @@ var favs={}; method: 'POST', dataType: 'json', contentType: "application/json; charset=utf-8", - data: { "option_name": name }, + data: JSON.stringify({ "option_name": name }), success: function(result) { get_fav(); } @@ -42,7 +46,7 @@ var favs={}; success: function(result) { $("#fav_menu").empty(); for (const key in result) { - $("#fav_menu").append(''+key+''); + $("#fav_menu").append(''); } favs=result; } From 3a6d2d8a2a7c09c93d5e7d0593416dc8e73f8d86 Mon Sep 17 00:00:00 2001 From: int2001 Date: Sat, 19 Aug 2023 04:55:59 +0000 Subject: [PATCH 17/60] cosmetics: star-icon instead of "FAV" --- application/views/qso/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/views/qso/index.php b/application/views/qso/index.php index 3b5ae78c..05a55f52 100755 --- a/application/views/qso/index.php +++ b/application/views/qso/index.php @@ -36,7 +36,7 @@