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

optimization pack

This commit is contained in:
NoobishSVK
2024-11-05 21:08:55 +01:00
parent 59e7b975a8
commit 22a3138b92
18 changed files with 801 additions and 1251 deletions

48
web/js/api.js Normal file
View File

@@ -0,0 +1,48 @@
function tuneUp() {
if (socket.readyState === WebSocket.OPEN) {
getCurrentFreq();
let addVal = 0;
if (currentFreq < 0.52) {
addVal = 9 - (Math.round(currentFreq*1000) % 9);
} else if (currentFreq < 1.71) {
// TODO: Rework to replace 9 with 9 or 10 based on regionalisation setting
addVal = 9 - (Math.round(currentFreq*1000) % 9);
} else if (currentFreq < 29.6) {
addVal = 5 - (Math.round(currentFreq*1000) % 5);
} else if (currentFreq >= 65.9 && currentFreq < 74) {
addVal = 30 - ((Math.round(currentFreq*1000) - 65900) % 30);
} else {
addVal = 100 - (Math.round(currentFreq*1000) % 100);
}
socket.send("T" + (Math.round(currentFreq*1000) + addVal));
}
}
function tuneDown() {
if (socket.readyState === WebSocket.OPEN) {
getCurrentFreq();
let subVal = 0;
if (currentFreq < 0.52) {
subVal = (Math.round(currentFreq*1000) % 9 == 0) ? 9 : (Math.round(currentFreq*1000) % 9);
} else if (currentFreq < 1.71) {
// TODO: Rework to replace 9 with 9 or 10 based on regionalisation setting
subVal = (Math.round(currentFreq*1000) % 9 == 0) ? 9 : (Math.round(currentFreq*1000) % 9);
} else if (currentFreq < 29.6) {
subVal = (Math.round(currentFreq*1000) % 5 == 0) ? 5 : (Math.round(currentFreq*1000) % 5);
} else if (currentFreq > 65.9 && currentFreq <= 74) {
subVal = ((Math.round(currentFreq*1000) - 65900) % 30 == 0) ? 30 : ((Math.round(currentFreq*1000) - 65900) % 30);
} else {
subVal = (Math.round(currentFreq*1000) % 100 == 0) ? 100 : (Math.round(currentFreq*1000) % 100);
}
socket.send("T" + (Math.round(currentFreq*1000) - subVal));
}
}
function tuneTo(freq) {
socket.send("T" + ((freq).toFixed(1) * 1000));
}
function resetRDS() {
socket.send("T0");
}

View File

