Get 2.6.22 ready for release

Get 2.6.22 ready for release
这个提交包含在:
Peter Goodhall 2025-08-02 13:14:51 +01:00 提交者 GitHub
当前提交 30fe639c79
找不到此签名对应的密钥
GPG 密钥 ID: B5690EEEBB952194
共有 13 个文件被更改,包括 377 次插入76 次删除

查看文件

@ -22,7 +22,7 @@ $config['migration_enabled'] = TRUE;
|
*/
$config['migration_version'] = 203;
$config['migration_version'] = 204;
/*
|--------------------------------------------------------------------------

查看文件

@ -814,4 +814,129 @@ class API extends CI_Controller {
$latlng = $this->qra->qra2latlong($qra);
return $latlng;
}
/**
* API endpoint to get recent QSOs from a public logbook
*
* @api GET /api/recent_qsos/{public_slug}/{limit}
*
* @param string public_slug Required. Public slug identifier for the logbook
* @param int limit Optional. Number of QSOs to return (default: 10, max: 50)
*
* @return json Returns JSON array with recent QSO data or error message
*
* @throws 404 Not Found - Logbook not found or empty logbook
* @throws 400 Bad Request - Invalid limit parameter
*
* @example
* Request: GET /api/recent_qsos/my-public-logbook/5
*
* Response:
* {
* "qsos": [
* {
* "date": "2024-01-15",
* "time": "14:30",
* "callsign": "W1AW",
* "mode": "SSB",
* "band": "20M",
* "rst_sent": "59",
* "rst_rcvd": "59"
* }
* ],
* "count": 1,
* "logbook_slug": "my-public-logbook"
* }
*/
function recent_qsos($public_slug = null, $limit = 10) {
header('Content-type: application/json');
if($public_slug == null) {
http_response_code(400);
echo json_encode(['status' => 'failed', 'reason' => 'missing public_slug parameter']);
return;
}
// Validate and sanitize limit parameter
$limit = intval($limit);
if ($limit <= 0) {
$limit = 10; // default
}
if ($limit > 50) {
$limit = 50; // maximum
}
$this->load->model('logbooks_model');
$this->load->model('logbook_model');
if($this->logbooks_model->public_slug_exists($public_slug)) {
$logbook_id = $this->logbooks_model->public_slug_exists_logbook_id($public_slug);
if($logbook_id != false) {
// Get associated station locations for mysql queries
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($logbook_id);
if (!$logbooks_locations_array) {
http_response_code(404);
echo json_encode(['status' => 'failed', 'reason' => 'Empty Logbook']);
return;
}
// Get recent QSOs using existing method
$recent_qsos_query = $this->logbook_model->get_last_qsos($limit, $logbooks_locations_array);
if ($recent_qsos_query == null) {
http_response_code(404);
echo json_encode(['status' => 'failed', 'reason' => 'No QSOs found']);
return;
}
// Format the data for JSON response
$qsos = array();
foreach ($recent_qsos_query->result() as $row) {
$qso = array(
'date' => date('Y-m-d', strtotime($row->COL_TIME_ON)),
'time' => date('H:i', strtotime($row->COL_TIME_ON)),
'callsign' => strtoupper($row->COL_CALL),
'mode' => $row->COL_SUBMODE ? $row->COL_SUBMODE : $row->COL_MODE,
'band' => $row->COL_SAT_NAME ? $row->COL_SAT_NAME : $row->COL_BAND,
'rst_sent' => $row->COL_RST_SENT,
'rst_rcvd' => $row->COL_RST_RCVD
);
// Add optional fields if they exist
if ($row->COL_STX_STRING) {
$qso['stx_string'] = $row->COL_STX_STRING;
}
if ($row->COL_SRX_STRING) {
$qso['srx_string'] = $row->COL_SRX_STRING;
}
if ($row->COL_GRIDSQUARE) {
$qso['gridsquare'] = $row->COL_GRIDSQUARE;
}
if ($row->COL_QTH) {
$qso['qth'] = $row->COL_QTH;
}
if ($row->COL_NAME) {
$qso['name'] = $row->COL_NAME;
}
$qsos[] = $qso;
}
http_response_code(200);
echo json_encode([
'qsos' => $qsos,
'count' => count($qsos),
'logbook_slug' => $public_slug
], JSON_PRETTY_PRINT);
} else {
http_response_code(404);
echo json_encode(['status' => 'failed', 'reason' => $public_slug.' has no associated station locations']);
}
} else {
http_response_code(404);
echo json_encode(['status' => 'failed', 'reason' => 'logbook not found']);
}
}
}

