You've already forked fm-dx-webserver
mirror of
https://github.com/KubaPro010/fm-dx-webserver.git
synced 2026-02-26 22:13:53 +01:00
new admin system, ui changes, bugfixes
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
var _3LAS_Settings = /** @class */ (function () {
|
||||
function _3LAS_Settings() {
|
||||
this.SocketHost = document.location.hostname ? document.location.hostname : "127.0.0.1";
|
||||
this.SocketPort = localStorage.getItem('audioPort') ? localStorage.getItem('audioPort') : 8081;
|
||||
this.SocketPath = "/";
|
||||
this.WebRTC = new WebRTC_Settings();
|
||||
this.Fallback = new Fallback_Settings();
|
||||
|
||||
145
web/js/confighandler.js
Normal file
145
web/js/confighandler.js
Normal file
@@ -0,0 +1,145 @@
|
||||
function submitData() {
|
||||
const webserverIp = $('#webserver-ip').val() || '0.0.0.0';
|
||||
const webserverPort = $('#webserver-port').val() || '8080';
|
||||
|
||||
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 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();
|
||||
|
||||
const publicTuner = $("#tuner-public").is(":checked");
|
||||
const lockToAdmin = $("#tuner-lock").is(":checked");
|
||||
const autoShutdown = $("#shutdown-tuner").is(":checked") || false;
|
||||
const antennaSwitch = $("#antenna-switch").is(":checked") || false;
|
||||
|
||||
const data = {
|
||||
webserver: {
|
||||
webserverIp,
|
||||
webserverPort,
|
||||
},
|
||||
xdrd: {
|
||||
xdrdIp,
|
||||
xdrdPort,
|
||||
xdrdPassword
|
||||
},
|
||||
audio: {
|
||||
audioDevice,
|
||||
audioChannels,
|
||||
audioBitrate,
|
||||
},
|
||||
identification: {
|
||||
tunerName,
|
||||
tunerDesc,
|
||||
broadcastTuner,
|
||||
contact,
|
||||
lat,
|
||||
lon,
|
||||
proxyIp
|
||||
},
|
||||
password: {
|
||||
tunePass,
|
||||
adminPass,
|
||||
},
|
||||
publicTuner,
|
||||
lockToAdmin,
|
||||
autoShutdown,
|
||||
antennaSwitch,
|
||||
};
|
||||
|
||||
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) {
|
||||
alert(message);
|
||||
},
|
||||
error: function (error) {
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function fetchData() {
|
||||
// Make a GET request to retrieve the data.json file
|
||||
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);
|
||||
|
||||
$('#xdrd-ip').val(data.xdrd.xdrdIp);
|
||||
$('#xdrd-port').val(data.xdrd.xdrdPort);
|
||||
$('#xdrd-password').val(data.xdrd.xdrdPassword);
|
||||
|
||||
$('#audio-devices').val(data.audio.audioDevice);
|
||||
$('#audio-channels').val(data.audio.audioChannels);
|
||||
$('#audio-quality').val(data.audio.audioBitrate);
|
||||
|
||||
$('#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.antennaSwitch);
|
||||
|
||||
// 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));
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching data:', error.message);
|
||||
});
|
||||
}
|
||||
@@ -3,6 +3,7 @@ url.protocol = url.protocol.replace('http', 'ws');
|
||||
var socketAddress = url.href;
|
||||
var socket = new WebSocket(socketAddress);
|
||||
var parsedData, signalChart, previousFreq;
|
||||
var signalData = [];
|
||||
var data = [];
|
||||
let updateCounter = 0;
|
||||
|
||||
@@ -118,6 +119,7 @@ $(document).ready(function () {
|
||||
var piCodeContainer = $('#pi-code-container')[0];
|
||||
var freqContainer = $('#freq-container')[0];
|
||||
var txContainer = $('#data-station-container')[0];
|
||||
var stereoContainer = $('#stereo-container')[0];
|
||||
|
||||
$("#data-eq").click(function () {
|
||||
toggleButtonState("eq");
|
||||
@@ -133,6 +135,7 @@ $(document).ready(function () {
|
||||
$(rtContainer).on("click", copyRt);
|
||||
$(txContainer).on("click", copyTx);
|
||||
$(piCodeContainer).on("click", findOnMaps);
|
||||
$(stereoContainer).on("click", toggleForcedStereo);
|
||||
$(freqContainer).on("click", function () {
|
||||
textInput.focus();
|
||||
});
|
||||
@@ -514,24 +517,31 @@ function findOnMaps() {
|
||||
window.open(url, "_blank");
|
||||
}
|
||||
|
||||
function updateSignalUnits(parsedData) {
|
||||
function updateSignalUnits(parsedData, averageSignal) {
|
||||
const signalUnit = localStorage.getItem('signalUnit');
|
||||
let currentSignal;
|
||||
|
||||
if(localStorage.getItem("smoothSignal") == 'true') {
|
||||
currentSignal = averageSignal
|
||||
} else {
|
||||
currentSignal = parsedData.signal;
|
||||
}
|
||||
let signalText = $('#signal-units');
|
||||
let signalValue;
|
||||
|
||||
switch (signalUnit) {
|
||||
case 'dbuv':
|
||||
signalValue = parsedData.signal - 11.25;
|
||||
signalValue = currentSignal - 11.25;
|
||||
signalText.text('dBµV');
|
||||
break;
|
||||
|
||||
case 'dbm':
|
||||
signalValue = parsedData.signal - 120;
|
||||
signalValue = currentSignal - 120;
|
||||
signalText.text('dBm');
|
||||
break;
|
||||
|
||||
default:
|
||||
signalValue = parsedData.signal;
|
||||
signalValue = currentSignal;
|
||||
signalText.text('dBf');
|
||||
break;
|
||||
}
|
||||
@@ -551,15 +561,6 @@ function updateDataElements(parsedData) {
|
||||
parsedData.ps = parsedData.ps.replace(/\s/g, '_');
|
||||
}
|
||||
$('#data-ps').html(parsedData.ps === '?' ? "<span class='opacity-half'>?</span>" : processString(parsedData.ps, parsedData.ps_errors));
|
||||
$('.data-tp').html(parsedData.tp === 0 ? "<span class='opacity-half'>TP</span>" : "TP");
|
||||
$('.data-ta').html(parsedData.ta === 0 ? "<span class='opacity-half'>TA</span>" : "TA");
|
||||
$('.data-ms').html(parsedData.ms === 0
|
||||
? "<span class='opacity-half'>M</span><span class='opacity-full'>S</span>"
|
||||
: (parsedData.ms === -1
|
||||
? "<span class='opacity-half'>M</span><span class='opacity-half'>S</span>"
|
||||
: "<span class='opacity-full'>M</span><span class='opacity-half'>S</span>"
|
||||
)
|
||||
);
|
||||
$('.data-pty').html(europe_programmes[parsedData.pty]);
|
||||
|
||||
|
||||
@@ -580,6 +581,7 @@ function updateDataElements(parsedData) {
|
||||
$('#data-rt0').html(processString(parsedData.rt0, parsedData.rt0_errors));
|
||||
$('#data-rt1').html(processString(parsedData.rt1, parsedData.rt1_errors));
|
||||
$('.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>`);
|
||||
$('#data-ant input').val($('#data-ant li[data-value="' + parsedData.ant + '"]').text());
|
||||
|
||||
if (parsedData.txInfo.station.length > 1) {
|
||||
@@ -596,6 +598,18 @@ function updateDataElements(parsedData) {
|
||||
}
|
||||
|
||||
updateCounter++;
|
||||
if(updateCounter % 8 === 0) {
|
||||
$('.data-tp').html(parsedData.tp === 0 ? "<span class='opacity-half'>TP</span>" : "TP");
|
||||
$('.data-ta').html(parsedData.ta === 0 ? "<span class='opacity-half'>TA</span>" : "TA");
|
||||
$('.data-ms').html(parsedData.ms === 0
|
||||
? "<span class='opacity-half'>M</span><span class='opacity-full'>S</span>"
|
||||
: (parsedData.ms === -1
|
||||
? "<span class='opacity-half'>M</span><span class='opacity-half'>S</span>"
|
||||
: "<span class='opacity-full'>M</span><span class='opacity-half'>S</span>"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (updateCounter % 30 === 0) {
|
||||
$('#data-ps').attr('aria-label', parsedData.ps);
|
||||
$('#data-rt0').attr('aria-label', parsedData.rt0);
|
||||
@@ -608,6 +622,13 @@ let isEventListenerAdded = false;
|
||||
function updatePanels(parsedData) {
|
||||
updateCounter++;
|
||||
|
||||
signalData.push(parsedData.signal);
|
||||
if (signalData.length > 8) {
|
||||
signalData.shift(); // Remove the oldest element
|
||||
}
|
||||
const sum = signalData.reduce((acc, strNum) => acc + parseFloat(strNum), 0);
|
||||
const averageSignal = sum / signalData.length;
|
||||
|
||||
const sortedAf = parsedData.af.sort(compareNumbers);
|
||||
const scaledArray = sortedAf.map(element => element / 1000);
|
||||
|
||||
@@ -642,9 +663,8 @@ function updatePanels(parsedData) {
|
||||
listContainer.scrollTop(scrollTop);
|
||||
}
|
||||
|
||||
// Update other elements every time
|
||||
updateDataElements(parsedData);
|
||||
updateSignalUnits(parsedData);
|
||||
updateSignalUnits(parsedData, averageSignal);
|
||||
$('.users-online').text(parsedData.users);
|
||||
}
|
||||
|
||||
@@ -669,3 +689,9 @@ function toggleButtonState(buttonId) {
|
||||
message += parsedData.ims ? "1" : "0";
|
||||
socket.send(message);
|
||||
}
|
||||
|
||||
function toggleForcedStereo() {
|
||||
var message = "B";
|
||||
message += parsedData.st_forced = (parsedData.st_forced == "1") ? "0" : "1";
|
||||
socket.send(message);
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
var currentVersion = 'v1.1.0 [29.2.2024]';
|
||||
|
||||
/**
|
||||
* Themes
|
||||
* @param first color
|
||||
* @param second color
|
||||
* @param text color
|
||||
*/
|
||||
* Themes
|
||||
* @param first color
|
||||
* @param second color
|
||||
* @param text color
|
||||
*/
|
||||
const themes = {
|
||||
theme1: [ 'rgba(0, 0, 0, 1)', 'rgba(204, 204, 204, 1)', 'rgba(255, 255, 255, 1)' ], // Monochrome (Default)
|
||||
theme1: ['rgba(32, 34, 40, 1)', 'rgba(88, 219, 171, 1)', 'rgba(255, 255, 255, 1)' ], // Retro (Default)
|
||||
theme2: [ 'rgba(31, 12, 12, 1)', 'rgba(255, 112, 112, 1)', 'rgba(255, 255, 255, 1)' ], // Red
|
||||
theme3: [ 'rgba(18, 28, 12, 1)', 'rgba(169, 255, 112, 1)', 'rgba(255, 255, 255, 1)' ], // Green
|
||||
theme4: [ 'rgba(12, 28, 27, 1)', 'rgba(104, 247, 238, 1)', 'rgba(255, 255, 255, 1)' ], // Cyan
|
||||
@@ -13,143 +15,154 @@
|
||||
theme6: [ 'rgba(33, 9, 29, 1)', 'rgba(237, 81, 211, 1)', 'rgba(255, 255, 255, 1)' ], // Pink
|
||||
theme7: [ 'rgba(13, 11, 26, 1)', 'rgba(128, 105, 250, 1)', 'rgba(255, 255, 255, 1)' ], // Blurple
|
||||
theme8: [ 'rgba(252, 186, 3, 1)', 'rgba(0, 0, 0, 1)', 'rgba(0, 0, 0, 1)' ], // Sunny
|
||||
theme9: ['rgba(32, 34, 40, 1)', 'rgba(88, 219, 171, 1)', 'rgba(255, 255, 255, 1)' ] // Retro
|
||||
};
|
||||
|
||||
// Signal Units
|
||||
const signalUnits = {
|
||||
dbf: ['dBf'],
|
||||
dbuv: ['dBµV'],
|
||||
dbm: ['dBm'],
|
||||
};
|
||||
|
||||
$(document).ready(() => {
|
||||
// Theme Selector
|
||||
const themeSelector = $('#theme-selector');
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
const savedUnit = localStorage.getItem('signalUnit');
|
||||
|
||||
if (savedTheme && themes[savedTheme]) {
|
||||
setTheme(savedTheme);
|
||||
themeSelector.find('input').val(themeSelector.find('.option[data-value="' + savedTheme + '"]').text());
|
||||
}
|
||||
|
||||
themeSelector.on('click', '.option', (event) => {
|
||||
const selectedTheme = $(event.target).data('value');
|
||||
setTheme(selectedTheme);
|
||||
themeSelector.find('input').val($(event.target).text()); // Set the text of the clicked option to the input
|
||||
localStorage.setItem('theme', selectedTheme);
|
||||
});
|
||||
|
||||
// Signal Selector
|
||||
const signalSelector = $('#signal-selector');
|
||||
|
||||
if (localStorage.getItem('signalUnit')) {
|
||||
signalSelector.find('input').val(signalSelector.find('.option[data-value="' + savedUnit + '"]').text());
|
||||
}
|
||||
|
||||
signalSelector.on('click', '.option', (event) => {
|
||||
const selectedSignalUnit = $(event.target).data('value');
|
||||
signalSelector.find('input').val($(event.target).text()); // Set the text of the clicked option to the input
|
||||
localStorage.setItem('signalUnit', selectedSignalUnit);
|
||||
});
|
||||
|
||||
$('#login-form').submit(function (event) {
|
||||
event.preventDefault();
|
||||
theme9: [ 'rgba(0, 0, 0, 1)', 'rgba(204, 204, 204, 1)', 'rgba(255, 255, 255, 1)' ], // AMOLED
|
||||
};
|
||||
|
||||
// Perform an AJAX request to the /login endpoint
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: './login',
|
||||
data: $(this).serialize(),
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Assuming you have an anchor tag with id 'logout-link'
|
||||
$('.logout-link').click(function (event) {
|
||||
event.preventDefault();
|
||||
// Signal Units
|
||||
const signalUnits = {
|
||||
dbf: ['dBf'],
|
||||
dbuv: ['dBµV'],
|
||||
dbm: ['dBm'],
|
||||
};
|
||||
|
||||
$(document).ready(() => {
|
||||
// Theme Selector
|
||||
const themeSelector = $('#theme-selector');
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
const savedUnit = localStorage.getItem('signalUnit');
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var extendedFreqRange = localStorage.getItem("extendedFreqRange");
|
||||
if (extendedFreqRange === "true") {
|
||||
$("#extended-frequency-range").prop("checked", true);
|
||||
}
|
||||
|
||||
// Save the value of the checkbox into local storage when its state changes
|
||||
$("#extended-frequency-range").change(function() {
|
||||
var isChecked = $(this).is(":checked");
|
||||
localStorage.setItem("extendedFreqRange", isChecked);
|
||||
});
|
||||
|
||||
var extendedFreqRange = localStorage.getItem("psUnderscores");
|
||||
if (extendedFreqRange === "true") {
|
||||
$("#ps-underscores").prop("checked", true);
|
||||
}
|
||||
|
||||
// Save the value of the checkbox into local storage when its state changes
|
||||
$("#ps-underscores").change(function() {
|
||||
var isChecked = $(this).is(":checked");
|
||||
localStorage.setItem("psUnderscores", isChecked);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
function setTheme(themeName) {
|
||||
const themeColors = themes[themeName];
|
||||
if (themeColors) {
|
||||
// Extracting the RGBA components and opacity value
|
||||
const rgbaComponents = themeColors[2].match(/(\d+(\.\d+)?)/g);
|
||||
const opacity = parseFloat(rgbaComponents[3]);
|
||||
// Calculating 80% of the opacity
|
||||
const newOpacity = opacity * 0.75;
|
||||
// Constructing the new RGBA string with the adjusted opacity
|
||||
const textColor2 = `rgba(${rgbaComponents[0]}, ${rgbaComponents[1]}, ${rgbaComponents[2]}, ${newOpacity})`;
|
||||
if (savedTheme && themes[savedTheme]) {
|
||||
setTheme(savedTheme);
|
||||
themeSelector.find('input').val(themeSelector.find('.option[data-value="' + savedTheme + '"]').text());
|
||||
}
|
||||
|
||||
$(':root').css('--color-main', themeColors[0]);
|
||||
$(':root').css('--color-main-bright', themeColors[1]);
|
||||
$(':root').css('--color-text', themeColors[2]);
|
||||
$(':root').css('--color-text-2', textColor2);
|
||||
}
|
||||
}
|
||||
themeSelector.on('click', '.option', (event) => {
|
||||
const selectedTheme = $(event.target).data('value');
|
||||
setTheme(selectedTheme);
|
||||
themeSelector.find('input').val($(event.target).text()); // Set the text of the clicked option to the input
|
||||
localStorage.setItem('theme', selectedTheme);
|
||||
});
|
||||
|
||||
// Signal Selector
|
||||
const signalSelector = $('#signal-selector');
|
||||
|
||||
if (localStorage.getItem('signalUnit')) {
|
||||
signalSelector.find('input').val(signalSelector.find('.option[data-value="' + savedUnit + '"]').text());
|
||||
}
|
||||
|
||||
signalSelector.on('click', '.option', (event) => {
|
||||
const selectedSignalUnit = $(event.target).data('value');
|
||||
signalSelector.find('input').val($(event.target).text()); // Set the text of the clicked option to the input
|
||||
localStorage.setItem('signalUnit', selectedSignalUnit);
|
||||
});
|
||||
|
||||
$('#login-form').submit(function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
// Perform an AJAX request to the /login endpoint
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: './login',
|
||||
data: $(this).serialize(),
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Assuming you have an anchor tag with id 'logout-link'
|
||||
$('.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);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var extendedFreqRange = localStorage.getItem("extendedFreqRange");
|
||||
if (extendedFreqRange === "true") {
|
||||
$("#extended-frequency-range").prop("checked", true);
|
||||
}
|
||||
|
||||
// Save the value of the checkbox into local storage when its state changes
|
||||
$("#extended-frequency-range").change(function() {
|
||||
var isChecked = $(this).is(":checked");
|
||||
localStorage.setItem("extendedFreqRange", isChecked);
|
||||
});
|
||||
|
||||
var extendedFreqRange = localStorage.getItem("psUnderscores");
|
||||
if (extendedFreqRange === "true") {
|
||||
$("#ps-underscores").prop("checked", true);
|
||||
}
|
||||
|
||||
var smoothSignal = localStorage.getItem("smoothSignal");
|
||||
if (smoothSignal === "true") {
|
||||
$("#smooth-signal").prop("checked", true);
|
||||
}
|
||||
|
||||
// Save the value of the checkbox into local storage when its state changes
|
||||
$("#ps-underscores").change(function() {
|
||||
var isChecked = $(this).is(":checked");
|
||||
localStorage.setItem("psUnderscores", isChecked);
|
||||
});
|
||||
|
||||
$("#smooth-signal").change(function() {
|
||||
var isChecked = $(this).is(":checked");
|
||||
localStorage.setItem("smoothSignal", isChecked);
|
||||
});
|
||||
|
||||
$('.version-string').text(currentVersion);
|
||||
});
|
||||
|
||||
|
||||
function setTheme(themeName) {
|
||||
const themeColors = themes[themeName];
|
||||
if (themeColors) {
|
||||
// Extracting the RGBA components and opacity value
|
||||
const rgbaComponents = themeColors[2].match(/(\d+(\.\d+)?)/g);
|
||||
const opacity = parseFloat(rgbaComponents[3]);
|
||||
// Calculating 80% of the opacity
|
||||
const newOpacity = opacity * 0.75;
|
||||
// Constructing the new RGBA string with the adjusted opacity
|
||||
const textColor2 = `rgba(${rgbaComponents[0]}, ${rgbaComponents[1]}, ${rgbaComponents[2]}, ${newOpacity})`;
|
||||
|
||||
$(':root').css('--color-main', themeColors[0]);
|
||||
$(':root').css('--color-main-bright', themeColors[1]);
|
||||
$(':root').css('--color-text', themeColors[2]);
|
||||
$(':root').css('--color-text-2', textColor2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
205
web/js/setup.js
205
web/js/setup.js
@@ -9,7 +9,12 @@ $(document).ready(function() {
|
||||
MapCreate();
|
||||
fetchData();
|
||||
|
||||
|
||||
setTimeout( function() {
|
||||
if ($('.nav li.active[data-panel="status"]').length > 0) {
|
||||
$('#submit-config').hide();
|
||||
}
|
||||
}, 50 )
|
||||
|
||||
map.on('click', function(ev) {
|
||||
$('#lat').val((ev.latlng.lat).toFixed(6));
|
||||
$('#lng').val((ev.latlng.lng).toFixed(6));
|
||||
@@ -25,7 +30,39 @@ $(document).ready(function() {
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$('#status').show();
|
||||
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);
|
||||
}
|
||||
|
||||
if(panelId == 'status') {
|
||||
$('#submit-config').hide();
|
||||
} else {
|
||||
$('#submit-config').show();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$('#login-form').submit(function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
@@ -105,7 +142,9 @@ $(document).ready(function() {
|
||||
});
|
||||
});
|
||||
|
||||
$("#console-output").scrollTop($("#console-output")[0].scrollHeight);
|
||||
if($("#console-output").length > 0) {
|
||||
$("#console-output").scrollTop($("#console-output")[0].scrollHeight);
|
||||
}
|
||||
});
|
||||
|
||||
function MapCreate() {
|
||||
@@ -126,149 +165,19 @@ function MapCreate() {
|
||||
}).addTo(map);
|
||||
}
|
||||
|
||||
function fetchData() {
|
||||
// Make a GET request to retrieve the data.json file
|
||||
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);
|
||||
$('#audio-port').val(data.webserver.audioPort);
|
||||
|
||||
$('#xdrd-ip').val(data.xdrd.xdrdIp);
|
||||
$('#xdrd-port').val(data.xdrd.xdrdPort);
|
||||
$('#xdrd-password').val(data.xdrd.xdrdPassword);
|
||||
|
||||
$('#audio-devices').val(data.audio.audioDevice);
|
||||
$('#audio-channels').val(data.audio.audioChannels);
|
||||
$('#audio-quality').val(data.audio.audioBitrate);
|
||||
|
||||
$('#webserver-name').val(data.identification.tunerName);
|
||||
$('#webserver-desc').val(data.identification.tunerDesc);
|
||||
$('#lat').val(data.identification.lat);
|
||||
$('#lng').val(data.identification.lon);
|
||||
$("#broadcast-tuner").prop("checked", data.identification.broadcastTuner);
|
||||
$("#broadcast-address").val(data.identification.proxyIp);
|
||||
|
||||
$('#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);
|
||||
|
||||
// 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));
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching data:', error.message);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function submitData() {
|
||||
const webserverIp = $('#webserver-ip').val() || '0.0.0.0';
|
||||
const webserverPort = $('#webserver-port').val() || '8080';
|
||||
const audioPort = $('#audio-port').val() || '8081';
|
||||
|
||||
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 tunerName = $('#webserver-name').val() || 'FM Tuner';
|
||||
const tunerDesc = $('#webserver-desc').val() || 'Default FM tuner description';
|
||||
const lat = $('#lat').val();
|
||||
const lon = $('#lng').val();
|
||||
const broadcastTuner = $("#broadcast-tuner").is(":checked");
|
||||
const proxyIp = $("#broadcast-address").val();
|
||||
|
||||
const tunePass = $('#tune-pass').val();
|
||||
const adminPass = $('#admin-pass').val();
|
||||
|
||||
const publicTuner = $("#tuner-public").is(":checked");
|
||||
const lockToAdmin = $("#tuner-lock").is(":checked");
|
||||
const autoShutdown = $("#shutdown-tuner").is(":checked");
|
||||
|
||||
const data = {
|
||||
webserver: {
|
||||
webserverIp,
|
||||
webserverPort,
|
||||
audioPort
|
||||
},
|
||||
xdrd: {
|
||||
xdrdIp,
|
||||
xdrdPort,
|
||||
xdrdPassword
|
||||
},
|
||||
audio: {
|
||||
audioDevice,
|
||||
audioChannels,
|
||||
audioBitrate,
|
||||
},
|
||||
identification: {
|
||||
tunerName,
|
||||
tunerDesc,
|
||||
lat,
|
||||
lon,
|
||||
broadcastTuner,
|
||||
proxyIp
|
||||
},
|
||||
password: {
|
||||
tunePass,
|
||||
adminPass,
|
||||
},
|
||||
publicTuner,
|
||||
lockToAdmin,
|
||||
autoShutdown
|
||||
};
|
||||
|
||||
|
||||
if(adminPass.length < 1) {
|
||||
alert('You need to fill in the admin password before continuing further.');
|
||||
return;
|
||||
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');
|
||||
}
|
||||
// Send data to the server using jQuery
|
||||
$.ajax({
|
||||
url: './saveData',
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(data),
|
||||
success: function (message) {
|
||||
alert(message);
|
||||
},
|
||||
error: function (error) {
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
62
web/js/wizard.js
Normal file
62
web/js/wizard.js
Normal file
@@ -0,0 +1,62 @@
|
||||
$(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();
|
||||
});
|
||||
});
|
||||
|
||||
// Function to update the progress bar buttons
|
||||
function updateProgressBar(currentStep) {
|
||||
var stepIndex = $('.step').index(currentStep) + 1;
|
||||
$('.btn-rounded-cube').removeClass('activated');
|
||||
$('.btn-rounded-cube:lt(' + stepIndex + ')').addClass('activated');
|
||||
}
|
||||
|
||||
function updateWizardContent() {
|
||||
if($('.step:visible').index() == 0) {
|
||||
$('.btn-prev').hide();
|
||||
} else {
|
||||
$('.btn-prev').show();
|
||||
}
|
||||
|
||||
if($('.step:visible').index() == 2) {
|
||||
setTimeout(function () {
|
||||
map.invalidateSize();
|
||||
}, 200);
|
||||
}
|
||||
|
||||
if($('.step:visible').index() == 3) {
|
||||
$('.btn-next').text('Save');
|
||||
} else {
|
||||
$('.btn-next').text('Next')
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user