@@ -1,358 +1,123 @@
function submitData() {
const webserverIp = $('#webserver-ip').val() || '0.0.0.0';
const webserverPort = $('#webserver-port').val() || '8080';
const tuningLimit = $('#tuning-limit').is(":checked") || false;
const tuningLowerLimit = $('#tuning-lower-limit').val() || '0';
const tuningUpperLimit = $('#tuning-upper-limit').val() || '108';
const chatEnabled = $("#chat-switch").length > 0 ? $("#chat-switch").is(":checked") : true;
let configData = {}; // Store the original data structure globally
var themeSelectedValue = $("#selected-theme").val();
var themeDataValue = $(".option:contains('" + themeSelectedValue + "')").attr('data-value') || 'theme1';
const defaultTheme = themeDataValue;
$(document).ready(function() {
fetchConfig();
});
const bgImage = $("#bg-image").val() || '';
const rdsMode = $('#rds-mode').is(":checked") || false;
const ant1enabled = $('#ant1-enabled').is(":checked") || false;
const ant2enabled = $('#ant2-enabled').is(":checked") || false;
const ant3enabled = $('#ant3-enabled').is(":checked") || false;
const ant4enabled = $('#ant4-enabled').is(":checked") || false;
const ant1name = $("#ant1-name").val() || 'Ant A';
const ant2name = $("#ant2-name").val() || 'Ant B';
const ant3name = $("#ant3-name").val() || 'Ant C';
const ant4name = $("#ant4-name").val() || 'Ant D';
let presets = [];
presets.push($('#preset1').val() || '87.5');
presets.push($('#preset2').val() || '87.5');
presets.push($('#preset3').val() || '87.5');
presets.push($('#preset4').val() || '87.5');
const enableDefaultFreq = $('#default-freq-enable').is(":checked") || false;
const defaultFreq = $('#default-freq').val() || '87.5';
let banlist = [];
if($('#ip-addresses').length > 0) {
validateAndAdd(banlist);
}
var comDevicesValue = $("#com-devices").val();
var comDevicesDataValue = $(".option:contains('" + comDevicesValue + "')").attr('data-value') || '';
const comPort = comDevicesDataValue;
const wirelessConnection = $('#connection-type-toggle').is(":checked") || false;
const xdrdIp = $('#xdrd-ip').val() || '127.0.0.1';
const xdrdPort = $('#xdrd-port').val() || '7373';
const xdrdPassword = $('#xdrd-password').val() || 'password';
const audioDevice = $('#audio-devices').val() || 'Microphone (High Definition Audio Device)';
const audioChannels = ($('.options .option').filter(function() {
return $(this).text() === $('#audio-channels').val();
}).data('value') || 2);
const audioBitrate = ($('.options .option').filter(function() {
return $(this).text() === $('#audio-quality').val();
}).data('value') || "192k");
const device = ($('.options .option').filter(function() {
return $(this).text() === $('#device-type').val();
}).data('value') || "tef");
const softwareMode = $('#audio-software-mode').is(":checked") || false;
const startupVolume = $('#startup-volume').val() || '1';
const tunerName = $('#webserver-name').val() || 'FM Tuner';
const tunerDesc = $('#webserver-desc').val() || 'Default FM tuner description';
const broadcastTuner = $("#broadcast-tuner").is(":checked");
const contact = $("#owner-contact").val() || '';
const lat = $('#lat').val();
const lon = $('#lng').val();
const proxyIp = $("#broadcast-address").val();
const tunePass = $('#tune-pass').val();
const adminPass = $('#admin-pass').val();
let plugins = [];
$('#plugin-list option:selected').each(function() {
plugins.push($(this).data('name'));
});
const fmlistIntegration = $("#fmlist-integration").is(":checked") || false;
const fmlistOmid = $('#fmlist-omid').val();
const tunnelUsername = $('#tunnel-username').val();
const tunnelSubdomain = $('#tunnel-subdomain').val();
const tunnelToken = $('#tunnel-token').val();
const tunnelEnabled = $("#tunnel-enable").is(":checked");
const tunnelLowLatency = $("#tunnel-lowlatency").is(":checked");
const publicTuner = $("#tuner-public").is(":checked");
const lockToAdmin = $("#tuner-lock").is(":checked");
const autoShutdown = $("#shutdown-tuner").is(":checked") || false;
const antennasEnabled = $("#antenna-switch").is(":checked") || false;
const bwSwitch = $("#toggle-bw").is(":checked") || false;
const data = {
webserver: {
webserverIp,
webserverPort,
tuningLimit,
tuningLowerLimit,
tuningUpperLimit,
chatEnabled,
defaultTheme,
presets,
banlist,
bgImage,
rdsMode,
},
antennas: {
enabled: antennasEnabled,
ant1: {
enabled: ant1enabled,
name: ant1name
},
ant2: {
enabled: ant2enabled,
name: ant2name
},
ant3: {
enabled: ant3enabled,
name: ant3name
},
ant4: {
enabled: ant4enabled,
name: ant4name
},
},
xdrd: {
comPort,
wirelessConnection,
xdrdIp,
xdrdPort,
xdrdPassword
},
audio: {
audioDevice,
audioChannels,
audioBitrate,
softwareMode,
startupVolume,
},
identification: {
tunerName,
tunerDesc,
broadcastTuner,
contact,
lat,
lon,
proxyIp
},
password: {
tunePass,
adminPass,
},
extras: {
fmlistIntegration,
fmlistOmid,
},
tunnel: {
enabled: tunnelEnabled,
username: tunnelUsername,
token: tunnelToken,
lowLatencyMode: tunnelLowLatency,
subdomain: tunnelSubdomain,
},
plugins,
device,
publicTuner,
lockToAdmin,
autoShutdown,
enableDefaultFreq,
defaultFreq,
bwSwitch,
};
if(adminPass.length < 1) {
alert('You need to fill in the admin password before continuing further.');
return;
}
// Send data to the server using jQuery
$.ajax({
url: './saveData',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(data),
success: function (message) {
sendToast('success', 'Data saved!', message, true, true);
},
error: function (error) {
console.error(error);
}
});
function submitConfig() {
updateConfigData(configData);
if (!configData.password || !configData.password.adminPass) {
alert('You need to fill in the admin password before continuing further.');
return;
}
function fetchData() {
fetch("./getData")
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
})
.then(data => {
$('#webserver-ip').val(data.webserver.webserverIp);
$('#webserver-port').val(data.webserver.webserverPort);
$('#tuning-limit').prop("checked", data.webserver.tuningLimit);
$('#tuning-lower-limit').val(data.webserver.tuningLowerLimit || "");
$('#tuning-upper-limit').val(data.webserver.tuningUpperLimit || "");
$("#chat-switch").prop("checked", data.webserver.chatEnabled || false);
$('#selected-theme').val(data.webserver.defaultTheme || 'Default');
$('#rds-mode').prop("checked", data.webserver.rdsMode || false);
var selectedTheme = $(".option[data-value='" + data.webserver.defaultTheme + "']");
// If the option exists, set its text as the value of the input
if (selectedTheme.length > 0) {
$("#selected-theme").val(selectedTheme.text());
}
if (data.webserver.bgImage && data.webserver.bgImage.length > 0) {
$("#bg-image").val(data.webserver.bgImage);
}
if(Array.isArray(data.webserver.presets)) {
$('#preset1').val(data.webserver.presets[0] || "");
$('#preset2').val(data.webserver.presets[1] || "");
$('#preset3').val(data.webserver.presets[2] || "");
$('#preset4').val(data.webserver.presets[3] || "");
}
$("#default-freq-enable").prop("checked", data.enableDefaultFreq || false);
$('#default-freq').val(data.defaultFreq || "87.5");
$('#ip-addresses').val(data.webserver.banlist?.join('\n') || "");
$('#connection-type-toggle').prop("checked", data.xdrd.wirelessConnection || false);
if($('#connection-type-toggle').is(":checked")) {
$('#tuner-usb').hide();
$('#tuner-wireless').show();
} else {
$('#tuner-wireless').hide();
$('#tuner-usb').show();
}
$('#xdrd-ip').val(data.xdrd.xdrdIp);
$('#xdrd-port').val(data.xdrd.xdrdPort);
$('#xdrd-password').val(data.xdrd.xdrdPassword);
$('#com-devices').val(data.xdrd.comPort);
var selectedDevice = $(".option[data-value='" + data.xdrd.comPort + "']");
if (selectedDevice.length > 0) {
$("#com-devices").val(selectedDevice.text());
}
$('#device-type').val(data.device);
var selectedDevice = $(".option[data-value='" + data.device + "']");
if (selectedDevice.length > 0) {
$("#device-type").val(selectedDevice.text());
}
$('#toggle-bw').prop("checked", data.bwSwitch ? data.bwSwitch : false);
$('#audio-devices').val(data.audio.audioDevice);
$('#audio-channels').val(data.audio.audioChannels);
var selectedChannels = $(".option[data-value='" + data.audio.audioChannels + "']");
if (selectedChannels.length > 0) {
$("#audio-channels").val(selectedChannels.text());
}
$('#audio-quality').val(data.audio.audioBitrate);
var selectedQuality = $(".option[data-value='" + data.audio.audioBitrate + "']");
if (selectedQuality.length > 0) {
$("#audio-quality").val(selectedQuality.text());
}
var antennaNames = ['ant1', 'ant2', 'ant3', 'ant4'];
// Iterate over each antenna name
antennaNames.forEach(function(antenna) {
// Set values based on the antenna name
$('#' + antenna + '-name').val(data.antennas?.[antenna]?.name || '');
$('#' + antenna + '-enabled').prop("checked", data.antennas?.[antenna]?.enabled || false);
});
$('#audio-software-mode').prop("checked", data.audio.softwareMode || false);
$('#startup-volume').val(data.audio.startupVolume || 1);
$('#volume-percentage-value').text(data.audio.startupVolume !== undefined ? (data.audio.startupVolume * 100).toFixed(0) + '%' : '100%');
$('#webserver-name').val(data.identification.tunerName);
$('#webserver-desc').val(data.identification.tunerDesc);
$("#broadcast-tuner").prop("checked", data.identification.broadcastTuner);
$("#broadcast-address").val(data.identification.proxyIp);
$("#owner-contact").val(data.identification.contact);
$('#lat').val(data.identification.lat);
$('#lng').val(data.identification.lon);
$('#tune-pass').val(data.password.tunePass);
$('#admin-pass').val(data.password.adminPass);
$("#tuner-public").prop("checked", data.publicTuner);
$("#tuner-lock").prop("checked", data.lockToAdmin);
$("#shutdown-tuner").prop("checked", data.autoShutdown);
$("#antenna-switch").prop("checked", data.antennas?.enabled);
data.plugins.forEach(function(name) {
// Find the option with the corresponding data-name attribute and mark it as selected
$('#plugin-list option[data-name="' + name + '"]').prop('selected', true);
});
// Update the multi-select element to reflect the changes
$('#plugin-list').trigger('change');
// Check if latitude and longitude are present in the data
if (data.identification.lat && data.identification.lon) {
// Set the map's center to the received coordinates
map.setView([data.identification.lat, data.identification.lon], 13);
// Add a pin to the map
if (typeof pin == "object") {
pin.setLatLng([data.identification.lat, data.identification.lon]);
} else {
pin = L.marker([data.identification.lat, data.identification.lon], { riseOnHover:true, draggable:true });
pin.addTo(map);
pin.on('drag',function(ev) {
$('#lat').val((ev.latlng.lat).toFixed(6));
$('#lng').val((ev.latlng.lng).toFixed(6));
});
}
}
$("#fmlist-integration").prop("checked", !!(data.extras && data.extras?.fmlistIntegration));
$('#fmlist-omid').val(data.extras?.fmlistOmid);
$("#tunnel-enable").prop("checked", !!(data.tunnel && data.tunnel?.enabled));
$("#tunnel-lowlatency").prop("checked", !!(data.tunnel && data.tunnel?.lowLatencyMode));
$('#tunnel-token').val(data.tunnel?.token);
$('#tunnel-subdomain').val(data.tunnel?.subdomain);
$('#tunnel-username').val(data.tunnel?.username);
})
.catch(error => {
console.error('Error fetching data:', error.message);
});
$.ajax({
url: './saveData',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(configData),
success: function (message) {
sendToast('success', 'Data saved!', message, true, true);
},
error: function (error) {
console.error(error);
}
});
}
function fetchConfig() {
$.getJSON("./getData")
.done(data => {
configData = data;
populateFields(configData);
initVolumeSlider();
initConnectionToggle();
})
.fail(error => console.error("Error fetching data:", error.message));
}
function validateAndAdd(banlist) {
var textarea = $('#ip-addresses');
var ipAddresses = textarea.val().split('\n');
function populateFields(data, prefix = "") {
$.each(data, (key, value) => {
// Regular expression to validate IP address
var ipRegex = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/;
if (key === "presets" && Array.isArray(value)) {
value.forEach((item, index) => {
const presetId = `${prefix}${prefix ? "-" : ""}${key}-${index + 1}`;
const $element = $(`#${presetId}`);
ipAddresses.forEach(function(ip) {
if (ipRegex.test(ip)) {
banlist.push(ip);
if ($element.length) {
$element.val(item);
}
});
return;
}
if (key === "banlist" && Array.isArray(value)) {
const $textarea = $(`#${prefix}${prefix ? "-" : ""}${key}`);
if ($textarea.length && $textarea.is("textarea")) {
$textarea.val(value.join("\n"));
}
return;
}
const id = `${prefix}${prefix ? "-" : ""}${key}`;
const $element = $(`#${id}`);
if (typeof value === "object" && !Array.isArray(value)) {
populateFields(value, id);
return;
}
if (!$element.length) {
console.log(`Element with id ${id} not found`);
return;
}
if (typeof value === "boolean") {
$element.prop("checked", value);
} else if ($element.is('input[type="text"]') && $element.closest('.dropdown').length) {
const $dropdownOption = $element.siblings('ul.options').find(`li[data-value="${value}"]`);
$element.val($dropdownOption.length ? $dropdownOption.text() : value);
$element.attr('data-value', value);
} else {
$element.val(value);
}
});
}
function updateConfigData(data, prefix = "") {
$.each(data, (key, value) => {
const id = `${prefix}${prefix ? "-" : ""}${key}`;
const $element = $(`#${id}`);
if (key === "presets") {
data[key] = [];
let index = 1;
while (true) {
const $presetElement = $(`#${prefix}${prefix ? "-" : ""}${key}-${index}`);
if ($presetElement.length) {
data[key].push($presetElement.val());
index++;
} else {
break;
}
}
return;
}
if (key === "banlist") {
const $textarea = $(`#${prefix}${prefix ? "-" : ""}${key}`);
if ($textarea.length && $textarea.is("textarea")) {
data[key] = $textarea.val().split("\n").filter(line => line.trim() !== ""); // Split lines into an array and filter out empty lines
}
return;
}
if (typeof value === "object" && !Array.isArray(value)) {
return updateConfigData(value, id);
}
if ($element.length) {
data[key] = typeof value === "boolean" ? $element.is(":checked") : $element.attr("data-value") ?? $element.val();
}
});
}

View File

@@ -33,7 +33,9 @@ $(document).ready(function() {
$currentDropdown.find('input').val($(event.currentTarget).text());
break;
default:
$currentDropdown.find('input').val($(event.currentTarget).text());
$currentDropdown.find('input')
.val($(event.currentTarget).text())
.attr('data-value', $(event.currentTarget).data('value'));
break;
}

View File

@@ -1,27 +1,28 @@
var currentDate = new Date('Sep 26, 2024 12:00:00');
var currentDate = new Date('Nov 5, 2024 21: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.1 [' + formattedDate + ']';
var currentVersion = 'v1.3.2 [' + formattedDate + ']';
getInitialSettings();
removeUrlParameters(); // Call this function to remove URL parameters
removeUrlParameters();
function getInitialSettings() {
$.ajax({
url: './static_data',
dataType: 'json',
success: function (data) {
localStorage.setItem('qthLatitude', data.qthLatitude);
localStorage.setItem('qthLongitude', data.qthLongitude);
localStorage.setItem('defaultTheme', data.defaultTheme);
localStorage.setItem('preset1', data.presets[0]);
localStorage.setItem('preset2', data.presets[1]);
localStorage.setItem('preset3', data.presets[2]);
localStorage.setItem('preset4', data.presets[3]);
localStorage.setItem('bgImage', data.bgImage);
localStorage.setItem('rdsMode', data.rdsMode);
['qthLatitude', 'qthLongitude', 'defaultTheme', 'bgImage', 'rdsMode'].forEach(key => {
if (data[key] !== undefined) {
localStorage.setItem(key, data[key]);
}
});
data.presets.forEach((preset, index) => {
localStorage.setItem(`preset${index + 1}`, preset);
});
},
error: function (error) {
console.error('Error:', error);

View File

@@ -124,9 +124,26 @@ $(document).ready(function () {
}
});
document.onkeydown = checkKey;
document.onkeydown = function(event) {
if (!event.repeat) {
checkKey(event);
}
};
let lastExecutionTime = 0;
const throttleDelay = 100; // Time in ms
$('#freq-container').on('wheel keypress', function (e) {
e.preventDefault();
const now = Date.now();
if (now - lastExecutionTime < throttleDelay) {
// Ignore this event as it's within the throttle delay
return;
}
lastExecutionTime = now; // Update the last execution time
getCurrentFreq();
var delta = e.originalEvent.deltaY;
var adjustment = 0;
@@ -654,54 +671,6 @@ function checkKey(e) {
}
}
function tuneUp() {
if (socket.readyState === WebSocket.OPEN) {
getCurrentFreq();
let addVal = 0;
if (currentFreq < 0.52) {
addVal = 9 - (Math.round(currentFreq*1000) % 9);
} else if (currentFreq < 1.71) {
// TODO: Rework to replace 9 with 9 or 10 based on regionalisation setting
addVal = 9 - (Math.round(currentFreq*1000) % 9);
} else if (currentFreq < 29.6) {
addVal = 5 - (Math.round(currentFreq*1000) % 5);
} else if (currentFreq >= 65.9 && currentFreq < 74) {
addVal = 30 - ((Math.round(currentFreq*1000) - 65900) % 30);
} else {
addVal = 100 - (Math.round(currentFreq*1000) % 100);
}
socket.send("T" + (Math.round(currentFreq*1000) + addVal));
}
}
function tuneDown() {
if (socket.readyState === WebSocket.OPEN) {
getCurrentFreq();
let subVal = 0;
if (currentFreq < 0.52) {
subVal = (Math.round(currentFreq*1000) % 9 == 0) ? 9 : (Math.round(currentFreq*1000) % 9);
} else if (currentFreq < 1.71) {
// TODO: Rework to replace 9 with 9 or 10 based on regionalisation setting
subVal = (Math.round(currentFreq*1000) % 9 == 0) ? 9 : (Math.round(currentFreq*1000) % 9);
} else if (currentFreq < 29.6) {
subVal = (Math.round(currentFreq*1000) % 5 == 0) ? 5 : (Math.round(currentFreq*1000) % 5);
} else if (currentFreq > 65.9 && currentFreq <= 74) {
subVal = ((Math.round(currentFreq*1000) - 65900) % 30 == 0) ? 30 : ((Math.round(currentFreq*1000) - 65900) % 30);
} else {
subVal = (Math.round(currentFreq*1000) % 100 == 0) ? 100 : (Math.round(currentFreq*1000) % 100);
}
socket.send("T" + (Math.round(currentFreq*1000) - subVal));
}
}
function tuneTo(freq) {
socket.send("T" + ((freq).toFixed(1) * 1000));
}
function resetRDS(freq) {
socket.send("T" + ((freq).toFixed(3) * 1000));
}
async function copyPs() {
var frequency = $('#data-frequency').text();
var pi = $('#data-pi').text();
@@ -1055,33 +1024,20 @@ function toggleForcedStereo() {
socket.send(message);
}
function toggleAdminLock() {
let $adminLockButton = $('#dashboard-lock-admin');
function toggleLock(buttonSelector, activeMessage, inactiveMessage, activeLabel, inactiveLabel) {
let $lockButton = $(buttonSelector);
if($adminLockButton.hasClass('active')) {
socket.send('wL0');
$adminLockButton.attr('aria-label', 'Lock Tuner (Admin)')
$adminLockButton.removeClass('active');
if ($lockButton.hasClass('active')) {
socket.send(inactiveMessage);
$lockButton.attr('aria-label', inactiveLabel);
$lockButton.removeClass('active');
} else {
socket.send('wL1');
$adminLockButton.attr('aria-label', 'Unlock Tuner (Admin)')
$adminLockButton.addClass('active');
socket.send(activeMessage);
$lockButton.attr('aria-label', activeLabel);
$lockButton.addClass('active');
}
}
function togglePasswordLock() {
let $passwordLockButton = $('#dashboard-lock-tune');
if($passwordLockButton.hasClass('active')) {
socket.send('wT0');
$passwordLockButton.removeClass('active');
$passwordLockButton.attr('aria-label', 'Lock Tuner (Password tune)')
} else {
socket.send('wT1');
$passwordLockButton.addClass('active');
$passwordLockButton.attr('aria-label', 'Unlock Tuner (Password tune)')
}
}
function initTooltips() {
$('.tooltip').hover(function(e){

View File

@@ -3,161 +3,20 @@ var pin;
var tilesURL=' https://tile.openstreetmap.org/{z}/{x}/{y}.png';
var mapAttrib='&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>';
// add map container
$(document).ready(function() {
MapCreate();
fetchData();
$('#startup-volume').on('change', function() {
var value = $(this).val(); // Get the value of the range input
var percentage = value * 100; // Convert to percentage
$('#volume-percentage-value').text(percentage.toFixed(0) + '%'); // Display the percentage value
});
map.on('click', function(ev) {
$('#lat').val((ev.latlng.lat).toFixed(6));
$('#lng').val((ev.latlng.lng).toFixed(6));
if (typeof pin == "object") {
pin.setLatLng(ev.latlng);
} else {
pin = L.marker(ev.latlng,{ riseOnHover:true,draggable:true });
pin.addTo(map);
pin.on('drag',function(ev) {
$('#lat').val((ev.latlng.lat).toFixed(6));
$('#lng').val((ev.latlng.lng).toFixed(6));
});
}
});
$('#dashboard').show();
mapCreate();
loadConsoleLogs();
showPanelFromHash();
$('.nav li').click(function() {
// Remove background color from all li elements
$('.nav li').removeClass('active');
// Add background color to the clicked li element
$(this).addClass('active');
// Get the data-panel attribute value
var panelId = $(this).data('panel');
window.location.hash = panelId;
// Hide all panels
$('.tab-content').hide();
// Show the corresponding panel
$('#' + panelId).show();
if(panelId == 'identification') {
setTimeout(function () {
map.invalidateSize();
}, 200);
}
});
$('#connection-type-toggle').change(function(){
if($(this).is(":checked")) {
$('#tuner-usb').hide();
$('#tuner-wireless').show();
} else {
$('#tuner-wireless').hide();
$('#tuner-usb').show();
}
});
$('.logout-link').click(function (event) {
event.preventDefault();
// Perform an AJAX request to the /logout endpoint
$.ajax({
type: 'GET', // Assuming the logout is a GET request, adjust accordingly
url: './logout',
success: function (data) {
// Update the content on the page with the message from the response
$('#login-message').text(data.message);
setTimeout(function () {
location.reload(true);
}, 1750);
},
error: function (xhr, status, error) {
// Handle error response
if (xhr.status === 403) {
// Update the content on the page with the message from the error response
$('#login-message').text(xhr.responseJSON.message);
} else {
// Handle other types of errors if needed
console.error('Error:', status, error);
}
}
});
});
function stripAnsi(str) {
return str.replace(/\u001b\[\d+m/g, '');
}
$("pre").html(function(_, html) {
html = stripAnsi(html);
return html.replace(/\[(\d{2}:\d{2})\]|\[(INFO|DEBUG|WARN|ERROR)\]/g, function(match, time, level) {
if (time) {
return "<span style='color: gray;'>" + match + "</span>";
} else if (level === "INFO") {
return "<span style='color: lime;'>" + match + "</span>";
} else if (level === "DEBUG") {
return "<span style='color: cyan;'>" + match + "</span>";
} else if (level === "WARN") {
return "<span style='color: yellow;'>" + match + "</span>";
} else if (level === "ERROR") {
return "<span style='color: red;'>" + match + "</span>";
} else {
return "<span style='color: white;'>" + match + "</span>";
}
});
});
if($("#console-output").length > 0) {
$("#console-output").scrollTop($("#console-output")[0].scrollHeight);
}
const $tabs = $('.nav li[role="presentation"]');
let currentTabIndex = 0;
function updateTabFocus(index) {
$tabs.each(function(i) {
const $link = $(this).find('a');
if (i === index) {
$(this).attr('aria-selected', 'true');
$link.attr('tabindex', '0').focus();
} else {
$(this).attr('aria-selected', 'false');
$link.attr('tabindex', '-1');
}
});
}
function handleKeyDown(event) {
if (event.key === 'ArrowRight') {
event.preventDefault();
currentTabIndex = (currentTabIndex + 1) % $tabs.length;
updateTabFocus(currentTabIndex);
} else if (event.key === 'ArrowLeft') {
event.preventDefault();
currentTabIndex = (currentTabIndex - 1 + $tabs.length) % $tabs.length;
updateTabFocus(currentTabIndex);
} else if (event.key === 'Enter') {
event.preventDefault();
$tabs.eq(currentTabIndex).find('a')[0].click();
}
}
updateTabFocus(currentTabIndex);
$tabs.on('keydown', handleKeyDown);
//toggleNav();
initNav();
});
function MapCreate() {
// create map instance
/**
* Function to create & handle maps.
* Also contains map handling such as reloading / pin click registering.
*/
function mapCreate() {
if (!(typeof map == "object")) {
map = L.map('map', {
center: [40,0],
@@ -167,39 +26,70 @@ function MapCreate() {
else {
map.setZoom(3).panTo([40,0]);
}
// create the tile layer with correct attribution
L.tileLayer(tilesURL, {
attribution: mapAttrib,
maxZoom: 19
}).addTo(map);
map.on('click', function(ev) {
$('#identification-lat').val((ev.latlng.lat).toFixed(6));
$('#identification-lon').val((ev.latlng.lng).toFixed(6));
if (typeof pin == "object") {
pin.setLatLng(ev.latlng);
} else {
pin = L.marker(ev.latlng,{ riseOnHover:true,draggable:true });
pin.addTo(map);
pin.on('dragend',function(ev) {
$('#identification-lat').val((ev.latlng.lat).toFixed(6));
$('#identification.lon').val((ev.latlng.lng).toFixed(6));
});
}
});
mapReload();
}
function showPanelFromHash() {
var panelId = window.location.hash.substring(1);
if (panelId) {
// Hide all panels
$('.tab-content').hide();
// Show the panel corresponding to the hash fragment
$('#' + panelId).show();
// Remove active class from all li elements
$('.nav li').removeClass('active');
// Add active class to the corresponding li element
$('.nav li[data-panel="' + panelId + '"]').addClass('active');
}
if(window.location.hash.length == 0) {
$('.nav li[data-panel="dashboard"]').addClass('active');
function mapReload() {
setTimeout(function () {
map.invalidateSize();
}, 200);
}
function showPanelFromHash() {
var panelId = window.location.hash.substring(1) || 'dashboard';
$('.tab-content').hide();
$('#' + panelId).show();
$('.nav li').removeClass('active');
$('.nav li[data-panel="' + panelId + '"]').addClass('active');
}
function initNav() {
$('.nav li').click(function() {
$('.nav li').removeClass('active');
$(this).addClass('active');
var panelId = $(this).data('panel');
window.location.hash = panelId;
$('.tab-content').hide();
$('#' + panelId).show();
panelId == 'identification' ? mapReload() : null;
});
$('[role="tab"]').on('keydown', function(event) {
if (event.key === 'Enter') {
$(this).find('a').click();
}
});
}
function toggleNav() {
const navOpen = $("#navigation").css('margin-left') === '0px';
const isMobile = window.innerWidth <= 768; // Define mobile screen width threshold (you can adjust this as needed)
const isMobile = window.innerWidth <= 768;
if (navOpen) {
// Close the navigation
if (isMobile) {
// Do nothing to .admin-wrapper on mobile (since we're overlaying)
$(".admin-wrapper").css({
@@ -217,10 +107,8 @@ function toggleNav() {
}
$(".sidenav-close").html('<i class="fa-solid fa-chevron-right"></i>');
} else {
// Open the navigation
$("#navigation").css('margin-left', '0');
if (isMobile) {
// On mobile, overlay the navigation
$(".admin-wrapper").css({
'margin-left': '0', // Keep content in place when sidenav is open
'width': '100%' // Keep content at full width
@@ -235,3 +123,69 @@ function toggleNav() {
$(".sidenav-close").html('<i class="fa-solid fa-chevron-left"></i>');
}
}
function initVolumeSlider() {
const $volumeInput = $('#audio-startupVolume');
const $percentageValue = $('#volume-percentage-value');
const updateDisplay = () => {
$percentageValue.text(($volumeInput.val() * 100).toFixed(0) + '%');
};
updateDisplay();
$volumeInput.on('change', updateDisplay);
}
function initConnectionToggle() {
const connectionToggle = $('#xdrd-wirelessConnection');
const tunerUSB = $('#tuner-usb');
const tunerWireless = $('#tuner-wireless');
function toggleType() {
if (connectionToggle.is(":checked")) {
tunerUSB.hide();
tunerWireless.show();
} else {
tunerWireless.hide();
tunerUSB.show();
}
}
toggleType();
connectionToggle.change(toggleType);
}
function stripAnsi(str) {
return str.replace(/\u001b\[\d+m/g, '');
}
async function loadConsoleLogs() {
await new Promise((resolve) => {
$("pre").html(function (_, html) {
html = stripAnsi(html);
const logColors = {
INFO: "lime",
DEBUG: "cyan",
WARN: "yellow",
ERROR: "red"
};
let firstBracketProcessed = false;
const processedHtml = html.replace(/\[([^\]]+)\]/g, function (match, content) {
if (!firstBracketProcessed) {
firstBracketProcessed = true;
return `<span style='color: gray;'>${match}</span>`;
}
const color = logColors[content] || "white";
return `<span style='color: ${color};'>${match}</span>`;
});
return processedHtml;
});
resolve();
});
$("#console-output").scrollTop($("#console-output")[0].scrollHeight);
}

View File

@@ -1,22 +1,18 @@
function sendToast(type, title, message, persistent, important) {
var toastId = 'toast-' + new Date().getTime(); // Unique ID for each toast
var toastId = 'toast-' + new Date().getTime();
// If title isn't provided, use the type as the title
var toastTitle = title ? title : capitalizeFirstLetter(type);
// Icon mapping based on the toast type
var toastIcons = {
success: 'fa-check-circle',
error: 'fa-times-circle',
warning: 'fa-exclamation-triangle',
info: 'fa-info-circle',
default: 'fa-bell' // Default icon if the type is not found
default: 'fa-bell'
};
// Get the icon class based on the toast type, fallback to 'default' if type doesn't exist
var iconClass = toastIcons[type] || toastIcons['default'];
var iconClass = toastIcons[type] || toastIcons['default']; // Get the icon class based on the toast type, fallback to 'default' if type doesn't exist
// Create the toast element
var $toast = $(`
<div class="toast ${type} flex-container flex-phone ${important ? 'important' : ''}" id="${toastId}">
<div class="toast-icon"><i class="fa-solid ${iconClass}"></i></div>
@@ -28,33 +24,28 @@ function sendToast(type, title, message, persistent, important) {
</div>
`);
// Append the toast to the container
$('#toast-container').append($toast);
// Add the 'show' class after appending for fade-in effect
setTimeout(function () {
$toast.addClass('show');
}, 10); // Timeout to ensure the element is appended before the animation triggers
}, 10);
// Close button functionality
$toast.find('.close-btn').click(function () {
closeToast($toast);
});
// If not persistent, remove it after 5 seconds
if (!persistent) {
setTimeout(function () {
closeToast($toast);
}, 5000); // 5000 ms = 5 seconds
}, 5000);
}
}
// Function to close and remove the toast
function closeToast($toast) {
$toast.removeClass('show'); // Trigger fade-out
$toast.removeClass('show');
setTimeout(function () {
$toast.remove(); // Remove the element from DOM after the animation
}, 300); // Timeout matches the CSS transition duration
$toast.remove();
}, 300);
}
function capitalizeFirstLetter(string) {

View File

@@ -1,3 +1,4 @@
$.getScript('./js/api.js');
$.getScript('./js/main.js');
$.getScript('./js/dropdown.js');
$.getScript('./js/modal.js');

View File

@@ -1,40 +1,9 @@
$(document).ready(function() {
if($('.step:visible').index() == 0) {
$('.btn-prev').hide();
}
$('.btn-next').click(function() {
var currentStep = $('.step:visible');
var nextStep = currentStep.next('.step');
if (nextStep.length !== 0) {
currentStep.hide();
nextStep.show();
updateProgressBar(nextStep);
} else {
submitData();
}
updateWizardContent();
});
$('.btn-prev').click(function() {
var currentStep = $('.step:visible');
var nextStep = currentStep.prev('.step');
if (nextStep.length !== 0) {
currentStep.hide();
nextStep.show();
updateProgressBar(nextStep);
} else {
alert('You have reached the beginning of the wizard.');
}
updateWizardContent();
});
$('.btn-prev').toggle($('.step:visible').index() !== 0);
$('.btn-next').click(() => navigateStep(true));
$('.btn-prev').click(() => navigateStep(false));
});
// Function to update the progress bar buttons
function updateProgressBar(currentStep) {
var stepIndex = $('.step').index(currentStep) + 1;
$('.btn-rounded-cube').removeClass('activated');
@@ -42,21 +11,24 @@ function updateProgressBar(currentStep) {
}
function updateWizardContent() {
if($('.step:visible').index() == 0) {
$('.btn-prev').hide();
} else {
$('.btn-prev').show();
}
var visibleStepIndex = $('.step:visible').index();
if($('.step:visible').index() == 3) {
setTimeout(function () {
map.invalidateSize();
}, 200);
}
$('.btn-prev').toggle(visibleStepIndex !== 0);
$('.btn-next').text(visibleStepIndex === 4 ? 'Save' : 'Next');
visibleStepIndex === 3 && mapReload();
}
function navigateStep(isNext) {
var currentStep = $('.step:visible');
var targetStep = isNext ? currentStep.next('.step') : currentStep.prev('.step');
if($('.step:visible').index() == 4) {
$('.btn-next').text('Save');
} else {
$('.btn-next').text('Next')
if (targetStep.length !== 0) {
currentStep.hide();
targetStep.show();
updateProgressBar(targetStep);
} else if (isNext) {
submitData();
}
updateWizardContent();
}