查看文件

@ -324,7 +324,7 @@ class Qrz extends CI_Controller {
// Return the structured error array here too for consistency
return ['status' => 'error', 'message' => $error_message];
}
$url = 'http://logbook.qrz.com/api'; // Correct URL
$url = 'https://logbook.qrz.com/api'; // Correct URL
$post_data['KEY'] = $qrz_api_key; // Correct parameter
$post_data['ACTION'] = 'FETCH'; // Correct parameter
@ -336,11 +336,35 @@ class Qrz extends CI_Controller {
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1); // Okay
curl_setopt( $ch, CURLOPT_HEADER, 0); // Correct - don't need response headers
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true); // Correct - get response as string
curl_setopt( $ch, CURLOPT_TIMEOUT, 300); // 5 minute timeout
curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, 30); // 30 second connection timeout
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
curl_setopt($ch, CURLOPT_BUFFERSIZE, 128000);
curl_setopt($ch, CURLOPT_ENCODING, 'gzip, deflate');
$content = curl_exec($ch); // Get raw content
$curl_error = curl_error($ch); // Check for cURL errors
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); // Get HTTP response code
curl_close($ch);
if ($curl_error) { // Check for cURL level errors first
$error_message = "QRZ download cURL error: " . $curl_error;
log_message('error', $error_message . ' API Key used: ' . $qrz_api_key);
return ['status' => 'error', 'message' => $error_message];
}
if ($http_code !== 200) {
$error_message = "QRZ download HTTP error: HTTP " . $http_code;
log_message('error', $error_message . ' API Key used: ' . $qrz_api_key);
return ['status' => 'error', 'message' => $error_message];
}
if ($content === false || $content === '') { // Check if curl_exec failed or returned empty
$error_message = "QRZ download failed: No content received from QRZ.com.";
log_message('error', $error_message . ' API Key used: ' . $qrz_api_key);
return ['status' => 'error', 'message' => $error_message];
}
// Find the start of the ADIF data after "ADIF="
$adif_start_pos = strpos($content, 'ADIF=');
if ($adif_start_pos !== false) {
@ -388,18 +412,6 @@ class Qrz extends CI_Controller {
$content = substr($content, 0, $truncate_pos);
}
if ($curl_error) { // Check for cURL level errors first
$error_message = "QRZ download cURL error: " . $curl_error;
log_message('error', $error_message . ' API Key used: ' . $qrz_api_key);
return ['status' => 'error', 'message' => $error_message];
}
if ($content === false || $content === '') { // Check if curl_exec failed or returned empty
$error_message = "QRZ download failed: No content received from QRZ.com.";
log_message('error', $error_message . ' API Key used: ' . $qrz_api_key);
return ['status' => 'error', 'message' => $error_message];
}
// Check for QRZ API specific error messages
if (strpos($content, 'STATUS=FAIL') !== false || strpos($content, 'STATUS=AUTH') !== false) {
// Extract reason if possible, otherwise use full content
@ -446,7 +458,7 @@ class Qrz extends CI_Controller {
$config['qrz_rcvd_mark'] = 'Y';
ini_set('memory_limit', '-1');
set_time_limit(0);
set_time_limit(1800); // 30 minutes max execution time instead of unlimited
$this->load->library('adif_parser');
@ -475,8 +487,24 @@ class Qrz extends CI_Controller {
$batch_data = [];
$batch_size = 500; // Process 500 records at a time
$record_count = 0; // Initialize record counter
$max_records = 50000; // Safety limit to prevent runaway processing
$start_time = time(); // Track processing time
$max_processing_time = 1200; // 20 minutes max for processing
while ($record = $this->adif_parser->get_record()) {
$record_count++; // Increment counter for each record read
// Safety checks to prevent runaway processing
if ($record_count > $max_records) {
log_message('error', 'QRZ download: Exceeded maximum record limit of ' . $max_records . ' records. Processing stopped.');
break;
}
if ((time() - $start_time) > $max_processing_time) {
log_message('error', 'QRZ download: Exceeded maximum processing time of ' . $max_processing_time . ' seconds. Processing stopped at record ' . $record_count . '.');
break;
}
if ((!(isset($record['app_qrzlog_qsldate']))) || (!(isset($record['qso_date'])))) {
continue;
}
@ -509,6 +537,12 @@ class Qrz extends CI_Controller {
if (count($batch_data) >= $batch_size) {
$table .= $this->logbook_model->process_qrz_batch($batch_data);
$batch_data = []; // Reset batch
// Log progress every 1000 records to help monitor long-running processes
if ($record_count % 1000 == 0) {
$elapsed_time = time() - $start_time;
log_message('info', 'QRZ download progress: ' . $record_count . ' records processed in ' . $elapsed_time . ' seconds.');
}
}
}
@ -517,6 +551,10 @@ class Qrz extends CI_Controller {
$table .= $this->logbook_model->process_qrz_batch($batch_data);
}
// Log successful completion with statistics
$processing_time = time() - $start_time;
log_message('info', 'QRZ download completed successfully. Processed ' . $record_count . ' records in ' . $processing_time . ' seconds.');
if ($table != "") {
$data['tableheaders'] = $tableheaders;
$data['table'] = $table;

查看文件

@ -41,6 +41,13 @@ class QSO extends CI_Controller {
$data['user_default_band'] = $this->session->userdata('user_default_band');
$data['sat_active'] = array_search("SAT", $this->bands->get_user_bands(), true);
// Set user's preferred date format
if($this->session->userdata('user_date_format')) {
$data['user_date_format'] = $this->session->userdata('user_date_format');
} else {
$data['user_date_format'] = $this->config->item('qso_date_format');
}
$this->load->library('form_validation');
$this->form_validation->set_rules('start_date', 'Date', 'required');

查看文件

@ -83,6 +83,8 @@ class Station extends CI_Controller {
$this->load->view('station_profile/edit');
$this->load->view('interface_assets/footer');
} else {
// Get all the posted data from the form and save it to log file
if ($this->stations->edit() !== false) {
// [eQSL default msg] ADD to user options (option_type='eqsl_default_qslmsg'; option_name='key_station_id'; option_key=station_id; option_value=value) //
$eqsl_default_qslmsg = xss_clean($this->input->post('eqsl_default_qslmsg', true));

查看文件

@ -0,0 +1,30 @@
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
/*
* Tag Cloudlog as 2.6.22
*/
class Migration_tag_2_6_22 extends CI_Migration {
public function up()
{
// Tag Cloudlog 2.6.22
$this->db->where('option_name', 'version');
$this->db->update('options', array('option_value' => '2.6.22'));
// Trigger Version Info Dialog
$this->db->where('option_type', 'version_dialog');
$this->db->where('option_name', 'confirmed');
$this->db->update('user_options', array('option_value' => 'false'));
}
public function down()
{
$this->db->where('option_name', 'version');
$this->db->update('options', array('option_value' => '2.6.21'));
}
}

查看文件

@ -8,10 +8,11 @@ class Logbook_model extends CI_Model
{
$callsign = str_replace('Ø', '0', $this->input->post('callsign'));
// Join date+time
$datetime = date("Y-m-d", strtotime($this->input->post('start_date'))) . " " . $this->input->post('start_time');
// Join date+time - Parse date according to user's format preference
$parsed_date = $this->parse_user_date($this->input->post('start_date'));
$datetime = $parsed_date . " " . $this->input->post('start_time');
if ($this->input->post('end_time') != null) {
$datetime_off = date("Y-m-d", strtotime($this->input->post('start_date'))) . " " . $this->input->post('end_time');
$datetime_off = $parsed_date . " " . $this->input->post('end_time');
// if time off < time on, and time off is on 00:xx >> add 1 day (concidering start and end are between 23:00 and 00:59) //
$_tmp_datetime_off = strtotime($datetime_off);
if (($_tmp_datetime_off < strtotime($datetime)) && (substr($this->input->post('end_time'), 0, 2) == "00")) {
@ -4888,7 +4889,7 @@ class Logbook_model extends CI_Model
foreach ($batch_data as $record) {
$this->db->or_group_start(); // Start group for this record's AND conditions
$this->db->where($this->config->item('table_name').'.COL_CALL', $record['call']);
$this->db->where($this->config->item('table_name').'.COL_TIME_ON', $record['time_on']);
$this->db->like($this->config->item('table_name').'.COL_TIME_ON', $record['time_on'], 'after');
$this->db->where($this->config->item('table_name').'.COL_BAND', $record['band']);
$this->db->group_end(); // End group for this record's AND conditions
}
@ -4901,7 +4902,8 @@ class Logbook_model extends CI_Model
// Index DB results for faster lookup
$indexed_results = [];
foreach ($db_results as $row) {
$key = $row['COL_CALL'] . '|' . $row['COL_TIME_ON'] . '|' . $row['COL_BAND'];
$time = substr($row['COL_TIME_ON'], 0, 16);
$key = $row['COL_CALL'] . '|' . $time . '|' . $row['COL_BAND'];
$indexed_results[$key] = $row['COL_PRIMARY_KEY'];
}
@ -4919,7 +4921,7 @@ class Logbook_model extends CI_Model
$update_batch_data[] = [
'COL_PRIMARY_KEY' => $primary_key,
'COL_QRZCOM_QSO_DOWNLOAD_DATE' => $record['qsl_date'],
'COL_QRZCOM_QSO_UPLOAD_STATUS' => $record['qsl_rcvd'] // Should be 'Y' if confirmed
'COL_QRZCOM_QSO_DOWNLOAD_STATUS' => $record['qsl_rcvd'] // Should be 'Y' if confirmed
];
}
@ -4942,6 +4944,42 @@ class Logbook_model extends CI_Model
// Step 6: Return Table HTML
return $table;
}
/**
* Parse date from user input according to user's preferred date format
* @param string $date_input The date string from user input
* @param string $user_format The user's preferred date format (e.g., 'd/m/Y', 'Y-m-d')
* @return string Returns date in Y-m-d format for database storage, or original input if parsing fails
*/
private function parse_user_date($date_input, $user_format = null) {
if (empty($date_input)) {
return $date_input;
}
// If no user format provided, try to get it from session or config
if ($user_format === null) {
if ($this->session->userdata('user_date_format')) {
$user_format = $this->session->userdata('user_date_format');
} else {
$user_format = $this->config->item('qso_date_format');
}
}
// Try to parse with the user's format first
$date = DateTime::createFromFormat($user_format, $date_input);
if ($date !== false) {
return $date->format('Y-m-d');
}
// Fallback to strtotime for formats it can handle (mostly Y-m-d, m/d/Y, etc.)
$timestamp = strtotime($date_input);
if ($timestamp !== false) {
return date('Y-m-d', $timestamp);
}
// If all parsing fails, return the original input and let the database handle it
return $date_input;
}
}
// Function to validate ADIF date format

查看文件

@ -77,9 +77,9 @@ class Stations extends CI_Model {
// Check if the state is Canada and get the correct state
if ($this->input->post('dxcc') == 1 && $this->input->post('station_ca_state') !="") {
$state = $this->input->post('station_ca_state');
$state = xss_clean($this->input->post('station_ca_state', true));
} else {
$state = $this->input->post('station_state');
$state = xss_clean($this->input->post('station_state', true));
}
// Create data array with field values
@ -131,9 +131,9 @@ class Stations extends CI_Model {
// Check if the state is Canada and get the correct state
if ($this->input->post('dxcc') == 1 && $this->input->post('station_ca_state') !="") {
$state = $this->input->post('station_ca_state');
$state = xss_clean($this->input->post('station_ca_state', true));
} else {
$state = $this->input->post('station_state');
$state = xss_clean($this->input->post('station_state', true));
}
$data = array(

查看文件

@ -102,48 +102,48 @@
<div class="row">
<div class="mb-3 col-md-3">
<label for="callsign"><?php echo lang('gen_hamradio_callsign'); ?></label>
<input type="text" class="form-control form-control-sm" id="callsign" name="callsign" required pattern="\S+" title="Whitespace is not allowed">
<input type="text" class="form-control form-control-sm" id="callsign" name="callsign" required pattern="\S+" title="Whitespace is not allowed" tabindex="1">
<small id="callsign_info" class="badge text-bg-danger"></small>
</div>
<div class="mb-3 col-md-1">
<label for="rst_sent"><?php echo lang('gen_hamradio_rsts'); ?></label>
<input type="text" class="form-control form-control-sm" name="rst_sent" id="rst_sent" value="59">
<input type="text" class="form-control form-control-sm" name="rst_sent" id="rst_sent" value="59" tabindex="2">
</div>
<div style="display:none" class="mb-3 col-md-1 serials">
<label for="exch_serial_s"><?php echo lang('contesting_exchange_serial_s'); ?></label>
<input type="number" class="form-control form-control-sm" name="exch_serial_s" id="exch_serial_s" value="">
<input type="number" class="form-control form-control-sm" name="exch_serial_s" id="exch_serial_s" value="" tabindex="3">
</div>
<div style="display:none" class="mb-3 col-md-1 exchanges">
<label for="exch_sent"><?php echo lang('gen_hamradio_exchange_sent_short'); ?></label>
<input type="text" class="form-control form-control-sm" name="exch_sent" id="exch_sent" value="">
<input type="text" class="form-control form-control-sm" name="exch_sent" id="exch_sent" value="" tabindex="3">
</div>
<div style="display:none" class="mb-3 col-md-2 gridsquares">
<label for="exch_gridsquare_s"><?php echo lang('contesting_exchange_gridsquare_s'); ?></label>
<input disabled type="text" class="form-control form-control-sm" name="exch_gridsquare_s" id="exch_gridsquare_s" value="<?php echo $my_gridsquare;?>">
<input disabled type="text" class="form-control form-control-sm" name="exch_gridsquare_s" id="exch_gridsquare_s" value="<?php echo $my_gridsquare;?>" tabindex="-1">
</div>
<div class="mb-3 col-md-1">
<label for="rst_rcvd"><?php echo lang('gen_hamradio_rstr'); ?></label>
<input type="text" class="form-control form-control-sm" name="rst_rcvd" id="rst_rcvd" value="59">
<input type="text" class="form-control form-control-sm" name="rst_rcvd" id="rst_rcvd" value="59" tabindex="4">
</div>
<div style="display:none" class="mb-3 col-md-1 serialr">
<label for="exch_serial_r"><?php echo lang('contesting_exchange_serial_r'); ?></label>
<input type="number" class="form-control form-control-sm" name="exch_serial_r" id="exch_serial_r" value="">
<input type="number" class="form-control form-control-sm" name="exch_serial_r" id="exch_serial_r" value="" tabindex="5">
</div>
<div style="display:none" class="mb-3 col-md-1 exchanger">
<label for="exch_rcvd"><?php echo lang('gen_hamradio_exchange_rcvd_short'); ?></label>
<input type="text" class="form-control form-control-sm" name="exch_rcvd" id="exch_rcvd" value="">
<input type="text" class="form-control form-control-sm" name="exch_rcvd" id="exch_rcvd" value="" tabindex="5">
</div>
<div style="display:none" class="mb-3 col-md-2 gridsquarer">
<label for="exch_gridsquare_r"><?php echo lang('contesting_exchange_gridsquare_r'); ?></label>
<input type="text" class="form-control form-control-sm" name="locator" id="exch_gridsquare_r" value="">
<input type="text" class="form-control form-control-sm" name="locator" id="exch_gridsquare_r" value="" maxlength="8" tabindex="6">
</div>
</div>

查看文件

@ -45,7 +45,7 @@ if ($qsos->result() != NULL) {
foreach ($qsos->result() as $qsl) {
echo '<tr id="qslprint_'.$qsl->COL_PRIMARY_KEY.'">';
echo '<td style=\'text-align: center\'><div class="form-check"><input class="form-check-input" type="checkbox" /></div></td>';
echo '<td style=\'text-align: center\'><div class="form-check"><input class="form-check-input qso-checkbox" type="checkbox" value="'.$qsl->COL_PRIMARY_KEY.'" /></div></td>';
?><td style='text-align: center'><span class="qso_call"><a id="edit_qso" href="javascript:displayQso(<?php echo $qsl->COL_PRIMARY_KEY; ?>);"><?php echo str_replace("0","&Oslash;",strtoupper($qsl->COL_CALL)); ?></a><a target="_blank" href="https://www.qrz.com/db/<?php echo strtoupper($qsl->COL_CALL); ?>"><img width="16" height="16" src="<?php echo base_url(); ?>images/icons/qrz.png" alt="Lookup <?php echo strtoupper($qsl->COL_CALL); ?> on QRZ.com"></a> <a target="_blank" href="https://www.hamqth.com/<?php echo strtoupper($qsl->COL_CALL); ?>"><img width="16" height="16" src="<?php echo base_url(); ?>images/icons/hamqth.png" alt="Lookup <?php echo strtoupper($qsl->COL_CALL); ?> on HamQTH"></a> <a target="_blank" href="http://www.eqsl.cc/Member.cfm?<?php echo strtoupper($qsl->COL_CALL); ?>"><img width="16" height="16" src="<?php echo base_url(); ?>images/icons/eqsl.png" alt="Lookup <?php echo strtoupper($qsl->COL_CALL); ?> on eQSL.cc"></a></td><?php
echo '<td style=\'text-align: center\'>'; $timestamp = strtotime($qsl->COL_TIME_ON); echo date($custom_date_format, $timestamp); echo '</td>';
echo '<td style=\'text-align: center\'>'; $timestamp = strtotime($qsl->COL_TIME_ON); echo date('H:i', $timestamp); echo '</td>';

查看文件

@ -69,8 +69,8 @@
<input type="text" class="form-control form-control-sm input_date" name="start_date" id="start_date" value="<?php if (($this->session->userdata('start_date') != NULL && ((time() - $this->session->userdata('time_stamp')) < 24 * 60 * 60))) {
echo $this->session->userdata('start_date');
} else {
echo date('d-m-Y');
} ?>" <?php echo ($_GET['manual'] == 0 ? "disabled" : ""); ?> required pattern="[0-3][0-9]-[0-1][0-9]-[0-9]{4}">
echo date($user_date_format);
} ?>" <?php echo ($_GET['manual'] == 0 ? "disabled" : ""); ?> required>
</div>
<div class="mb-3 col-md-3">
@ -102,7 +102,7 @@
<?php if ($_GET['manual'] == 0) { ?>
<input class="input_start_time" type="hidden" id="start_time" name="start_time" value="<?php echo date('H:i:s'); ?>" />
<input class="input_end_time" type="hidden" id="end_time" name="end_time" value="<?php echo date('H:i:s'); ?>" />
<input class="input_date" type="hidden" id="start_date" name="start_date" value="<?php echo date('d-m-Y'); ?>" />
<input class="input_date" type="hidden" id="start_date" name="start_date" value="<?php echo date($user_date_format); ?>" />
<?php } ?>
</div>
@ -113,8 +113,8 @@
<input type="text" class="form-control form-control-sm input_date" name="start_date" id="start_date" value="<?php if (($this->session->userdata('start_date') != NULL && ((time() - $this->session->userdata('time_stamp')) < 24 * 60 * 60))) {
echo $this->session->userdata('start_date');
} else {
echo date('d-m-Y');
} ?>" <?php echo ($_GET['manual'] == 0 ? "disabled" : ""); ?> required pattern="[0-3][0-9]-[0-1][0-9]-[0-9]{4}">
echo date($user_date_format);
} ?>" <?php echo ($_GET['manual'] == 0 ? "disabled" : ""); ?> required>
</div>
<div class="mb-3 col-md-6">
@ -131,7 +131,7 @@
<?php if ($_GET['manual'] == 0) { ?>
<input class="input_start_time" type="hidden" id="start_time" name="start_time" value="<?php echo date('H:i:s'); ?>" />
<input class="input_date" type="hidden" id="start_date" name="start_date" value="<?php echo date('d-m-Y'); ?>" />
<input class="input_date" type="hidden" id="start_date" name="start_date" value="<?php echo date($user_date_format); ?>" />
<?php } ?>
</div>
<?php } ?>

查看文件

@ -634,5 +634,7 @@ if ($('.table-responsive .dropdown-toggle').length>0) {
}
function getDataTablesLanguageUrl() {
return base_url + "/assets/json/datatables_languages/" + lang_datatables_language + ".json";
// Check if lang_datatables_language is defined, otherwise use a default
var language = (typeof lang_datatables_language !== 'undefined') ? lang_datatables_language : 'english';
return base_url + "/assets/json/datatables_languages/" + language + ".json";
}

查看文件

@ -77,20 +77,93 @@ $(".station_id").change(function(){
type: 'post',
data: {'station_id': station_id},
success: function(html) {
$('.resulttable').empty();
$('.resulttable').append(html);
try {
// Destroy existing DataTable if it exists
if ($.fn.DataTable.isDataTable('#qslprint_table')) {
$('#qslprint_table').DataTable().destroy();
}
$('.resulttable').empty();
$('.resulttable').append(html);
// Reinitialize DataTable
$('#qslprint_table').DataTable({
"stateSave": true,
paging: false,
"language": {
url: getDataTablesLanguageUrl(),
},
"drawCallback": function(settings) {
// Re-attach event handlers after DataTable draws/redraws
attachCheckboxEvents();
}
});
// Attach checkbox events immediately after initialization
attachCheckboxEvents();
} catch (error) {
console.error('Error reinitializing DataTable:', error);
}
}
});
});
$('#qslprint_table').DataTable({
"stateSave": true,
paging: false,
"language": {
url: getDataTablesLanguageUrl(),
// Initialize DataTable only if it exists and isn't already initialized
$(document).ready(function() {
try {
if ($('#qslprint_table').length && !$.fn.DataTable.isDataTable('#qslprint_table')) {
$('#qslprint_table').DataTable({
"stateSave": true,
paging: false,
"language": {
url: getDataTablesLanguageUrl(),
},
"drawCallback": function(settings) {
// Re-attach event handlers after DataTable draws/redraws
attachCheckboxEvents();
}
});
}
// Initial attachment of events
attachCheckboxEvents();
} catch (error) {
console.error('Error initializing DataTable:', error);
// Still try to attach checkbox events even if DataTable fails
attachCheckboxEvents();
}
});
// Function to attach checkbox events
function attachCheckboxEvents() {
// Remove any existing handlers to prevent duplicates
$('#checkBoxAll').off('change.qslprint');
$('.qso-checkbox').off('click.qslprint');
// Attach select all functionality
$('#checkBoxAll').on('change.qslprint', function (event) {
var isChecked = this.checked;
$('#qslprint_table tbody tr .qso-checkbox').each(function (i) {
$(this).prop("checked", isChecked);
if (isChecked) {
$(this).closest('tr').addClass('activeRow');
} else {
$(this).closest('tr').removeClass('activeRow');
}
});
});
// Attach individual checkbox functionality
$(document).on('click.qslprint', '.qso-checkbox', function() {
if ($(this).is(":checked")) {
$(this).closest('tr').addClass('activeRow');
} else {
$(this).closest('tr').removeClass('activeRow');
}
// Update the "select all" checkbox state
var totalCheckboxes = $('#qslprint_table tbody tr .qso-checkbox').length;
var checkedCheckboxes = $('#qslprint_table tbody tr .qso-checkbox:checked').length;
$('#checkBoxAll').prop('checked', totalCheckboxes === checkedCheckboxes);
});
}
function showOqrs(id) {
$.ajax({
url: base_url + 'index.php/qslprint/show_oqrs',
@ -135,30 +208,8 @@ function mark_qsl_sent(id, method) {
});
}
$('#checkBoxAll').change(function (event) {
if (this.checked) {
$('.qslprint tbody tr').each(function (i) {
$(this).closest('tr').addClass('activeRow');
$(this).closest('tr').find("input[type=checkbox]").prop("checked", true);
});
} else {
$('.qslprint tbody tr').each(function (i) {
$(this).closest('tr').removeClass('activeRow');
$(this).closest('tr').find("input[type=checkbox]").prop("checked", false);
});
}
});
$('.qslprint').on('click', 'input[type="checkbox"]', function() {
if ($(this).is(":checked")) {
$(this).closest('tr').addClass('activeRow');
} else {
$(this).closest('tr').removeClass('activeRow');
}
});
function markSelectedQsos() {
var elements = $('.qslprint tbody input:checked');
var elements = $('.qso-checkbox:checked');
var nElements = elements.length;
if (nElements == 0) {
return;
@ -179,18 +230,22 @@ function markSelectedQsos() {
'method' : ''
},
success: function(data) {
if (data !== []) {
if (data && data.length > 0) {
$.each(data, function(k, v) {
$("#qslprint_"+this.qsoID).remove();
});
}
$('.markallprinted').prop("disabled", false);
},
error: function(xhr, status, error) {
console.error('Error marking QSOs as printed:', error);
$('.markallprinted').prop("disabled", false);
}
});
}
function removeSelectedQsos() {
var elements = $('.qslprint tbody input:checked');
var elements = $('.qso-checkbox:checked');
var nElements = elements.length;
if (nElements == 0) {
return;
@ -213,12 +268,16 @@ function removeSelectedQsos() {
'method' : ''
},
success: function(data) {
if (data !== []) {
if (data && data.length > 0) {
$.each(data, function(k, v) {
$("#qslprint_"+this.qsoID).remove();
});
}
$('.removeall').prop("disabled", false);
},
error: function(xhr, status, error) {
console.error('Error removing QSOs from queue:', error);
$('.removeall').prop("disabled", false);
}
});
}