cloudlog/assets/js/sections/common.js
Peter Goodhall 8439798799 Lazy-load Leaflet and fix QRB modal map
Leaflet CSS/JS assets are now loaded conditionally in shared headers/footers so map libraries are only included on pages that need them. For the QRB calculator dialog, Leaflet is loaded on demand in `common.js`, and the `newpath` map-rendering function was moved into the QRB view so the modal still works when global map scripts are skipped. Also adds a small HTMX updating indicator to the dashboard’s Today’s QSOs section.
2026-07-06 17:18:39 +01:00

810 lines
34 KiB
JavaScript

function qsl_rcvd(id, method) {
$(".ld-ext-right-r-"+method).addClass('running');
$(".ld-ext-right-r-"+method).prop('disabled', true);
$.ajax({
url: base_url + 'index.php/qso/qsl_rcvd_ajax',
type: 'post',
data: {'id': id,
'method': method
},
success: function(data) {
$(".ld-ext-right-r-"+method).removeClass('running');
$(".ld-ext-right-r-"+method).prop('disabled', false);
if (data.message == 'OK') {
$("#qsl_" + id).find("span:eq(1)").attr('class', 'qsl-green'); // Paints arrow green
$(".qsl_rcvd_" + id).remove(); // removes choice from menu
}
else {
$(".bootstrap-dialog-message").append('<div class="alert alert-danger"><a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>You are not allowed to update QSL status!</div>');
}
}
});
}
function qsl_sent(id, method) {
$.ajax({
url: base_url + 'index.php/qso/qsl_sent_ajax',
type: 'post',
data: {'id': id,
'method': method
},
success: function(data) {
if (data.message == 'OK') {
$("#qsl_" + id).find("span:eq(0)").attr('class', 'qsl-green'); // Paints arrow green
$(".qsl_sent_" + id).remove(); // removes choice from menu
}
else {
$(".bootstrap-dialog-message").append('<div class="alert alert-danger"><a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>You are not allowed to update QSL status!</div>');
}
}
});
}
// Function: qsl_requested
// Marks QSL card requested against the QSO.
function qsl_requested(id, method) {
$(".ld-ext-right-t-"+method).addClass('running');
$(".ld-ext-right-t-"+method).prop('disabled', true);
$.ajax({
url: base_url + 'index.php/qso/qsl_requested_ajax',
type: 'post',
data: {'id': id,
'method': method
},
success: function(data) {
$(".ld-ext-right-t-"+method).removeClass('running');
$(".ld-ext-right-t-"+method).prop('disabled', false);
if (data.message == 'OK') {
$("#qsl_" + id).find("span:eq(0)").attr('class', 'qsl-yellow'); // Paints arrow yellow
}
else {
$(".bootstrap-dialog-message").append('<div class="alert alert-danger"><a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>You are not allowed to update QSL status!</div>');
}
}
});
}
// Function: qsl_ignore
// Marks QSL card ignore against the QSO.
function qsl_ignore(id, method) {
$(".ld-ext-right-ignore").addClass('running');
$(".ld-ext-right-ignore").prop('disabled', true);
$.ajax({
url: base_url + 'index.php/qso/qsl_ignore_ajax',
type: 'post',
data: {'id': id,
'method': method
},
success: function(data) {
$(".ld-ext-right-ignore").removeClass('running');
$(".ld-ext-right-ignore").prop('disabled', false);
if (data.message == 'OK') {
$("#qsl_" + id).find("span:eq(0)").attr('class', 'qsl-grey'); // Paints arrow grey
}
else {
$(".bootstrap-dialog-message").append('<div class="alert alert-danger"><a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>You are not allowed to update QSL status!</div>');
}
}
});
}
function qso_delete(id, call) {
BootstrapDialog.confirm({
title: lang_general_word_danger,
message: lang_qso_delete_warning + call + '?' ,
type: BootstrapDialog.TYPE_DANGER,
closable: true,
draggable: true,
btnOKClass: 'btn-danger',
callback: function(result) {
if(result) {
$(".edit-dialog").modal('hide');
$(".qso-dialog").modal('hide');
$.ajax({
url: base_url + 'index.php/qso/delete_ajax',
type: 'post',
data: {'id': id
},
success: function(data) {
$(".alert").remove();
$(".bootstrap-dialog-message").prepend('<div class="alert alert-danger"><a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>The contact with ' + call + ' has been deleted!</div>');
$("#qso_" + id).remove(); // removes qso from table in dialog
}
});
}
}
});
}
function qso_edit(id) {
$.ajax({
url: base_url + 'index.php/qso/edit_ajax',
type: 'post',
data: {'id': id
},
success: function(html) {
// remove actions QSO menu //
$('.menuOnResultTab').hide();
$('.menuOnBody').remove();
BootstrapDialog.show({
title: lang_general_word_qso_data,
cssClass: 'edit-dialog',
size: BootstrapDialog.SIZE_WIDE,
nl2br: false,
message: html,
onshown: function(dialog) {
var state = $("#input_usa_state_edit option:selected").text();
if (state != "") {
$("#stationCntyInputEdit").prop('disabled', false);
selectize_usa_county();
}
$('#input_usa_state_edit').change(function(){
var state = $("#input_usa_state_edit option:selected").text();
if (state != "") {
$("#stationCntyInputEdit").prop('disabled', false);
selectize_usa_county();
} else {
$("#stationCntyInputEdit").prop('disabled', true);
//$('#stationCntyInput')[0].selectize.destroy();
$("#stationCntyInputEdit").val("");
}
});
// Add callsign change handler to update DXCC/location info
$('.modal-content #callsign').on('change blur', function() {
var callsignValue = $(this).val();
if (callsignValue.length >= 3) {
var find_callsign = callsignValue.toUpperCase();
find_callsign = find_callsign.replace(/\//g, "-");
find_callsign = find_callsign.replace('Ø', '0');
$.getJSON(base_url + 'index.php/logbook/json/' + find_callsign + '/0/0/0/' + $('.modal-content #stationProfile').val(), function(result) {
if (result.dxcc && result.dxcc.entity !== undefined && result.dxcc.entity !== 'Not Found') {
// Update country field
$('.modal-content #country').val(result.dxcc.entity);
// Update DXCC ID
if (result.dxcc.adif !== undefined) {
$('.modal-content #dxcc_id').val(result.dxcc.adif);
}
// Update CQ Zone
if (result.dxcc.cqz !== undefined) {
$('.modal-content #cqz').val(result.dxcc.cqz);
}
// Update ITU Zone
if (result.dxcc.ituz !== undefined) {
$('.modal-content #ituz').val(result.dxcc.ituz);
}
// Update continent
if (result.dxcc.cont !== undefined) {
$('.modal-content #continent').val(result.dxcc.cont);
}
// Update state if available
if (result.callsign_state && $('.modal-content #input_usa_state_edit').val() == "") {
$('.modal-content #input_usa_state_edit').val(result.callsign_state).trigger('change');
}
}
});
}
});
$('#locator').change(function(){
if ($(this).val().length >= 4) {
$.ajax({
url: base_url + 'index.php/logbook/searchbearing',
type: 'post',
data: {
grid: $(this).val(),
stationProfile: $('#stationProfile').val()
},
success: function(data) {
$('#locator_info').html(data).fadeIn("slow");
},
error: function() {
$('#locator_info').text("Error loading bearing!").fadeIn("slow");
},
});
$.ajax({
url: base_url + 'index.php/logbook/searchdistance',
type: 'post',
data: {
grid: $(this).val(),
stationProfile: $('#stationProfile').val()
},
success: function(data) {
document.getElementById("distance").value = data;
},
error: function() {
document.getElementById("distance").value = null;
},
});
}
});
$('#sota_ref_edit').selectize({
maxItems: 1,
closeAfterSelect: true,
createOnBlur: true,
selectOnTab: true,
loadThrottle: 250,
valueField: 'name',
labelField: 'name',
searchField: 'name',
options: [],
create: true,
load: function(query, callback) {
if (!query || query.length < 3) return callback(); // Only trigger if 3 or more characters are entered
$.ajax({
url: base_url+'index.php/qso/get_sota',
type: 'GET',
dataType: 'json',
data: {
query: query,
},
error: function() {
callback();
},
success: function(res) {
callback(res);
}
});
}
});
$('#wwff_ref_edit').selectize({
maxItems: 1,
closeAfterSelect: true,
createOnBlur: true,
selectOnTab: true,
loadThrottle: 250,
valueField: 'name',
labelField: 'name',
searchField: 'name',
options: [],
create: true,
load: function(query, callback) {
if (!query || query.length < 3) return callback(); // Only trigger if 3 or more characters are entered
$.ajax({
url: base_url+'index.php/qso/get_wwff',
type: 'GET',
dataType: 'json',
data: {
query: query,
},
error: function() {
callback();
},
success: function(res) {
callback(res);
}
});
}
});
$('#pota_ref_edit').selectize({
maxItems: null,
closeAfterSelect: true,
createOnBlur: true,
selectOnTab: true,
loadThrottle: 250,
valueField: 'name',
labelField: 'name',
searchField: 'name',
options: [],
create: true,
load: function(query, callback) {
if (!query || query.length < 3) return callback(); // Only trigger if 3 or more characters are entered
$.ajax({
url: base_url+'index.php/qso/get_pota',
type: 'GET',
dataType: 'json',
data: {
query: query,
},
error: function() {
callback();
},
success: function(res) {
callback(res);
}
});
}
});
$('#darc_dok_edit').selectize({
maxItems: 1,
closeAfterSelect: true,
loadThrottle: 250,
valueField: 'name',
labelField: 'name',
searchField: 'name',
options: [],
create: true,
load: function(query, callback) {
if (!query) return callback(); // Only trigger if 3 or more characters are entered
$.ajax({
url: base_url+'index.php/qso/get_dok',
type: 'GET',
dataType: 'json',
data: {
query: query,
},
error: function() {
callback();
},
success: function(res) {
callback(res);
}
});
}
});
// Populate satellite names datalist for edit dialog
$.getJSON(base_url+"assets/json/satellite_data.json", function( data ) {
var items = [];
$.each( data, function( key, val ) {
items.push('<option value="' + key + '">' + key + '</option>');
});
$('.satellite_names_list_edit').append(items.join( "" ));
});
// Handle satellite name change in edit dialog
var selected_sat_edit;
$('#sat_name_edit').on('input', function(){
var optionslist = $('.satellite_names_list_edit')[0].options;
var value = $(this).val();
for (var x=0; x<optionslist.length; x++){
if (optionslist[x].value === value) {
$("#sat_mode_edit").val("");
$('.satellite_modes_list_edit').find('option').remove().end();
selected_sat_edit = value;
// Get satellite modes from JSON
$.getJSON( base_url+"assets/json/satellite_data.json", function( data ) {
var sat_modes = [];
$.each( data, function( key, val ) {
if (key == value) {
$.each( val.Modes, function( key1, val2 ) {
sat_modes.push('<option value="' + key1 + '">' + key1 + '</option>');
});
}
});
$('.satellite_modes_list_edit').append(sat_modes.join( "" ));
});
break;
}
}
});
// Handle satellite mode change in edit dialog to update frequencies and modes
$('#sat_mode_edit').on('input', function(){
var optionslist = $('.satellite_modes_list_edit')[0].options;
var value = $(this).val();
for (var x=0; x<optionslist.length; x++){
if (optionslist[x].value === value) {
var selected_sat_mode_edit = value;
// Get satellite data from JSON
$.getJSON( base_url+"assets/json/satellite_data.json", function( data ) {
$.each( data, function( key, val ) {
if (key == selected_sat_edit) {
$.each( val.Modes, function( key1, val2 ) {
if(key1 == selected_sat_mode_edit) {
// Update mode - handle inverting transponders
if ( (val2[0].Downlink_Mode == "LSB" && val2[0].Uplink_Mode == "USB") ||
(val2[0].Downlink_Mode == "USB" && val2[0].Uplink_Mode == "LSB") ) {
$("#mode").val("SSB");
} else {
$("#mode").val(val2[0].Uplink_Mode);
}
// Update bands based on frequencies
$("#band").val(frequencyToBand(val2[0].Uplink_Freq));
$("#band_rx").val(frequencyToBand(val2[0].Downlink_Freq));
// Update frequencies
$("#freq").val(val2[0].Uplink_Freq);
$("#freqrx").val(val2[0].Downlink_Freq);
// Update propagation mode to SAT
$("#prop_mode").val('SAT');
}
});
}
});
});
break;
}
}
});
// [eQSL default msg] change value (for qso edit page) //
$('.modal-content #stationProfile').change(function() {
qso_set_eqsl_qslmsg($('.modal-content #stationProfile').val(),false,'.modal-content');
});
$('.modal-content .qso_eqsl_qslmsg_update').off('click').on('click',function() {
qso_set_eqsl_qslmsg($('.modal-content #stationProfile').val(),true,'.modal-content');
$('.modal-content #charsLeft').text(" ");
});
$('.modal-content #qslmsg').keyup(function(event) {
calcRemainingChars(event, '.modal-content');
});
},
});
}
});
}
function loadLeafletAssets(callback) {
if (typeof L !== 'undefined' && typeof L.maidenheadqrb !== 'undefined') {
if (typeof callback === 'function') {
callback();
}
return;
}
// Load CSS if not already present
if ($('link[href*="' + base_url + 'assets/js/leaflet/leaflet.css"]').length === 0) {
$('head').append('<link rel="stylesheet" type="text/css" href="' + base_url + 'assets/js/leaflet/leaflet.css">');
}
if ($('link[href*="' + base_url + 'assets/js/leaflet/Control.FullScreen.css"]').length === 0) {
$('head').append('<link rel="stylesheet" type="text/css" href="' + base_url + 'assets/js/leaflet/Control.FullScreen.css">');
}
// Helper to load scripts sequentially
function loadScript(src, next) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = src;
script.onload = next;
script.onerror = function() {
console.error('Failed to load ' + src);
if (typeof next === 'function') {
next();
}
};
document.head.appendChild(script);
}
loadScript(base_url + 'assets/js/leaflet/leaflet.js', function() {
loadScript(base_url + 'assets/js/leaflet/Control.FullScreen.js', function() {
loadScript(base_url + 'assets/js/leaflet/L.Maidenhead.qrb.js', function() {
loadScript(base_url + 'assets/js/leaflet/leaflet.geodesic.js', function() {
if (typeof callback === 'function') {
callback();
}
});
});
});
});
}
function spawnQrbCalculator(locator1, locator2) {
loadLeafletAssets(function() {
$.ajax({
url: base_url + 'index.php/qrbcalc',
type: 'post',
success: function (html) {
BootstrapDialog.show({
title: 'Compute QRB and QTF',
size: BootstrapDialog.SIZE_WIDE,
cssClass: 'lookup-dialog',
nl2br: false,
message: html,
onshown: function(dialog) {
if (locator1 !== undefined) {
$("#qrbcalc_locator1").val(locator1);
}
if (locator2 !== undefined) {
$("#qrbcalc_locator2").val(locator2);
calculateQrb();
}
},
buttons: [{
label: lang_admin_close,
action: function (dialogItself) {
dialogItself.close();
}
}]
});
}
});
});
}
function spawnActivatorsMap(call, count, grids) {
$.ajax({
url: base_url + 'index.php/activatorsmap',
type: 'post',
success: function (html) {
BootstrapDialog.show({
title: 'Activators Map',
size: BootstrapDialog.SIZE_WIDE,
cssClass: 'lookup-dialog',
nl2br: false,
message: html,
onshown: function(dialog) {
showActivatorsMap(call, count, grids);
},
buttons: [{
label: lang_admin_close,
action: function (dialogItself) {
dialogItself.close();
}
}]
});
}
});
}
function calculateQrb() {
let locator1 = $("#qrbcalc_locator1").val();
let locator2 = $("#qrbcalc_locator2").val();
$(".qrbalert").remove();
if (validateLocator(locator1) && validateLocator(locator2)) {
$.ajax({
url: base_url+'index.php/qrbcalc/calculate',
type: 'post',
data: {'locator1': locator1,
'locator2': locator2},
success: function (html) {
var result = "<h5>Negative latitudes are south of the equator, negative longitudes are west of Greenwich. <br/>";
result += ' ' + locator1.toUpperCase() + ' Latitude = ' + html['latlng1'][0] + ' Longitude = ' + html['latlng1'][1] + '<br/>';
result += ' ' + locator2.toUpperCase() + ' Latitude = ' + html['latlng2'][0] + ' Longitude = ' + html['latlng2'][1] + '<br/>';
result += 'Distance between ' + locator1.toUpperCase() + ' and ' + locator2.toUpperCase() + ' is ' + html['distance'] + '.<br />';
result += 'The bearing is ' + html['bearing'] + '.</h5>';
$(".qrbResult").html(result);
newpath(html['latlng1'], html['latlng2'], locator1, locator2);
}
});
} else {
$('.qrbResult').html('<div class="qrbalert alert alert-danger" role="alert">Error in locators. Please check.</div>');
}
}
function validateLocator(locator) {
vucc_gridno = locator.split(",").length;
if(vucc_gridno == 3 || vucc_gridno > 4) {
return false;
}
if(locator.length < 4 && !(/^[a-rA-R]{2}[0-9]{2}[a-xA-X]{0,2}[0-9]{0,2}[a-xA-X]{0,2}$/.test(locator))) {
return false;
}
return true;
}
// This displays the dialog with the form and it's where the resulttable is displayed
function spawnLookupModal(searchphrase, searchtype) {
$.ajax({
url: base_url + 'index.php/lookup',
type: 'post',
success: function (html) {
BootstrapDialog.show({
title: 'Quick lookup',
size: BootstrapDialog.SIZE_WIDE,
cssClass: 'lookup-dialog',
nl2br: false,
message: html,
onshown: function(dialog) {
$('#quicklookuptype').change(function(){
var type = $('#quicklookuptype').val();
changeLookupType(type);
});
if (searchtype !== undefined) {
$('#quicklookuptype').val(searchtype);
if (searchtype == 'dxcc') {
$("#quicklookupdxcc").val(searchphrase);
} else if (searchtype == 'iota') {
$("#quicklookupiota").val(searchphrase);
} else if (searchtype == 'cq') {
$("#quicklookupcqz").val(searchphrase);
} else {
$("#quicklookuptext").val(searchphrase);
}
changeLookupType(searchtype);
getLookupResult(this.form);
}
},
buttons: [{
label: lang_admin_close,
action: function (dialogItself) {
dialogItself.close();
}
}]
});
}
});
}
function changeLookupType(type) {
if (type == "dxcc") {
$('#quicklookupdxcc').show();
$('#quicklookupiota').hide();
$('#quicklookupcqz').hide();
$('#quicklookupwas').hide();
$('#quicklookuptext').hide();
} else if (type == "iota") {
$('#quicklookupiota').show();
$('#quicklookupdxcc').hide();
$('#quicklookupcqz').hide();
$('#quicklookupwas').hide();
$('#quicklookuptext').hide();
} else if (type == "vucc" || type == "sota" || type == "wwff") {
$('#quicklookuptext').show();
$('#quicklookupiota').hide();
$('#quicklookupdxcc').hide();
$('#quicklookupcqz').hide();
$('#quicklookupwas').hide();
} else if (type == "cq") {
$('#quicklookupcqz').show();
$('#quicklookupiota').hide();
$('#quicklookupdxcc').hide();
$('#quicklookupwas').hide();
$('#quicklookuptext').hide();
} else if (type == "was") {
$('#quicklookupwas').show();
$('#quicklookupcqz').hide();
$('#quicklookupiota').hide();
$('#quicklookupdxcc').hide();
$('#quicklookuptext').hide();
}
}
// This function executes the call to the backend for fetching queryresult and displays the table in the dialog
function getLookupResult() {
$(".ld-ext-right").addClass('running');
$(".ld-ext-right").prop('disabled', true);
$.ajax({
url: base_url + 'index.php/lookup/search',
type: 'post',
data: {
type: $('#quicklookuptype').val(),
dxcc: $('#quicklookupdxcc').val(),
was: $('#quicklookupwas').val(),
grid: $('#quicklookuptext').val(),
cqz: $('#quicklookupcqz').val(),
iota: $('#quicklookupiota').val(),
sota: $('#quicklookuptext').val(),
wwff: $('#quicklookuptext').val(),
},
success: function (html) {
$('#lookupresulttable').html(html);
$(".ld-ext-right").removeClass('running');
$(".ld-ext-right").prop('disabled', false);
}
});
}
// This function executes the call to the backend for fetching dxcc summary and inserted table below qso entry
function getDxccResult(dxcc, name) {
$.ajax({
url: base_url + 'index.php/lookup/search',
type: 'post',
data: {
type: 'dxcc',
dxcc: dxcc,
},
success: function (html) {
// Update the DXCC Summary tab content
$('#dxcc-summary-content').html(html);
}
});
}
function displayQsl(id) {
$.ajax({
url: base_url + 'index.php/qsl/viewQsl',
type: 'post',
data: {
id: id,
},
success: function (html) {
BootstrapDialog.show({
title: 'QSL Card',
size: BootstrapDialog.SIZE_WIDE,
cssClass: 'lookup-dialog',
nl2br: false,
message: html,
onshown: function(dialog) {
},
buttons: [{
label: lang_admin_close,
action: function (dialogItself) {
dialogItself.close();
}
}]
});
}
});
}
// [eQSL default msg] function to load default qslmsg to qslmsg field on qso add/edit //
function qso_set_eqsl_qslmsg(station_id, force_diff_to_origin=false, object='') {
$.ajax({
url: base_url+'index.php/station/get_options',
type: 'post', data: {'option_type':'eqsl_default_qslmsg','option_name':'key_station_id','option_key':station_id },
success: function(res) {
if (typeof res.eqsl_default_qslmsg !== "undefined") {
object = (object!='')?(object+' '):'';
if ((force_diff_to_origin) || ($(object+'#qslmsg').val()==$(object+'#qslmsg_hide').html())) {
$(object+'#qslmsg').val(res.eqsl_default_qslmsg);
$(object+'#qslmsg_hide').html(res.eqsl_default_qslmsg);
}
}
},
error: function() { },
});
}
// [PWD] button show/hide //
function btn_pwd_showhide() {
if ($(this).closest('div').find('input[type="password"]').length>0) {
$(this).closest('div').find('input[type="password"]').attr('type','text');
$(this).closest('div').find('.fa-eye-slash').removeClass('fa-eye-slash').addClass('fa-eye');
} else {
$(this).closest('div').find('input[type="text"]').attr('type','password');
$(this).closest('div').find('.fa-eye').removeClass('fa-eye').addClass('fa-eye-slash');
}
}
$('.user_edit .btn-pwd-showhide').off('click').on('click', btn_pwd_showhide );
// [QSO] show/hide actions menu on qso list (_this = div.dropdown actived) //
function showQsoActionsMenu(_this) {
$('.menuOnResultTab').hide();
$('.menuOnBody').remove();
var _id = _this.find('.menuOnResultTab').attr('data-qsoid');
var _dropdownMenuClone = _this.find('.menuOnResultTab[data-qsoid="'+ _id +'"]').clone();
_dropdownMenuClone.removeClass('menuOnResultTab').addClass('menuOnBody');
$('body').append(_dropdownMenuClone);
var _dropdownMenu = _this.find('.menuOnResultTab[data-qsoid="'+ _id +'"]');
var eOffset = _this.offset();
if ((eOffset.top - $(window).scrollTop() + _dropdownMenu.outerHeight()) >= ($(window).height()-50)) {
_topMenu = eOffset.top - _dropdownMenu.outerHeight();
} else {
_topMenu = eOffset.top + _this.outerHeight();
}
_dropdownMenuClone.css({
'top': _topMenu,
'left': eOffset.left - _dropdownMenu.width() + _this.find('.dropdown-toggle').outerWidth(),
'display': 'block',
});
_dropdownMenuClone.off('mouseenter').on('mouseenter', function () {
_dropdownMenuClone.attr('data-mouseenteronmenu','1');
});
_this.off('mouseleave').on('mouseleave', function () {
setTimeout(function(){ if (_dropdownMenuClone.attr('data-mouseenteronmenu')!='1') { _dropdownMenuClone.remove();} }, 200);
});
_dropdownMenuClone.off('mouseleave').on('mouseleave', function () {
$(this).remove();
});
_dropdownMenuClone.find('a').off('click').on('click', function () {
if ($(this).is(':first-child') || $(this).is(':last-child')) { // Only for edit & delete action //
$(this).closest('.menuOnResultTab').remove();
}
});
}
if ($('.table-responsive .dropdown-toggle').length>0) {
$('.table-responsive .dropdown-toggle').off('mouseenter').on('mouseenter', function () {
showQsoActionsMenu($(this).closest('.dropdown'));
});
}
function getDataTablesLanguageUrl() {
// 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";
}