1
0
mirror of https://github.com/KubaPro010/fm-dx-webserver.git synced 2026-02-26 22:13:53 +01:00

mobile panel, UI bugfixes, security improvements

This commit is contained in:
Marek Farkaš
2025-05-02 16:06:48 +02:00
parent 27e9ee93fb
commit fb8af10ce5
19 changed files with 909 additions and 888 deletions

View File

@@ -9,27 +9,13 @@ $(document).ready(function() {
const chatIdentityNickname = $('#chat-identity-nickname');
const chatNicknameInput = $('#chat-nickname');
const chatNicknameSave = $('#chat-nickname-save');
$(function () {
$("#popup-panel-chat").draggable({
handle: ".popup-header"
}).resizable({
minHeight: 300,
minWidth: 250
});
$(".chatbutton").on("click", function () {
$("#popup-panel-chat").fadeIn(200, function () {
$(".chatbutton").on("click", function () {
$("#popup-panel-chat").fadeIn(200, function () {
chatMessages.scrollTop(chatMessages[0].scrollHeight);
});
});
$("#popup-panel-chat .popup-close").on("click", function () {
$("#popup-panel-chat").fadeOut(200);
});
});
});
// Function to generate a random string
function generateRandomString(length) {
const characters = 'ABCDEFGHJKMNOPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz0123456789';
@@ -39,12 +25,12 @@ $(document).ready(function() {
}
return result;
}
// Load nickname from localStorage on page load
let savedNickname = localStorage.getItem('nickname') || `User ${generateRandomString(5)}`;
chatNicknameInput.val(savedNickname);
chatIdentityNickname.text(savedNickname);
chatSocket.onmessage = function(event) {
const messageData = JSON.parse(event.data);
const isAdmin = messageData.admin ? '<span style="color: #bada55">[ADMIN]</span>' : '';
@@ -59,7 +45,7 @@ $(document).ready(function() {
<span style="color: var(--color-text-2);">${$('<div/>').text(messageData.message).html()}</span><br>
`;
chatMessages.append(chatMessage);
if (chatMessages.is(':visible')) {
setTimeout(function() {
chatMessages.scrollTop(chatMessages[0].scrollHeight);
@@ -74,7 +60,7 @@ $(document).ready(function() {
}
}
};
$('.chat-send-message-btn').click(sendMessage);
chatNicknameSave.click(function() {
const currentNickname = chatNicknameInput.val().trim() || `Anonymous User ${generateRandomString(5)}`;
@@ -89,28 +75,28 @@ $(document).ready(function() {
chatMessagesCount.text(chatMessageCount);
chatButton.removeClass('blink').addClass('bg-color-1');
chatSendInput.focus();
setTimeout(function() {
chatMessages.scrollTop(chatMessages[0].scrollHeight);
}, 100);
});
chatNicknameInput.keypress(function(event) {
if (event.which === 13) {
chatNicknameSave.trigger('click');
}
});
chatSendInput.keypress(function(event) {
if (event.which === 13) {
sendMessage();
}
});
function sendMessage() {
const nickname = savedNickname || `Anonymous User ${generateRandomString(5)}`;
const message = chatSendInput.val().trim();
if (message) {
const messageData = { nickname, message };
chatSocket.send(JSON.stringify(messageData));

View File

@@ -1,110 +1,120 @@
$(document).ready(function() {
// Variables
const $dropdowns = $('.dropdown');
const $listOfOptions = $('.option');
let currentDropdown = null; // Track the currently clicked dropdown
let currentIndex = -1; // Track the currently focused option
// Functions
const toggleDropdown = (event) => {
event.stopPropagation();
const $currentDropdown = $(event.currentTarget).closest('.dropdown');
// Close the previously opened dropdown if any
$dropdowns.not($currentDropdown).removeClass('opened');
$currentDropdown.toggleClass('opened');
currentDropdown = $currentDropdown.hasClass('opened') ? $currentDropdown : null;
currentIndex = -1; // Reset the current index when toggling the dropdown
};
const selectOption = (event) => {
const $currentDropdown = currentDropdown;
switch($currentDropdown.attr('id')) {
case 'data-ant':
socket.send("Z" + $(event.currentTarget).attr('data-value'));
resetRDS(getCurrentFreq()); // Reset RDS when change antenna input
break;
case 'data-bw':
legacyBwValue = $(event.currentTarget).attr('data-value2') || "";
socket.send("F" + legacyBwValue);
socket.send("W" + $(event.currentTarget).attr('data-value'));
$currentDropdown.find('input').val($(event.currentTarget).text());
break;
default:
// Variables
const $dropdowns = $('.dropdown');
const $listOfOptions = $('.option');
let currentDropdown = null; // Track the currently clicked dropdown
let currentIndex = -1; // Track the currently focused option
// Functions
const toggleDropdown = (event) => {
event.stopPropagation();
const $currentDropdown = $(event.currentTarget).closest('.dropdown');
// Close the previously opened dropdown if any
$dropdowns.not($currentDropdown).removeClass('opened');
$currentDropdown.toggleClass('opened');
currentDropdown = $currentDropdown.hasClass('opened') ? $currentDropdown : null;
currentIndex = -1; // Reset the current index when toggling the dropdown
};
const selectOption = (event) => {
const $currentDropdown = currentDropdown;
switch($currentDropdown.attr('id')) {
case 'data-ant':
socket.send("Z" + $(event.currentTarget).attr('data-value'));
resetRDS(getCurrentFreq()); // Reset RDS when change antenna input
break;
case 'data-ant-phone':
socket.send("Z" + $(event.currentTarget).attr('data-value'));
resetRDS(getCurrentFreq()); // Reset RDS when change antenna input
break;
case 'data-bw':
legacyBwValue = $(event.currentTarget).attr('data-value2') || "";
socket.send("F" + legacyBwValue);
socket.send("W" + $(event.currentTarget).attr('data-value'));
$currentDropdown.find('input').val($(event.currentTarget).text());
break;
case 'data-bw-phone':
legacyBwValue = $(event.currentTarget).attr('data-value2') || "";
socket.send("F" + legacyBwValue);
socket.send("W" + $(event.currentTarget).attr('data-value'));
$currentDropdown.find('input').val($(event.currentTarget).text());
break;
default:
$currentDropdown.find('input')
.val($(event.currentTarget).text())
.attr('data-value', $(event.currentTarget).data('value'));
break;
}
// Use setTimeout to delay class removal
setTimeout(() => {
$currentDropdown.removeClass('opened');
currentDropdown = null;
}, 10); // Adjust the delay as needed
};
const closeDropdownFromOutside = (event) => {
const $currentDropdown = currentDropdown && $(currentDropdown);
const isClickedInsideDropdown = $currentDropdown && $currentDropdown.has(event.target).length > 0;
if (!isClickedInsideDropdown && $currentDropdown && $currentDropdown.hasClass('opened')) {
$currentDropdown.removeClass('opened');
currentDropdown = null;
}
};
const navigateOptions = (event) => {
if (!currentDropdown) return;
const $options = currentDropdown.find('.option');
switch (event.key) {
case 'ArrowDown':
event.preventDefault();
currentIndex = (currentIndex + 1) % $options.length;
$options.eq(currentIndex).focus();
break;
case 'ArrowUp':
event.preventDefault();
currentIndex = (currentIndex - 1 + $options.length) % $options.length;
$options.eq(currentIndex).focus();
break;
case 'Enter':
event.preventDefault();
$options.eq(currentIndex).click();
break;
case 'Escape':
currentDropdown.removeClass('opened');
currentDropdown = null;
currentIndex = -1;
break;
}
};
// Event Listeners
$(document).on('click', closeDropdownFromOutside);
$listOfOptions.on('click', selectOption);
$dropdowns.on('click', 'input', toggleDropdown);
$dropdowns.on('keydown', 'input', function(event) {
if (event.key === 'Enter') {
toggleDropdown(event);
}
});
$dropdowns.on('keydown', '.option', navigateOptions);
// MULTISELECT
$('.multiselect option').mousedown(function(e) {
e.preventDefault();
var originalScrollTop = $(this).parent().scrollTop();
$(this).prop('selected', $(this).prop('selected') ? false : true);
var self = this;
$(this).parent().focus();
setTimeout(function() {
$(self).parent().scrollTop(originalScrollTop);
}, 0);
return false;
});
break;
}
// Use setTimeout to delay class removal
setTimeout(() => {
$currentDropdown.removeClass('opened');
currentDropdown = null;
}, 10); // Adjust the delay as needed
};
const closeDropdownFromOutside = (event) => {
const $currentDropdown = currentDropdown && $(currentDropdown);
const isClickedInsideDropdown = $currentDropdown && $currentDropdown.has(event.target).length > 0;
if (!isClickedInsideDropdown && $currentDropdown && $currentDropdown.hasClass('opened')) {
$currentDropdown.removeClass('opened');
currentDropdown = null;
}
};
const navigateOptions = (event) => {
if (!currentDropdown) return;
const $options = currentDropdown.find('.option');
switch (event.key) {
case 'ArrowDown':
event.preventDefault();
currentIndex = (currentIndex + 1) % $options.length;
$options.eq(currentIndex).focus();
break;
case 'ArrowUp':
event.preventDefault();
currentIndex = (currentIndex - 1 + $options.length) % $options.length;
$options.eq(currentIndex).focus();
break;
case 'Enter':
event.preventDefault();
$options.eq(currentIndex).click();
break;
case 'Escape':
currentDropdown.removeClass('opened');
currentDropdown = null;
currentIndex = -1;
break;
}
};
// Event Listeners
$(document).on('click', closeDropdownFromOutside);
$listOfOptions.on('click', selectOption);
$dropdowns.on('click', 'input', toggleDropdown);
$dropdowns.on('keydown', 'input', function(event) {
if (event.key === 'Enter') {
toggleDropdown(event);
}
});
$dropdowns.on('keydown', '.option', navigateOptions);
// MULTISELECT
$('.multiselect option').mousedown(function(e) {
e.preventDefault();
var originalScrollTop = $(this).parent().scrollTop();
$(this).prop('selected', $(this).prop('selected') ? false : true);
var self = this;
$(this).parent().focus();
setTimeout(function() {
$(self).parent().scrollTop(originalScrollTop);
}, 0);
return false;
});
});

View File

@@ -1,9 +1,9 @@
var currentDate = new Date('Apr 22, 2025 21:30:00');
var currentDate = new Date('May 2, 2025 16:00:00');
var day = currentDate.getDate();
var month = currentDate.getMonth() + 1; // Months are zero-indexed, so add 1
var year = currentDate.getFullYear();
var formattedDate = day + '/' + month + '/' + year;
var currentVersion = 'v1.3.7 [' + formattedDate + ']';
var currentVersion = 'v1.3.8 [' + formattedDate + ']';
getInitialSettings();
removeUrlParameters();

View File

@@ -178,11 +178,11 @@ $(document).ready(function () {
var freqContainer = $('#freq-container')[0];
var txContainer = $('#data-station-container')[0];
$("#data-eq").click(function () {
$(".data-eq").click(function () {
toggleButtonState("eq");
});
$("#data-ims").click(function () {
$(".data-ims").click(function () {
toggleButtonState("ims");
});
@@ -207,7 +207,7 @@ $(document).ready(function () {
$('.popup-content').removeClass('show');
});
$('#log-fmlist').on('click', function() {
$('.log-fmlist').on('click', function() {
const logKey = 'fmlistLogChoice';
const logTimestampKey = 'fmlistLogTimestamp';
const expirationTime = 10 * 60 * 1000;
@@ -222,20 +222,20 @@ $(document).ready(function () {
}
if (parsedData.txInfo.dist > 700) {
$('#log-fmlist .popup-content').addClass('show'); // Show popup if no valid choice
$('.log-fmlist .mini-popup-content').addClass('show'); // Show popup if no valid choice
$('#log-fmlist-sporadice').off('click').on('click', function () {
$('.log-fmlist-sporadice').off('click').on('click', function () {
localStorage.setItem(logKey, './log_fmlist?type=sporadice');
localStorage.setItem(logTimestampKey, now);
if(parsedData.txInfo.dist > 700) sendLog('./log_fmlist?type=sporadice');
$('#log-fmlist .popup-content').removeClass('show');
$('.log-fmlist .mini-popup-content').removeClass('show');
});
$('#log-fmlist-tropo').off('click').on('click', function () {
$('.log-fmlist-tropo').off('click').on('click', function () {
localStorage.setItem(logKey, './log_fmlist?type=tropo');
localStorage.setItem(logTimestampKey, now);
if(parsedData.txInfo.dist > 700) sendLog('./log_fmlist?type=tropo');
$('#log-fmlist .popup-content').removeClass('show');
$('.log-fmlist .mini-popup-content').removeClass('show');
});
} else {
sendLog('./log_fmlist');
@@ -696,7 +696,7 @@ function checkKey(e) {
tuneUp();
break;
case 46:
let $dropdown = $("#data-ant");
let $dropdown = $(".data-ant");
let $input = $dropdown.find("input");
let $options = $dropdown.find("ul.options .option");
@@ -870,8 +870,8 @@ const $dataPs = $('#data-ps');
const $dataSt = $('.data-st');
const $dataRt0 = $('#data-rt0 span');
const $dataRt1 = $('#data-rt1 span');
const $dataAntInput = $('#data-ant input');
const $dataBwInput = $('#data-bw input');
const $dataAntInput = $('.data-ant input');
const $dataBwInput = $('.data-bw input');
const $dataStationContainer = $('#data-station-container');
const $dataTp = $('.data-tp');
const $dataTa = $('.data-ta');
@@ -961,12 +961,12 @@ const updateDataElements = throttle(function(parsedData) {
$('.data-flag').html(`<i title="${parsedData.country_name}" class="flag-sm flag-sm-${parsedData.country_iso}"></i>`);
$('.data-flag-big').html(`<i title="${parsedData.country_name}" class="flag-md flag-md-${parsedData.country_iso}"></i>`);
$dataAntInput.val($('#data-ant li[data-value="' + parsedData.ant + '"]').text());
$dataAntInput.val($('.data-ant li[data-value="' + parsedData.ant + '"]').first().text());
if(parsedData.bw < 500) {
$dataBwInput.val($('#data-bw li[data-value2="' + parsedData.bw + '"]').text());
if (parsedData.bw < 500) {
$dataBwInput.val($('.data-bw li[data-value2="' + parsedData.bw + '"]').first().text());
} else {
$dataBwInput.val($('#data-bw li[data-value="' + parsedData.bw + '"]').text());
$dataBwInput.val($('.data-bw li[data-value="' + parsedData.bw + '"]').first().text());
}
if (parsedData.txInfo.tx.length > 1) {
@@ -984,9 +984,9 @@ const updateDataElements = throttle(function(parsedData) {
}
if(parsedData.txInfo.tx.length > 1 && parsedData.txInfo.dist > 150 && parsedData.txInfo.dist < 4000) {
$('#log-fmlist').removeAttr('disabled').removeClass('btn-disabled cursor-disabled');
$('.log-fmlist').removeAttr('disabled').removeClass('btn-disabled cursor-disabled');
} else {
$('#log-fmlist').attr('disabled', 'true').addClass('btn-disabled cursor-disabled');
$('.log-fmlist').attr('disabled', 'true').addClass('btn-disabled cursor-disabled');
}
updateHtmlIfChanged($('#data-regular-pi'), parsedData.txInfo.reg === true ? parsedData.txInfo.pi : '&nbsp;');
@@ -1006,7 +1006,7 @@ const updateDataElements = throttle(function(parsedData) {
$dataPs.attr('aria-label', parsedData.ps);
$dataRt0.attr('aria-label', parsedData.rt0);
$dataRt1.attr('aria-label', parsedData.rt1);
$('#users-online-container').attr("aria-label", "Online users: " + parsedData.users);
$('.users-online-container').attr("aria-label", "Online users: " + parsedData.users);
}
}, 75); // Update at most once every 100 milliseconds
@@ -1067,15 +1067,25 @@ function createListItem(element) {
function updateButtonState(buttonId, value) {
var button = $("#" + buttonId);
if (value == 0) {
button.hasClass("btn-disabled") ? null : button.addClass("btn-disabled");
button.attr('aria-description', 'Off');
if (button.length === 0) {
button = $("." + buttonId);
}
if (button.length > 0) {
if (value == 0) {
button.hasClass("btn-disabled") ? null : button.addClass("btn-disabled");
button.attr('aria-description', 'Off');
} else {
button.hasClass("btn-disabled") ? button.removeClass("btn-disabled") : null;
button.attr('aria-description', 'On');
}
} else {
button.hasClass("btn-disabled") ? button.removeClass("btn-disabled") : null;
button.attr('aria-description', 'On');
console.log("Button not found!");
}
}
function toggleButtonState(buttonId) {
parsedData[buttonId] = 1 - parsedData[buttonId]; // Toggle between 0 and 1
updateButtonState(buttonId, parsedData[buttonId]);
@@ -1122,9 +1132,6 @@ function showTunerDescription() {
if ($(window).width() < 768) {
$('.dashboard-panel-plugin-list').slideToggle(300);
$('#users-online-container').slideToggle(300);
$('.chatbutton').slideToggle(300);
$('#settings').slideToggle(300);
}
}

View File

@@ -1,11 +1,17 @@
$(document).ready(function() {
// Cache jQuery objects for reuse
var modal = $("#myModal");
var modalPanel = $(".modal-panel");
var openBtn = $("#settings");
var openBtn = $(".settings");
var closeBtn = $(".closeModal, .closeModalButton");
// Function to open the modal
initPopups();
openBtn.on("click", function() {
openModal(modalPanel);
});
closeBtn.on("click", closeModal);
function openModal(panel) {
modal.css("display", "block");
panel.css("display", "block");
@@ -22,25 +28,37 @@ $(document).ready(function() {
$("body").removeClass("modal-open"); // Enable body scrolling
}, 300);
}
// Event listeners for the open and close buttons
openBtn.on("click", function() {
openModal(modalPanel);
});
closeBtn.on("click", closeModal);
// Close the modal when clicking outside of it
$(document).on("click", function(event) {
$(document).on("click", function(event) { // Close the modal when clicking outside of it
if ($(event.target).is(modal)) {
closeModal();
}
});
// Close the modal when pressing ESC key
$(document).on("keydown", function(event) {
$(document).on("keydown", function(event) { // Close the modal when pressing ESC key
if (event.key === "Escape") {
closeModal();
}
});
});
$(".tuner-mobile-settings").on("click", function () {
$(".popup-window").fadeOut(200);
$("#popup-panel-mobile-settings").fadeIn(200);
});
});
function initPopups() {
$(".popup-window").draggable({
handle: ".popup-header",
containment: "body"
}).resizable({
minHeight: 330,
minWidth: 350,
containment: "body"
});
$(".popup-close").on("click", function () {
$(".popup-window").fadeOut(200);
});
}