1
0
mirror of https://github.com/KubaPro010/fm-dx-webserver.git synced 2026-02-27 06:23:53 +01:00

some changes

This commit is contained in:
2026-02-24 15:03:56 +01:00
parent 648ef00bed
commit 5d524eba56
15 changed files with 316 additions and 378 deletions

View File

@@ -193,8 +193,7 @@ function handleData(wss, receivedData, rdsWss) {
data += (((errors & 0x03) == 0) ? modifiedData.slice(12, 16) : '----'); data += (((errors & 0x03) == 0) ? modifiedData.slice(12, 16) : '----');
const newDataString = "G:\r\n" + data + "\r\n\r\n"; const newDataString = "G:\r\n" + data + "\r\n\r\n";
const finalBuffer = Buffer.from(newDataString, 'utf-8'); client.send(newDataString);
client.send(finalBuffer);
}); });
rdsdec.decodeGroup(parseInt(modifiedData.slice(0, 4), 16), parseInt(modifiedData.slice(4, 8), 16), parseInt(modifiedData.slice(8, 12), 16), parseInt(modifiedData.slice(12, 16), 16)); rdsdec.decodeGroup(parseInt(modifiedData.slice(0, 4), 16), parseInt(modifiedData.slice(4, 8), 16), parseInt(modifiedData.slice(8, 12), 16), parseInt(modifiedData.slice(12, 16), 16));

View File

@@ -13,14 +13,14 @@
<div class="panel-100 no-bg"> <div class="panel-100 no-bg">
<img class="top-10" src="./images/openradio_logo_neutral.png" height="64px"> <img class="top-10" src="./images/openradio_logo_neutral.png" height="64px">
<h2 class="text-monospace text-light text-center">[403]</h2> <h2 class="text-monospace text-light text-center">[403]</h2>
<div class="panel-100 p-10"> <div class="panel-100 p-10">
<br> <br>
<i class="text-big fa-solid fa-exclamation-triangle color-4"></i> <i class="text-big fa-solid fa-exclamation-triangle color-4"></i>
<p> <p>
There's a possibility you were kicked by the system.<br> There's a possibility you were kicked by the system.<br>
Please try again later.</p> Please try again later.</p>
</div> </div>
</div> </div>
</div> </div>
<script src="js/settings.js"></script> <script src="js/settings.js"></script>

View File

@@ -261,7 +261,7 @@
</span> </span>
<% if (bwSwitch) { %> <% if (bwSwitch) { %>
<%- include('_bwSwitch', { device: device, tunerProfiles: tunerProfiles, id: 'data-bw', cssClass: 'panel-50 dropdown-up m-0 w-150 m-left-15', cssClassOptions: 'open-top' }) %> <%- include('_bwSwitch', { device: device, tunerProfiles: tunerProfiles, id: 'data-bw', cssClass: 'panel-50 dropdown-up m-0 w-150 m-left-15', cssClassOptions: 'open-top' }) %>
<% } %> <% } %>
<% if (fmlist_integration == true && (fmlist_adminOnly == false || isTuneAuthenticated)) { %> <% if (fmlist_integration == true && (fmlist_adminOnly == false || isTuneAuthenticated)) { %>
<button class="tooltip bg-color-4 mini-popup log-fmlist" data-tooltip="<strong>LOG TO FMLIST</strong><br>Clicking this button logs the current station to FMLIST's visual logbook." aria-label="Log to FMLIST" style="width: 80px; height: 48px;margin-left: 15px !important;"> <button class="tooltip bg-color-4 mini-popup log-fmlist" data-tooltip="<strong>LOG TO FMLIST</strong><br>Clicking this button logs the current station to FMLIST's visual logbook." aria-label="Log to FMLIST" style="width: 80px; height: 48px;margin-left: 15px !important;">
<i class="fa-solid fa-flag fa-lg"></i> <i class="fa-solid fa-flag fa-lg"></i>
@@ -367,10 +367,10 @@
<div style="max-height: 48px;width: 50%;margin-right: 5px;"> <div style="max-height: 48px;width: 50%;margin-right: 5px;">
<%- include('_bwSwitch', { device: device, tunerProfiles: tunerProfiles, id: 'data-bw-phone', cssClass: 'panel-100-real', cssClassOptions: 'text-center open-bottom' }) %> <%- include('_bwSwitch', { device: device, tunerProfiles: tunerProfiles, id: 'data-bw-phone', cssClass: 'panel-100-real', cssClassOptions: 'text-center open-bottom' }) %>
</div> </div>
<% } %> <% } %>
</div> </div>
<p class="flex-phone flex-center">Filters</p> <p class="flex-phone flex-center">Filters</p>
<div class="flex-container flex-phone flex-center"> <div class="flex-container flex-phone flex-center">
<% if (device == 'tef') { %><button class="data-eq tooltip p-10 m-right-5" style="height: 48px" aria-label="EQ Filter" data-tooltip="<strong>The cEQ filter can reduce bandwidth below 56 kHz.</strong><br><br>Useful for weak stations next to strong ones,<br>although it may pick up more interference."><span class="text-bold">cEQ</span></button><% } %> <% if (device == 'tef') { %><button class="data-eq tooltip p-10 m-right-5" style="height: 48px" aria-label="EQ Filter" data-tooltip="<strong>The cEQ filter can reduce bandwidth below 56 kHz.</strong><br><br>Useful for weak stations next to strong ones,<br>although it may pick up more interference."><span class="text-bold">cEQ</span></button><% } %>
@@ -445,14 +445,14 @@
<div style="width: calc(50% - 32px);text-align: center;"> <div style="width: calc(50% - 32px);text-align: center;">
<button class="users-online-container" aria-label="Online users" style="display: inline-block;"><i class="fa-solid fa-user"></i> <span class="users-online"></span></button> <button class="users-online-container" aria-label="Online users" style="display: inline-block;"><i class="fa-solid fa-user"></i> <span class="users-online"></span></button>
<% if (chatEnabled) { %> <% if (chatEnabled) { %>
<button class="chatbutton m-10" aria-label="Chatbox" style="display: inline-block;"><i class="fa-solid fa-message"></i></button> <button class="chatbutton m-10" aria-label="Chatbox" style="display: inline-block;"><i class="fa-solid fa-message"></i></button>
<% } %> <% } %>
</div> </div>
<div style="width: 64px;text-align: center;"> <div style="width: 64px;text-align: center;">
</div> </div>
<div style="width: calc(50% - 32px);text-align: center;"> <div style="width: calc(50% - 32px);text-align: center;">
@@ -469,7 +469,7 @@
<h1 class="top-25">Settings</h1> <h1 class="top-25">Settings</h1>
<div class="panel-full flex-center no-bg m-0"> <div class="panel-full flex-center no-bg m-0">
<%- include('_components', { component: 'dropdown', id: 'theme-selector', inputId: 'theme-selector-input', label: 'Theme', cssClass: '', placeholder: 'Default', <%- include('_components', { component: 'dropdown', id: 'theme-selector', inputId: 'theme-selector-input', label: 'Theme', cssClass: '', placeholder: 'Default',
options: [ options: [
{ value: 'theme1', label: 'Mint' }, { value: 'theme1', label: 'Mint' },
{ value: 'theme2', label: 'Cappuccino' }, { value: 'theme2', label: 'Cappuccino' },
@@ -486,7 +486,7 @@
<% if (device !== 'sdr') { %> <% if (device !== 'sdr') { %>
<div class="panel-full flex-center no-bg m-0"> <div class="panel-full flex-center no-bg m-0">
<%- include('_components', { component: 'dropdown', id: 'signal-selector', inputId: 'signal-selector-input', label: 'Signal units', cssClass: '', placeholder: 'dBf', <%- include('_components', { component: 'dropdown', id: 'signal-selector', inputId: 'signal-selector-input', label: 'Signal units', cssClass: '', placeholder: 'dBf',
options: [ options: [
{ value: 'dbf', label: 'dBf' }, { value: 'dbf', label: 'dBf' },
{ value: 'dbuv', label: 'dBuV' }, { value: 'dbuv', label: 'dBuV' },

View File

@@ -27,11 +27,8 @@ function destroyStream() {
function OnConnectivityCallback(isConnected) { function OnConnectivityCallback(isConnected) {
console.log("Connectivity changed:", isConnected); console.log("Connectivity changed:", isConnected);
if (Stream) { if (Stream) Stream.Volume = $('#volumeSlider').val();
Stream.Volume = $('#volumeSlider').val(); else console.warn("Stream is not initialized.");
} else {
console.warn("Stream is not initialized.");
}
} }
@@ -44,18 +41,14 @@ function OnPlayButtonClick(_ev) {
shouldReconnect = false; shouldReconnect = false;
destroyStream(); destroyStream();
$playbutton.find('.fa-solid').toggleClass('fa-stop fa-play'); $playbutton.find('.fa-solid').toggleClass('fa-stop fa-play');
if (isAppleiOS && 'audioSession' in navigator) { if (isAppleiOS && 'audioSession' in navigator) navigator.audioSession.type = "none";
navigator.audioSession.type = "none";
}
} else { } else {
console.log("Starting stream..."); console.log("Starting stream...");
shouldReconnect = true; shouldReconnect = true;
createStream(); createStream();
Stream.Start(); Stream.Start();
$playbutton.find('.fa-solid').toggleClass('fa-play fa-stop'); $playbutton.find('.fa-solid').toggleClass('fa-play fa-stop');
if (isAppleiOS && 'audioSession' in navigator) { if (isAppleiOS && 'audioSession' in navigator) navigator.audioSession.type = "playback";
navigator.audioSession.type = "playback";
}
} }
$playbutton.addClass('bg-gray').prop('disabled', true); $playbutton.addClass('bg-gray').prop('disabled', true);
@@ -70,9 +63,7 @@ function updateVolume() {
newVolumeGlobal = newVolume; newVolumeGlobal = newVolume;
console.log("Volume updated to:", newVolume); console.log("Volume updated to:", newVolume);
Stream.Volume = newVolume; Stream.Volume = newVolume;
} else { } else console.warn("Stream is not initialized.");
console.warn("Stream is not initialized.");
}
} }
$(document).ready(Init); $(document).ready(Init);

View File

@@ -3,18 +3,13 @@ function tuneUp() {
if (socket.readyState === WebSocket.OPEN) { if (socket.readyState === WebSocket.OPEN) {
getCurrentFreq(); getCurrentFreq();
let addVal = 0; let addVal = 0;
if (currentFreq < 0.52) { if (currentFreq < 0.52) addVal = 9 - (Math.round(currentFreq*1000) % 9);
addVal = 9 - (Math.round(currentFreq*1000) % 9); else if (currentFreq < 1.71) {
} else if (currentFreq < 1.71) {
// TODO: Rework to replace 9 with 9 or 10 based on regionalisation setting // TODO: Rework to replace 9 with 9 or 10 based on regionalisation setting
addVal = 9 - (Math.round(currentFreq*1000) % 9); addVal = 9 - (Math.round(currentFreq*1000) % 9);
} else if (currentFreq < 29.6) { } else if (currentFreq < 29.6) addVal = 5 - (Math.round(currentFreq*1000) % 5);
addVal = 5 - (Math.round(currentFreq*1000) % 5); else if (currentFreq >= 65.9 && currentFreq < 74) addVal = 30 - ((Math.round(currentFreq*1000) - 65900) % 30);
} else if (currentFreq >= 65.9 && currentFreq < 74) { else addVal = 100 - (Math.round(currentFreq*1000) % 100);
addVal = 30 - ((Math.round(currentFreq*1000) - 65900) % 30);
} else {
addVal = 100 - (Math.round(currentFreq*1000) % 100);
}
socket.send("T" + (Math.round(currentFreq*1000) + addVal)); socket.send("T" + (Math.round(currentFreq*1000) + addVal));
} }
} }
@@ -23,18 +18,13 @@ function tuneDown() {
if (socket.readyState === WebSocket.OPEN) { if (socket.readyState === WebSocket.OPEN) {
getCurrentFreq(); getCurrentFreq();
let subVal = 0; let subVal = 0;
if (currentFreq < 0.52) { 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 (Americans use 10, because of dumbfuckinstan)
subVal = (Math.round(currentFreq*1000) % 9 == 0) ? 9 : (Math.round(currentFreq*1000) % 9); subVal = (Math.round(currentFreq*1000) % 9 == 0) ? 9 : (Math.round(currentFreq*1000) % 9);
} else if (currentFreq < 1.71) { } else if (currentFreq < 29.6) subVal = (Math.round(currentFreq*1000) % 5 == 0) ? 5 : (Math.round(currentFreq*1000) % 5);
// TODO: Rework to replace 9 with 9 or 10 based on regionalisation setting else if (currentFreq > 65.9 && currentFreq <= 74) subVal = ((Math.round(currentFreq*1000) - 65900) % 30 == 0) ? 30 : ((Math.round(currentFreq*1000) - 65900) % 30);
subVal = (Math.round(currentFreq*1000) % 9 == 0) ? 9 : (Math.round(currentFreq*1000) % 9); else subVal = (Math.round(currentFreq*1000) % 100 == 0) ? 100 : (Math.round(currentFreq*1000) % 100);
} 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)); socket.send("T" + (Math.round(currentFreq*1000) - subVal));
} }
} }
@@ -52,6 +42,6 @@ function getCurrentFreq() {
currentFreq = $('#data-frequency').text(); currentFreq = $('#data-frequency').text();
currentFreq = parseFloat(currentFreq).toFixed(3); currentFreq = parseFloat(currentFreq).toFixed(3);
currentFreq = parseFloat(currentFreq); currentFreq = parseFloat(currentFreq);
return currentFreq; return currentFreq;
} }

View File

@@ -9,42 +9,40 @@ $(document).ready(function() {
const chatIdentityNickname = $('#chat-identity-nickname'); const chatIdentityNickname = $('#chat-identity-nickname');
const chatNicknameInput = $('#chat-nickname'); const chatNicknameInput = $('#chat-nickname');
const chatNicknameSave = $('#chat-nickname-save'); const chatNicknameSave = $('#chat-nickname-save');
$(".chatbutton").on("click", function () { $(".chatbutton").on("click", function () {
togglePopup("#popup-panel-chat"); togglePopup("#popup-panel-chat");
chatMessages.scrollTop(chatMessages[0].scrollHeight); chatMessages.scrollTop(chatMessages[0].scrollHeight);
}); });
// Function to generate a random string // Function to generate a random string
function generateRandomString(length) { function generateRandomString(length) {
const characters = 'ABCDEFGHJKMNOPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz0123456789'; const characters = 'ABCDEFGHJKMNOPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz0123456789';
let result = ''; let result = '';
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) result += characters.charAt(Math.floor(Math.random() * characters.length));
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result; return result;
} }
// Load nickname from localStorage on page load // Load nickname from localStorage on page load
let savedNickname = localStorage.getItem('nickname') || `User ${generateRandomString(5)}`; let savedNickname = localStorage.getItem('nickname') || `User ${generateRandomString(5)}`;
chatNicknameInput.val(savedNickname); chatNicknameInput.val(savedNickname);
chatIdentityNickname.text(savedNickname); chatIdentityNickname.text(savedNickname);
chatSocket.onmessage = function(event) { chatSocket.onmessage = function(event) {
const messageData = JSON.parse(event.data); const messageData = JSON.parse(event.data);
const isAdmin = messageData.admin ? '<span style="color: #bada55">[ADMIN]</span>' : ''; const isAdmin = messageData.admin ? '<span style="color: #bada55">[ADMIN]</span>' : '';
if (messageData.type === 'clientIp') { if (messageData.type === 'clientIp') {
chatIdentityNickname.html(isAdmin).append(document.createTextNode(" " + savedNickname)); chatIdentityNickname.html(isAdmin).append(document.createTextNode(" " + savedNickname));
chatIdentityNickname.attr('title', messageData.ip); chatIdentityNickname.attr('title', messageData.ip);
} else { } else {
const chatMessage = ` const chatMessage = `
<span class="color-2">[${messageData.time}]</span> <span class="color-2">[${messageData.time}]</span>
${isAdmin} <strong class="color-5" title="${typeof messageData.ip !== "undefined" ? 'IP Address: ' + messageData.ip : ''}">${messageData.nickname}</strong>: ${isAdmin} <strong class="color-5" title="${typeof messageData.ip !== "undefined" ? 'IP Address: ' + messageData.ip : ''}">${messageData.nickname}</strong>:
<span style="color: var(--color-text-2);">${$('<div/>').text(messageData.message).html()}</span><br> <span style="color: var(--color-text-2);">${$('<div/>').text(messageData.message).html()}</span><br>
`; `;
chatMessages.append(chatMessage); chatMessages.append(chatMessage);
if (chatMessages.is(':visible')) { if (chatMessages.is(':visible')) {
setTimeout(function() { setTimeout(function() {
chatMessages.scrollTop(chatMessages[0].scrollHeight); chatMessages.scrollTop(chatMessages[0].scrollHeight);
@@ -59,7 +57,7 @@ $(document).ready(function() {
} }
} }
}; };
$('.chat-send-message-btn').click(sendMessage); $('.chat-send-message-btn').click(sendMessage);
chatNicknameSave.click(function() { chatNicknameSave.click(function() {
const currentNickname = chatNicknameInput.val().trim() || `Anonymous User ${generateRandomString(5)}`; const currentNickname = chatNicknameInput.val().trim() || `Anonymous User ${generateRandomString(5)}`;
@@ -68,34 +66,32 @@ $(document).ready(function() {
chatIdentityNickname.text(savedNickname); chatIdentityNickname.text(savedNickname);
chatNicknameInput.blur(); chatNicknameInput.blur();
}); });
chatButton.click(function() { chatButton.click(function() {
chatMessageCount = 0; chatMessageCount = 0;
chatMessagesCount.text(chatMessageCount); chatMessagesCount.text(chatMessageCount);
chatButton.removeClass('blink').addClass('bg-color-1'); chatButton.removeClass('blink').addClass('bg-color-1');
chatSendInput.focus(); chatSendInput.focus();
setTimeout(function() { setTimeout(function() {
chatMessages.scrollTop(chatMessages[0].scrollHeight); chatMessages.scrollTop(chatMessages[0].scrollHeight);
}, 100); }, 100);
}); });
chatNicknameInput.keypress(function(event) { chatNicknameInput.keypress(function(event) {
if (event.which === 13) { if (event.which === 13) {
chatNicknameSave.trigger('click'); chatNicknameSave.trigger('click');
} }
}); });
chatSendInput.keypress(function(event) { chatSendInput.keypress(function(event) {
if (event.which === 13) { if (event.which === 13) sendMessage();
sendMessage();
}
}); });
function sendMessage() { function sendMessage() {
const nickname = savedNickname || `Anonymous User ${generateRandomString(5)}`; const nickname = savedNickname || `Anonymous User ${generateRandomString(5)}`;
const message = chatSendInput.val().trim(); const message = chatSendInput.val().trim();
if (message) { if (message) {
const messageData = { nickname, message }; const messageData = { nickname, message };
chatSocket.send(JSON.stringify(messageData)); chatSocket.send(JSON.stringify(messageData));

View File

@@ -28,7 +28,7 @@ function submitConfig() {
function fetchConfig() { function fetchConfig() {
$.getJSON("./getData") $.getJSON("./getData")
.done(data => { .done(data => {
configData = data; configData = data;
populateFields(configData); populateFields(configData);
initVolumeSlider(); initVolumeSlider();
initConnectionToggle(); initConnectionToggle();
@@ -38,9 +38,7 @@ function fetchConfig() {
function populateFields(data, prefix = "") { function populateFields(data, prefix = "") {
$.each(data, (key, value) => { $.each(data, (key, value) => {
if (value === null) { if (value === null) value = ""; // Convert null to an empty string
value = ""; // Convert null to an empty string
}
let id = `${prefix}${prefix ? "-" : ""}${key}`; let id = `${prefix}${prefix ? "-" : ""}${key}`;
const $element = $(`#${id}`); const $element = $(`#${id}`);
@@ -50,16 +48,13 @@ function populateFields(data, prefix = "") {
$element.find('option').each(function() { $element.find('option').each(function() {
const $option = $(this); const $option = $(this);
const dataName = $option.data('name'); const dataName = $option.data('name');
if (value.includes(dataName)) { if (value.includes(dataName)) $option.prop('selected', true);
$option.prop('selected', true); else $option.prop('selected', false);
} else {
$option.prop('selected', false);
}
}); });
$element.trigger('change'); $element.trigger('change');
} }
return; return;
} }
if (typeof value === "object" && value !== null) { if (typeof value === "object" && value !== null) {
@@ -68,11 +63,8 @@ function populateFields(data, prefix = "") {
const arrayId = `${id}-${index + 1}`; const arrayId = `${id}-${index + 1}`;
const $arrayElement = $(`#${arrayId}`); const $arrayElement = $(`#${arrayId}`);
if ($arrayElement.length) { if ($arrayElement.length) $arrayElement.val(item);
$arrayElement.val(item); else console.log(`Element with id ${arrayId} not found`);
} else {
console.log(`Element with id ${arrayId} not found`);
}
}); });
return; return;
} else { } else {
@@ -92,9 +84,7 @@ function populateFields(data, prefix = "") {
const $dropdownOption = $element.siblings('ul.options').find(`li[data-value="${value}"]`); const $dropdownOption = $element.siblings('ul.options').find(`li[data-value="${value}"]`);
$element.val($dropdownOption.length ? $dropdownOption.text() : value); $element.val($dropdownOption.length ? $dropdownOption.text() : value);
$element.attr('data-value', value); $element.attr('data-value', value);
} else { } else $element.val(value);
$element.val(value);
}
}); });
} }
@@ -111,9 +101,7 @@ function updateConfigData(data, prefix = "") {
if ($presetElement.length) { if ($presetElement.length) {
data[key].push($presetElement.val() || null); // Allow null if necessary data[key].push($presetElement.val() || null); // Allow null if necessary
index++; index++;
} else { } else break;
break;
}
} }
return; return;
} }
@@ -123,16 +111,12 @@ function updateConfigData(data, prefix = "") {
const $selectedOptions = $element.find('option:selected'); const $selectedOptions = $element.find('option:selected');
$selectedOptions.each(function() { $selectedOptions.each(function() {
const dataName = $(this).attr('data-name'); const dataName = $(this).attr('data-name');
if (dataName) { if (dataName) data[key].push(dataName);
data[key].push(dataName);
}
}); });
return; return;
} }
if (typeof value === "object" && value !== null && !Array.isArray(value)) { if (typeof value === "object" && value !== null && !Array.isArray(value)) return updateConfigData(value, id);
return updateConfigData(value, id);
}
if ($element.length) { if ($element.length) {
const newValue = $element.attr("data-value") ?? $element.val() ?? null; const newValue = $element.attr("data-value") ?? $element.val() ?? null;

View File

@@ -23,38 +23,38 @@ $(document).ready(function() {
switch($currentDropdown.attr('id')) { switch($currentDropdown.attr('id')) {
case 'data-ant': case 'data-ant':
socket.send("Z" + $(event.currentTarget).attr('data-value')); socket.send("Z" + $(event.currentTarget).attr('data-value'));
resetRDS(getCurrentFreq()); // Reset RDS when change antenna input resetRDS(getCurrentFreq()); // Reset RDS when change antenna input
break; break;
case 'data-ant-phone': case 'data-ant-phone':
socket.send("Z" + $(event.currentTarget).attr('data-value')); socket.send("Z" + $(event.currentTarget).attr('data-value'));
resetRDS(getCurrentFreq()); // Reset RDS when change antenna input resetRDS(getCurrentFreq()); // Reset RDS when change antenna input
break; break;
case 'data-bw': case 'data-bw':
legacyBwValue = $(event.currentTarget).attr('data-value2') || ""; legacyBwValue = $(event.currentTarget).attr('data-value2') || "";
socket.send("F" + legacyBwValue); socket.send("F" + legacyBwValue);
socket.send("W" + $(event.currentTarget).attr('data-value')); socket.send("W" + $(event.currentTarget).attr('data-value'));
$currentDropdown.find('input').val($(event.currentTarget).text()); $currentDropdown.find('input').val($(event.currentTarget).text());
break; break;
case 'data-bw-phone': case 'data-bw-phone':
legacyBwValue = $(event.currentTarget).attr('data-value2') || ""; legacyBwValue = $(event.currentTarget).attr('data-value2') || "";
socket.send("F" + legacyBwValue); socket.send("F" + legacyBwValue);
socket.send("W" + $(event.currentTarget).attr('data-value')); socket.send("W" + $(event.currentTarget).attr('data-value'));
$currentDropdown.find('input').val($(event.currentTarget).text()); $currentDropdown.find('input').val($(event.currentTarget).text());
break; break;
case 'data-agc': case 'data-agc':
socket.send("A" + $(event.currentTarget).attr('data-value')); socket.send("A" + $(event.currentTarget).attr('data-value'));
$currentDropdown.find('input').val($(event.currentTarget).text()); $currentDropdown.find('input').val($(event.currentTarget).text());
break; break;
case 'data-agc-phone': case 'data-agc-phone':
socket.send("A" + $(event.currentTarget).attr('data-value')); socket.send("A" + $(event.currentTarget).attr('data-value'));
$currentDropdown.find('input').val($(event.currentTarget).text()); $currentDropdown.find('input').val($(event.currentTarget).text());
break; break;
default: default:
$currentDropdown.find('input') $currentDropdown.find('input')
.val($(event.currentTarget).text()) .val($(event.currentTarget).text())
.attr('data-value', $(event.currentTarget).data('value')); .attr('data-value', $(event.currentTarget).data('value'));
break; break;
} }
// Use setTimeout to delay class removal // Use setTimeout to delay class removal
@@ -80,24 +80,24 @@ $(document).ready(function() {
const $options = currentDropdown.find('.option'); const $options = currentDropdown.find('.option');
switch (event.key) { switch (event.key) {
case 'ArrowDown': case 'ArrowDown':
event.preventDefault(); event.preventDefault();
currentIndex = (currentIndex + 1) % $options.length; currentIndex = (currentIndex + 1) % $options.length;
$options.eq(currentIndex).focus(); $options.eq(currentIndex).focus();
break; break;
case 'ArrowUp': case 'ArrowUp':
event.preventDefault(); event.preventDefault();
currentIndex = (currentIndex - 1 + $options.length) % $options.length; currentIndex = (currentIndex - 1 + $options.length) % $options.length;
$options.eq(currentIndex).focus(); $options.eq(currentIndex).focus();
break; break;
case 'Enter': case 'Enter':
event.preventDefault(); event.preventDefault();
$options.eq(currentIndex).click(); $options.eq(currentIndex).click();
break; break;
case 'Escape': case 'Escape':
currentDropdown.removeClass('opened'); currentDropdown.removeClass('opened');
currentDropdown = null; currentDropdown = null;
currentIndex = -1; currentIndex = -1;
break; break;
} }
}; };
@@ -106,9 +106,7 @@ $(document).ready(function() {
$listOfOptions.on('click', selectOption); $listOfOptions.on('click', selectOption);
$dropdowns.on('click', 'input', toggleDropdown); $dropdowns.on('click', 'input', toggleDropdown);
$dropdowns.on('keydown', 'input', function(event) { $dropdowns.on('keydown', 'input', function(event) {
if (event.key === 'Enter') { if (event.key === 'Enter') toggleDropdown(event);
toggleDropdown(event);
}
}); });
$dropdowns.on('keydown', '.option', navigateOptions); $dropdowns.on('keydown', '.option', navigateOptions);

View File

@@ -25,23 +25,23 @@ const europe_programmes = [
const usa_programmes = [ const usa_programmes = [
"No PTY", "News", "Information", "Sports", "Talk", "Rock", "Classic Rock", "No PTY", "News", "Information", "Sports", "Talk", "Rock", "Classic Rock",
"Adults Hits", "Soft Rock", "Top 40", "Country", "Oldies", "Soft Music", "Adults Hits", "Soft Rock", "Top 40", "Country", "Oldies", "Soft Music",
"Nostalgia", "Jazz", "Classical", "Rhythm and Blues", "Soft Rhythm and Blues", "Nostalgia", "Jazz", "Classical", "Rhythm and Blues", "Soft Rhythm and Blues",
"Language", "Religious Music", "Religious Talk", "Personality", "Public", "College", "Language", "Religious Music", "Religious Talk", "Personality", "Public", "College",
"Spanish Talk", "Spanish Music", "Hip Hop", "", "", "Weather", "Emergency Test", "Emergency" "Spanish Talk", "Spanish Music", "Hip Hop", "", "", "Weather", "Emergency Test", "Emergency"
]; ];
const rdsMode = localStorage.getItem('rdsMode'); const rdsMode = localStorage.getItem('rdsMode');
$(document).ready(function () { $(document).ready(function () {
const signalToggle = $("#signal-units-toggle"); const signalToggle = $("#signal-units-toggle");
var $panel = $('.admin-quick-dashboard'); var $panel = $('.admin-quick-dashboard');
var panelWidth = $panel.outerWidth(); var panelWidth = $panel.outerWidth();
$(document).mousemove(function(e) { $(document).mousemove(function(e) {
var mouseX = e.pageX; var mouseX = e.pageX;
var panelLeft = parseInt($panel.css('left')); var panelLeft = parseInt($panel.css('left'));
if (mouseX <= 10 || (panelLeft === 4 && mouseX <= 100)) { if (mouseX <= 10 || (panelLeft === 4 && mouseX <= 100)) {
$panel.css('left', '4px'); $panel.css('left', '4px');
} else { } else {
@@ -50,10 +50,10 @@ $(document).ready(function () {
}); });
fillPresets(); fillPresets();
signalToggle.on("change", function () { signalToggle.on("change", function () {
const signalText = localStorage.getItem('signalUnit'); const signalText = localStorage.getItem('signalUnit');
if (signalText == 'dbuv') { if (signalText == 'dbuv') {
signalText.text('dBµV'); signalText.text('dBµV');
} else if (signalText == 'dbf') { } else if (signalText == 'dbf') {
@@ -62,7 +62,7 @@ $(document).ready(function () {
signalText.text('dBm'); signalText.text('dBm');
} }
}); });
// Check if device is an iPhone to prevent zoom on button press // Check if device is an iPhone to prevent zoom on button press
if (/iPhone|iPod|iPad/.test(navigator.userAgent) && !window.MSStream) { if (/iPhone|iPod|iPad/.test(navigator.userAgent) && !window.MSStream) {
// Handle touchstart for buttons to prevent zoom // Handle touchstart for buttons to prevent zoom
@@ -89,9 +89,9 @@ $(document).ready(function () {
$viewportMeta.attr('content', content); $viewportMeta.attr('content', content);
} }
} }
const textInput = $('#commandinput'); const textInput = $('#commandinput');
textInput.on('change blur', function (event) { textInput.on('change blur', function (event) {
const inputValue = Number(textInput.val()); const inputValue = Number(textInput.val());
// Check if the user agent contains 'iPhone' // Check if the user agent contains 'iPhone'
@@ -101,18 +101,18 @@ $(document).ready(function () {
textInput.val(''); textInput.val('');
} }
}); });
textInput.on('keyup', function (event) { textInput.on('keyup', function (event) {
if (event.key !== 'Backspace' && localStorage.getItem('extendedFreqRange') != "true") { if (event.key !== 'Backspace' && localStorage.getItem('extendedFreqRange') != "true") {
let inputValue = textInput.val(); let inputValue = textInput.val();
inputValue = inputValue.replace(/[^0-9.]/g, ''); inputValue = inputValue.replace(/[^0-9.]/g, '');
if (inputValue.includes("..")) { if (inputValue.includes("..")) {
inputValue = inputValue.slice(0, inputValue.lastIndexOf('.')) + inputValue.slice(inputValue.lastIndexOf('.') + 1); inputValue = inputValue.slice(0, inputValue.lastIndexOf('.')) + inputValue.slice(inputValue.lastIndexOf('.') + 1);
textInput.val(inputValue); textInput.val(inputValue);
} }
if (!inputValue.includes(".")) { if (!inputValue.includes(".")) {
if (inputValue.startsWith('10') && inputValue.length > 2) { if (inputValue.startsWith('10') && inputValue.length > 2) {
inputValue = inputValue.slice(0, 3) + '.' + inputValue.slice(3); inputValue = inputValue.slice(0, 3) + '.' + inputValue.slice(3);
@@ -130,31 +130,31 @@ $(document).ready(function () {
textInput.val(''); textInput.val('');
} }
}); });
document.onkeydown = function(event) { document.onkeydown = function(event) {
if (!event.repeat) { if (!event.repeat) {
checkKey(event); checkKey(event);
} }
}; };
let lastExecutionTime = 0; let lastExecutionTime = 0;
const throttleDelay = 100; // Time in ms const throttleDelay = 100; // Time in ms
$('#freq-container').on('wheel keypress', function (e) { $('#freq-container').on('wheel keypress', function (e) {
e.preventDefault(); e.preventDefault();
const now = Date.now(); const now = Date.now();
if (now - lastExecutionTime < throttleDelay) { if (now - lastExecutionTime < throttleDelay) {
// Ignore this event as it's within the throttle delay // Ignore this event as it's within the throttle delay
return; return;
} }
lastExecutionTime = now; // Update the last execution time lastExecutionTime = now; // Update the last execution time
getCurrentFreq(); getCurrentFreq();
var delta = e.originalEvent.deltaY; var delta = e.originalEvent.deltaY;
var adjustment = 0; var adjustment = 0;
if (e.shiftKey) { if (e.shiftKey) {
adjustment = e.altKey ? 1 : 0.01; adjustment = e.altKey ? 1 : 0.01;
} else if (e.ctrlKey) { } else if (e.ctrlKey) {
@@ -167,21 +167,21 @@ $(document).ready(function () {
} }
return false; return false;
} }
var newFreq = currentFreq + (delta > 0 ? -adjustment : adjustment); var newFreq = currentFreq + (delta > 0 ? -adjustment : adjustment);
socket.send("T" + (Math.round(newFreq * 1000))); socket.send("T" + (Math.round(newFreq * 1000)));
return false; return false;
}); });
setInterval(getServerTime, 10000); setInterval(getServerTime, 10000);
getServerTime(); getServerTime();
setInterval(sendPingRequest, 5000); setInterval(sendPingRequest, 5000);
sendPingRequest(); sendPingRequest();
$("#tuner-name").click(function() { $("#tuner-name").click(function() {
showTunerDescription(); showTunerDescription();
}); });
var freqUpButton = $('#freq-up')[0]; var freqUpButton = $('#freq-up')[0];
var freqDownButton = $('#freq-down')[0]; var freqDownButton = $('#freq-down')[0];
var psContainer = $('#ps-container')[0]; var psContainer = $('#ps-container')[0];
@@ -189,19 +189,19 @@ $(document).ready(function () {
var piCodeContainer = $('#pi-code-container')[0]; var piCodeContainer = $('#pi-code-container')[0];
var freqContainer = $('#freq-container')[0]; var freqContainer = $('#freq-container')[0];
var txContainer = $('#data-station-container')[0]; var txContainer = $('#data-station-container')[0];
$(".data-eq").click(function () { $(".data-eq").click(function () {
toggleButtonState("eq"); toggleButtonState("eq");
}); });
$(".data-ims").click(function () { $(".data-ims").click(function () {
toggleButtonState("ims"); toggleButtonState("ims");
}); });
$("#volumeSlider").on('mouseup', function() { $("#volumeSlider").on('mouseup', function() {
$('#volumeSlider').blur(); $('#volumeSlider').blur();
}) })
$(freqUpButton).on("click", tuneUp); $(freqUpButton).on("click", tuneUp);
$(freqDownButton).on("click", tuneDown); $(freqDownButton).on("click", tuneDown);
$(psContainer).on("click", copyPs); $(psContainer).on("click", copyPs);
@@ -212,37 +212,37 @@ $(document).ready(function () {
$(freqContainer).on("click", function () { $(freqContainer).on("click", function () {
textInput.focus(); textInput.focus();
}); });
//FMLIST logging //FMLIST logging
$('.popup-content').on('click', function(event) { $('.popup-content').on('click', function(event) {
event.stopPropagation(); event.stopPropagation();
$('.popup-content').removeClass('show'); $('.popup-content').removeClass('show');
}); });
$('.log-fmlist').on('click', function() { $('.log-fmlist').on('click', function() {
const logKey = 'fmlistLogChoice'; const logKey = 'fmlistLogChoice';
const logTimestampKey = 'fmlistLogTimestamp'; const logTimestampKey = 'fmlistLogTimestamp';
const expirationTime = 10 * 60 * 1000; const expirationTime = 10 * 60 * 1000;
const now = Date.now(); const now = Date.now();
const storedChoice = localStorage.getItem(logKey); const storedChoice = localStorage.getItem(logKey);
const storedTimestamp = localStorage.getItem(logTimestampKey); const storedTimestamp = localStorage.getItem(logTimestampKey);
if (storedChoice && storedTimestamp && (now - storedTimestamp < expirationTime)) { if (storedChoice && storedTimestamp && (now - storedTimestamp < expirationTime)) {
sendLog(storedChoice); sendLog(storedChoice);
return; return;
} }
if (parsedData.txInfo.dist > 700) { if (parsedData.txInfo.dist > 700) {
$('.log-fmlist .mini-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(logKey, './log_fmlist?type=sporadice');
localStorage.setItem(logTimestampKey, now); localStorage.setItem(logTimestampKey, now);
if(parsedData.txInfo.dist > 700) sendLog('./log_fmlist?type=sporadice'); if(parsedData.txInfo.dist > 700) sendLog('./log_fmlist?type=sporadice');
$('.log-fmlist .mini-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(logKey, './log_fmlist?type=tropo');
localStorage.setItem(logTimestampKey, now); localStorage.setItem(logTimestampKey, now);
@@ -250,9 +250,9 @@ $(document).ready(function () {
$('.log-fmlist .mini-popup-content').removeClass('show'); $('.log-fmlist .mini-popup-content').removeClass('show');
}); });
} else { } else {
sendLog('./log_fmlist'); sendLog('./log_fmlist');
} }
function sendLog(endpoint) { function sendLog(endpoint) {
$.ajax({ $.ajax({
url: endpoint, url: endpoint,
@@ -262,7 +262,7 @@ $(document).ready(function () {
}, },
error: function(xhr) { error: function(xhr) {
let errorMessage; let errorMessage;
switch (xhr.status) { switch (xhr.status) {
case 429: case 429:
errorMessage = xhr.responseText; errorMessage = xhr.responseText;
@@ -273,7 +273,7 @@ $(document).ready(function () {
default: default:
errorMessage = xhr.statusText || 'An error occurred'; errorMessage = xhr.statusText || 'An error occurred';
} }
sendToast('error', 'Log failed', errorMessage, false, true); sendToast('error', 'Log failed', errorMessage, false, true);
} }
}); });
@@ -290,7 +290,7 @@ function getServerTime() {
dataType: "json", dataType: "json",
success: function(data) { success: function(data) {
const serverTimeUtc = data.serverTime; const serverTimeUtc = data.serverTime;
const options = { const options = {
year: 'numeric', year: 'numeric',
month: 'short', month: 'short',
@@ -299,32 +299,32 @@ function getServerTime() {
minute: '2-digit', minute: '2-digit',
hour12: false hour12: false
}; };
const serverOptions = { const serverOptions = {
...options, ...options,
timeZone: 'Etc/UTC' timeZone: 'Etc/UTC'
}; };
const formattedServerTime = new Date(serverTimeUtc).toLocaleString(navigator.language ? navigator.language : 'en-US', serverOptions); const formattedServerTime = new Date(serverTimeUtc).toLocaleString(navigator.language ? navigator.language : 'en-US', serverOptions);
$("#server-time").text(formattedServerTime); $("#server-time").text(formattedServerTime);
}, },
error: function(jqXHR, textStatus, errorThrown) { error: function(jqXHR, textStatus, errorThrown) {
console.error("Error fetching server time:", errorThrown); console.error("Error fetching server time:", errorThrown);
} }
}); });
} }
function sendPingRequest() { function sendPingRequest() {
const timeoutDuration = 5000; const timeoutDuration = 5000;
const startTime = new Date().getTime(); const startTime = new Date().getTime();
const fetchWithTimeout = (url, options, timeout = timeoutDuration) => { const fetchWithTimeout = (url, options, timeout = timeoutDuration) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const timerTimeout = setTimeout(() => { const timerTimeout = setTimeout(() => {
reject(new Error('Request timed out')); reject(new Error('Request timed out'));
}, timeout); }, timeout);
fetch(url, options) fetch(url, options)
.then(response => { .then(response => {
clearTimeout(timerTimeout); clearTimeout(timerTimeout);
@@ -336,7 +336,7 @@ function sendPingRequest() {
}); });
}); });
}; };
fetchWithTimeout('./ping', { cache: 'no-store' }, timeoutDuration) fetchWithTimeout('./ping', { cache: 'no-store' }, timeoutDuration)
.then(response => { .then(response => {
const endTime = new Date().getTime(); const endTime = new Date().getTime();
@@ -354,7 +354,7 @@ function sendPingRequest() {
pingTimeLimit = true; pingTimeLimit = true;
} }
}); });
function handleMessage(message) { function handleMessage(message) {
messageData = JSON.parse(message.data.length); messageData = JSON.parse(message.data.length);
socket.removeEventListener('message', handleMessage); socket.removeEventListener('message', handleMessage);
@@ -362,7 +362,7 @@ function sendPingRequest() {
socket.addEventListener('message', handleMessage); socket.addEventListener('message', handleMessage);
messageLength = messageData; messageLength = messageData;
messageData = 0; messageData = 0;
// Force reconnection if no WebSocket data after several queries // Force reconnection if no WebSocket data after several queries
if (messageLength === 0) { if (messageLength === 0) {
messageCounter++; messageCounter++;
@@ -375,7 +375,7 @@ function sendPingRequest() {
} else { } else {
messageCounter = 0; messageCounter = 0;
} }
// Automatic reconnection on WebSocket close with cooldown // Automatic reconnection on WebSocket close with cooldown
const now = Date.now(); const now = Date.now();
if ( if (
@@ -421,12 +421,12 @@ function handleWebSocketMessage(event) {
}, 500); }, 500);
return; return;
} }
parsedData = JSON.parse(event.data); parsedData = JSON.parse(event.data);
resetDataTimeout(); resetDataTimeout();
updatePanels(parsedData); updatePanels(parsedData);
const sum = signalData.reduce((acc, strNum) => acc + parseFloat(strNum), 0); const sum = signalData.reduce((acc, strNum) => acc + parseFloat(strNum), 0);
const averageSignal = sum / signalData.length; const averageSignal = sum / signalData.length;
data.push(averageSignal); data.push(averageSignal);
@@ -500,11 +500,11 @@ function initCanvas() {
beginAtZero: false, beginAtZero: false,
grace: 0.25, grace: 0.25,
border: { display: false }, border: { display: false },
ticks: { ticks: {
maxTicksLimit: 3, maxTicksLimit: 3,
display: false // Hide default labels display: false // Hide default labels
}, },
grid: { grid: {
display: false, // Hide default grid lines display: false, // Hide default grid lines
}, },
}, },
@@ -513,11 +513,11 @@ function initCanvas() {
beginAtZero: false, beginAtZero: false,
grace: 0.25, grace: 0.25,
border: { display: false }, border: { display: false },
ticks: { ticks: {
maxTicksLimit: 3, maxTicksLimit: 3,
display: false // Hide default labels for the right axis display: false // Hide default labels for the right axis
}, },
grid: { grid: {
display: false, // No grid for right axis display: false, // No grid for right axis
} }
} }
@@ -558,21 +558,21 @@ function initCanvas() {
case "dbm": adjustedTickValue = tick.value - 120; break; case "dbm": adjustedTickValue = tick.value - 120; break;
default: adjustedTickValue = tick.value; break; default: adjustedTickValue = tick.value; break;
} }
if (isMiddleTick) { adjustedY += 3; } if (isMiddleTick) { adjustedY += 3; }
ctx.textAlign = 'right'; ctx.textAlign = 'right';
ctx.fillText(adjustedTickValue.toFixed(1), leftX + 25, adjustedY); ctx.fillText(adjustedTickValue.toFixed(1), leftX + 25, adjustedY);
ctx.textAlign = 'left'; ctx.textAlign = 'left';
ctx.fillText(adjustedTickValue.toFixed(1), rightX - 25, adjustedY); // Right side ctx.fillText(adjustedTickValue.toFixed(1), rightX - 25, adjustedY); // Right side
}); });
const gridLineWidth = 0.5; // Make the lines thinner to avoid overlapping text const gridLineWidth = 0.5; // Make the lines thinner to avoid overlapping text
const adjustedGridTop = chartArea.top + offset; const adjustedGridTop = chartArea.top + offset;
const adjustedGridBottom = chartArea.bottom - offset; const adjustedGridBottom = chartArea.bottom - offset;
const middleY = chartArea.top + chartArea.height / 2; const middleY = chartArea.top + chartArea.height / 2;
const padding = 45; // 30px inward on both sides const padding = 45; // 30px inward on both sides
// Helper function to draw a horizontal line // Helper function to draw a horizontal line
function drawGridLine(y) { function drawGridLine(y) {
ctx.beginPath(); ctx.beginPath();
@@ -582,12 +582,12 @@ function initCanvas() {
ctx.lineWidth = gridLineWidth; ctx.lineWidth = gridLineWidth;
ctx.stroke(); ctx.stroke();
} }
// Draw the three horizontal grid lines // Draw the three horizontal grid lines
drawGridLine(adjustedGridTop); drawGridLine(adjustedGridTop);
drawGridLine(adjustedGridBottom); drawGridLine(adjustedGridBottom);
drawGridLine(middleY); drawGridLine(middleY);
ctx.restore(); ctx.restore();
} }
}] }]
@@ -634,12 +634,12 @@ socket.onmessage = (event) => {
}, 500); }, 500);
return; return;
} }
parsedData = JSON.parse(event.data); parsedData = JSON.parse(event.data);
resetDataTimeout(); resetDataTimeout();
updatePanels(parsedData); updatePanels(parsedData);
const sum = signalData.reduce((acc, strNum) => acc + parseFloat(strNum), 0); const sum = signalData.reduce((acc, strNum) => acc + parseFloat(strNum), 0);
const averageSignal = sum / signalData.length; const averageSignal = sum / signalData.length;
data.push(averageSignal); data.push(averageSignal);
@@ -661,7 +661,7 @@ function processString(string, errors) {
const alpha_range = 50; const alpha_range = 50;
const max_error = 10; const max_error = 10;
errors = errors?.split(','); errors = errors?.split(',');
for (let i = 0; i < string.length; i++) { for (let i = 0; i < string.length; i++) {
alpha = parseInt(errors[i]) * (alpha_range / (max_error + 1)); alpha = parseInt(errors[i]) * (alpha_range / (max_error + 1));
if (alpha) { if (alpha) {
@@ -670,27 +670,27 @@ function processString(string, errors) {
output += escapeHTML(string[i]); output += escapeHTML(string[i]);
} }
} }
return output; return output;
} }
function checkKey(e) { function checkKey(e) {
e = e || window.event; e = e || window.event;
if (e.ctrlKey || e.altKey || e.shiftKey || e.metaKey) { if (e.ctrlKey || e.altKey || e.shiftKey || e.metaKey) {
return; return;
} }
if ($('#password:focus').length > 0 if ($('#password:focus').length > 0
|| $('#chat-send-message:focus').length > 0 || $('#chat-send-message:focus').length > 0
|| $('#volumeSlider:focus').length > 0 || $('#volumeSlider:focus').length > 0
|| $('#chat-nickname:focus').length > 0 || $('#chat-nickname:focus').length > 0
|| $('.option:focus').length > 0) { || $('.option:focus').length > 0) {
return; return;
} }
getCurrentFreq(); getCurrentFreq();
if (socket.readyState === WebSocket.OPEN) { if (socket.readyState === WebSocket.OPEN) {
switch (e.keyCode) { switch (e.keyCode) {
case 66: // Back to previous frequency case 66: // Back to previous frequency
@@ -717,9 +717,9 @@ function checkKey(e) {
let $dropdown = $(".data-ant"); let $dropdown = $(".data-ant");
let $input = $dropdown.find("input"); let $input = $dropdown.find("input");
let $options = $dropdown.find("ul.options .option"); let $options = $dropdown.find("ul.options .option");
if ($options.length === 0) return; // No antennas available if ($options.length === 0) return; // No antennas available
// Find the currently selected antenna // Find the currently selected antenna
let currentText = $input.val().trim(); let currentText = $input.val().trim();
let currentIndex = $options.index($options.filter(function () { let currentIndex = $options.index($options.filter(function () {
@@ -727,15 +727,15 @@ function checkKey(e) {
})); }));
console.log(currentIndex, currentText); console.log(currentIndex, currentText);
// Cycle to the next option // Cycle to the next option
let nextIndex = (currentIndex + 1) % $options.length; let nextIndex = (currentIndex + 1) % $options.length;
let $nextOption = $options.eq(nextIndex); let $nextOption = $options.eq(nextIndex);
// Update UI // Update UI
$input.attr("placeholder", $nextOption.text()); $input.attr("placeholder", $nextOption.text());
$input.data("value", $nextOption.data("value")); $input.data("value", $nextOption.data("value"));
let socketMessage = "Z" + $nextOption.data("value"); let socketMessage = "Z" + $nextOption.data("value");
socket.send(socketMessage); socket.send(socketMessage);
break; break;
@@ -769,7 +769,7 @@ async function copyPs() {
var signal = $('#data-signal').text(); var signal = $('#data-signal').text();
var signalDecimal = $('#data-signal-decimal').text(); var signalDecimal = $('#data-signal-decimal').text();
var signalUnit = $('.signal-units').eq(0).text(); var signalUnit = $('.signal-units').eq(0).text();
try { try {
await copyToClipboard(frequency + " - " + pi + " | " + ps + " [" + signal + signalDecimal + " " + signalUnit + "]"); await copyToClipboard(frequency + " - " + pi + " | " + ps + " [" + signal + signalDecimal + " " + signalUnit + "]");
} catch (error) { } catch (error) {
@@ -785,7 +785,7 @@ async function copyTx() {
const stationItu = $('#data-station-itu').text(); const stationItu = $('#data-station-itu').text();
const stationDistance = $('#data-station-distance').text(); const stationDistance = $('#data-station-distance').text();
const stationErp = $('#data-station-erp').text(); const stationErp = $('#data-station-erp').text();
try { try {
await copyToClipboard(frequency + " - " + pi + " | " + stationName + " [" + stationCity + ", " + stationItu + "] - " + stationDistance + " | " + stationErp + " kW"); await copyToClipboard(frequency + " - " + pi + " | " + stationName + " [" + stationCity + ", " + stationItu + "] - " + stationDistance + " | " + stationErp + " kW");
} catch (error) { } catch (error) {
@@ -796,7 +796,7 @@ async function copyTx() {
async function copyRt() { async function copyRt() {
var rt0 = $('#data-rt0 span').text(); var rt0 = $('#data-rt0 span').text();
var rt1 = $('#data-rt1 span').text(); var rt1 = $('#data-rt1 span').text();
try { try {
await copyToClipboard("[0] RT: " + rt0 + "\n[1] RT: " + rt1); await copyToClipboard("[0] RT: " + rt0 + "\n[1] RT: " + rt1);
} catch (error) { } catch (error) {
@@ -818,10 +818,10 @@ function copyToClipboard(textToCopy) {
'position': 'absolute', 'position': 'absolute',
'left': '-999999px' 'left': '-999999px'
}); });
$('body').prepend(textArea); $('body').prepend(textArea);
textArea.select(); textArea.select();
try { try {
document.execCommand('copy'); document.execCommand('copy');
} catch (error) { } catch (error) {
@@ -837,9 +837,9 @@ function findOnMaps() {
var pi = $('#data-pi').text(); var pi = $('#data-pi').text();
var latitude = localStorage.getItem('qthLongitude'); var latitude = localStorage.getItem('qthLongitude');
var longitude = localStorage.getItem('qthLatitude'); var longitude = localStorage.getItem('qthLatitude');
frequency > 74 ? frequency = frequency.toFixed(1) : null; frequency > 74 ? frequency = frequency.toFixed(1) : null;
var url = `https://maps.fmdx.org/#qth=${longitude},${latitude}&freq=${frequency}&findPi=${pi}`; var url = `https://maps.fmdx.org/#qth=${longitude},${latitude}&freq=${frequency}&findPi=${pi}`;
window.open(url, "_blank"); window.open(url, "_blank");
} }
@@ -849,33 +849,33 @@ function updateSignalUnits(parsedData, averageSignal) {
const signalUnit = localStorage.getItem('signalUnit'); const signalUnit = localStorage.getItem('signalUnit');
let currentSignal; let currentSignal;
let highestSignal = parsedData.sigTop; let highestSignal = parsedData.sigTop;
currentSignal = averageSignal currentSignal = averageSignal
let signalText = $('.signal-units'); let signalText = $('.signal-units');
let signalValue; let signalValue;
switch (signalUnit) { switch (signalUnit) {
case 'dbuv': case 'dbuv':
signalValue = currentSignal - 11.25; signalValue = currentSignal - 11.25;
highestSignal = highestSignal - 11.25; highestSignal = highestSignal - 11.25;
signalText.text('dBµV'); signalText.text('dBµV');
break; break;
case 'dbm': case 'dbm':
signalValue = currentSignal - 120; signalValue = currentSignal - 120;
highestSignal = highestSignal - 120; highestSignal = highestSignal - 120;
signalText.text('dBm'); signalText.text('dBm');
break; break;
default: default:
signalValue = currentSignal; signalValue = currentSignal;
signalText.text('dBf'); signalText.text('dBf');
break; break;
} }
const formatted = (Math.round(signalValue * 10) / 10).toFixed(1); const formatted = (Math.round(signalValue * 10) / 10).toFixed(1);
const [integerPart, decimalPart] = formatted.split('.'); const [integerPart, decimalPart] = formatted.split('.');
$('#data-signal-highest').text(Number(highestSignal).toFixed(1)); $('#data-signal-highest').text(Number(highestSignal).toFixed(1));
$('#data-signal').text(integerPart); $('#data-signal').text(integerPart);
$('#data-signal-decimal').text('.' + decimalPart); $('#data-signal-decimal').text('.' + decimalPart);
@@ -902,17 +902,17 @@ const $dataPty = $('.data-pty');
// Throttling function to limit the frequency of updates // Throttling function to limit the frequency of updates
function throttle(fn, wait) { function throttle(fn, wait) {
let isThrottled = false, savedArgs, savedThis; let isThrottled = false, savedArgs, savedThis;
function wrapper() { function wrapper() {
if (isThrottled) { if (isThrottled) {
savedArgs = arguments; savedArgs = arguments;
savedThis = this; savedThis = this;
return; return;
} }
fn.apply(this, arguments); fn.apply(this, arguments);
isThrottled = true; isThrottled = true;
setTimeout(function() { setTimeout(function() {
isThrottled = false; isThrottled = false;
if (savedArgs) { if (savedArgs) {
@@ -921,7 +921,7 @@ function throttle(fn, wait) {
} }
}, wait); }, wait);
} }
return wrapper; return wrapper;
} }
@@ -968,18 +968,18 @@ const updateDataElements = throttle(function(parsedData) {
updateTextIfChanged($dataFrequency, parsedData.freq); updateTextIfChanged($dataFrequency, parsedData.freq);
$commandInput.attr("aria-label", "Current frequency: " + parsedData.freq); $commandInput.attr("aria-label", "Current frequency: " + parsedData.freq);
updateHtmlIfChanged($dataPi, parsedData.pi === '?' ? "<span class='opacity-half'>?</span>" : parsedData.pi); updateHtmlIfChanged($dataPi, parsedData.pi === '?' ? "<span class='opacity-half'>?</span>" : parsedData.pi);
if ($('#ps-underscores').is(':checked')) { if ($('#ps-underscores').is(':checked')) {
parsedData.ps = parsedData.ps.replace(/\s/g, '_'); parsedData.ps = parsedData.ps.replace(/\s/g, '_');
} }
updateHtmlIfChanged($dataPs, parsedData.ps === '?' ? "<span class='opacity-half'>?</span>" : processString(parsedData.ps, parsedData.ps_errors)); updateHtmlIfChanged($dataPs, parsedData.ps === '?' ? "<span class='opacity-half'>?</span>" : processString(parsedData.ps, parsedData.ps_errors));
if(parsedData.st) { if(parsedData.st) {
$dataSt.parent().removeClass('opacity-half'); $dataSt.parent().removeClass('opacity-half');
} else { } else {
$dataSt.parent().addClass('opacity-half'); $dataSt.parent().addClass('opacity-half');
} }
if(parsedData.stForced) { if(parsedData.stForced) {
if (!parsedData.st) { if (!parsedData.st) {
stereoColor = 'gray'; stereoColor = 'gray';
@@ -992,28 +992,28 @@ const updateDataElements = throttle(function(parsedData) {
$('.data-st.circle1').css('left', '0px'); $('.data-st.circle1').css('left', '0px');
$('.data-st.circle2').css('display', 'block'); $('.data-st.circle2').css('display', 'block');
} }
updateHtmlIfChanged($dataRt0, processString(parsedData.rt0, parsedData.rt0_errors)); updateHtmlIfChanged($dataRt0, processString(parsedData.rt0, parsedData.rt0_errors));
updateHtmlIfChanged($dataRt1, processString(parsedData.rt1, parsedData.rt1_errors)); updateHtmlIfChanged($dataRt1, processString(parsedData.rt1, parsedData.rt1_errors));
updateTextIfChanged($dataPty, rdsMode == 'true' ? usa_programmes[parsedData.pty] : europe_programmes[parsedData.pty]); updateTextIfChanged($dataPty, rdsMode == 'true' ? usa_programmes[parsedData.pty] : europe_programmes[parsedData.pty]);
if (parsedData.rds === true) { if (parsedData.rds === true) {
$flagDesktopCointainer.css('background-color', 'var(--color-2-transparent)'); $flagDesktopCointainer.css('background-color', 'var(--color-2-transparent)');
} else { } else {
$flagDesktopCointainer.css('background-color', 'var(--color-1-transparent)'); $flagDesktopCointainer.css('background-color', 'var(--color-1-transparent)');
} }
$('.data-flag').html(`<i title="${parsedData.country_name}" class="flag-sm flag-sm-${parsedData.country_iso}"></i>`); $('.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-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 + '"]').first().text()); $dataAntInput.val($('.data-ant li[data-value="' + parsedData.ant + '"]').first().text());
if (typeof parsedData.agc !== 'undefined') $dataAgcInput.val($('.data-agc li[data-value="' + parsedData.agc + '"]').first().text()); if (typeof parsedData.agc !== 'undefined') $dataAgcInput.val($('.data-agc li[data-value="' + parsedData.agc + '"]').first().text());
if (parsedData.bw < 500) $dataBwInput.val($('.data-bw li[data-value2="' + parsedData.bw + '"]').first().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 + '"]').first().text()); else $dataBwInput.val($('.data-bw li[data-value="' + parsedData.bw + '"]').first().text());
if (parsedData.txInfo.tx.length > 1) { if (parsedData.txInfo.tx.length > 1) {
updateTextIfChanged($('#data-station-name'), parsedData.txInfo.tx.replace(/%/g, '%25')); updateTextIfChanged($('#data-station-name'), parsedData.txInfo.tx.replace(/%/g, '%25'));
updateTextIfChanged($('#data-station-erp'), parsedData.txInfo.erp); updateTextIfChanged($('#data-station-erp'), parsedData.txInfo.erp);
@@ -1028,17 +1028,12 @@ const updateDataElements = throttle(function(parsedData) {
updateHtmlIfChanged($('#alternative-txes'), altTxInfo); updateHtmlIfChanged($('#alternative-txes'), altTxInfo);
updateTextIfChanged($('#data-station-distance'), txDistance); updateTextIfChanged($('#data-station-distance'), txDistance);
$dataStationContainer.css('display', 'block'); $dataStationContainer.css('display', 'block');
} else { } else $dataStationContainer.removeAttr('style');
$dataStationContainer.removeAttr('style');
} if(parsedData.txInfo.tx.length > 1 && parsedData.txInfo.dist > 150 && parsedData.txInfo.dist < 4000) $('.log-fmlist').removeAttr('disabled').removeClass('btn-disabled cursor-disabled');
else $('.log-fmlist').attr('disabled', 'true').addClass('btn-disabled cursor-disabled');
if(parsedData.txInfo.tx.length > 1 && parsedData.txInfo.dist > 150 && parsedData.txInfo.dist < 4000) {
$('.log-fmlist').removeAttr('disabled').removeClass('btn-disabled cursor-disabled');
} else {
$('.log-fmlist').attr('disabled', 'true').addClass('btn-disabled cursor-disabled');
}
updateHtmlIfChanged($('#data-regular-pi'), parsedData.txInfo.reg === true ? parsedData.txInfo.pi : '&nbsp;'); updateHtmlIfChanged($('#data-regular-pi'), parsedData.txInfo.reg === true ? parsedData.txInfo.pi : '&nbsp;');
if (updateCounter % 8 === 0) { if (updateCounter % 8 === 0) {
$dataTp.html(parsedData.tp === 0 ? "<span class='opacity-half'>TP</span>" : "TP"); $dataTp.html(parsedData.tp === 0 ? "<span class='opacity-half'>TP</span>" : "TP");
$dataTa.html(parsedData.ta === 0 ? "<span class='opacity-half'>TA</span>" : "TA"); $dataTa.html(parsedData.ta === 0 ? "<span class='opacity-half'>TA</span>" : "TA");
@@ -1050,7 +1045,7 @@ const updateDataElements = throttle(function(parsedData) {
) )
); );
} }
if (updateCounter % 30 === 0) { if (updateCounter % 30 === 0) {
$dataPs.attr('aria-label', parsedData.ps); $dataPs.attr('aria-label', parsedData.ps);
$dataRt0.attr('aria-label', parsedData.rt0); $dataRt0.attr('aria-label', parsedData.rt0);
@@ -1063,36 +1058,35 @@ let isEventListenerAdded = false;
function updatePanels(parsedData) { function updatePanels(parsedData) {
updateCounter = (updateCounter % 10000) + 1; // Count to 10000 then reset back to 1 updateCounter = (updateCounter % 10000) + 1; // Count to 10000 then reset back to 1
signalData.push(parsedData.sig); signalData.push(parsedData.sig);
if (signalData.length > 8) { if (signalData.length > 8) {
signalData.shift(); // Remove the oldest element signalData.shift(); // Remove the oldest element
} }
const sum = signalData.reduce((acc, strNum) => acc + parseFloat(strNum), 0); const sum = signalData.reduce((acc, strNum) => acc + parseFloat(strNum), 0);
const averageSignal = sum / signalData.length; const averageSignal = sum / signalData.length;
const sortedAf = parsedData.af.sort(compareNumbers); const sortedAf = parsedData.af.sort(compareNumbers);
const scaledArray = sortedAf.map(element => element / 1000); const scaledArray = sortedAf.map(element => element / 1000);
const listContainer = $('#af-list'); const listContainer = $('#af-list');
const scrollTop = listContainer.scrollTop(); const scrollTop = listContainer.scrollTop();
let ul = listContainer.find('ul'); let ul = listContainer.find('ul');
if (!ul.length) { if (!ul.length) {
ul = $('<ul></ul>'); ul = $('<ul></ul>');
listContainer.append(ul); listContainer.append(ul);
} }
if (updateCounter % 3 === 0) { if (updateCounter % 3 === 0) {
updateButtonState("data-eq", parsedData.eq); updateButtonState("data-eq", parsedData.eq);
updateButtonState("data-ims", parsedData.ims); updateButtonState("data-ims", parsedData.ims);
// Only update #af-list on every 3rd call // Only update #af-list on every 3rd call
ul.html(''); ul.html('');
const listItems = scaledArray.map(createListItem); const listItems = scaledArray.map(createListItem);
ul.append(listItems); ul.append(listItems);
// Add the event listener only once // Add the event listener only once
if (!isEventListenerAdded) { if (!isEventListenerAdded) {
ul.on('click', 'a', function () { ul.on('click', 'a', function () {
@@ -1101,10 +1095,10 @@ function updatePanels(parsedData) {
}); });
isEventListenerAdded = true; isEventListenerAdded = true;
} }
listContainer.scrollTop(scrollTop); listContainer.scrollTop(scrollTop);
} }
updateDataElements(parsedData); updateDataElements(parsedData);
updateSignalUnits(parsedData, averageSignal); updateSignalUnits(parsedData, averageSignal);
$('.users-online').text(parsedData.users); $('.users-online').text(parsedData.users);
@@ -1116,11 +1110,11 @@ function createListItem(element) {
function updateButtonState(buttonId, value) { function updateButtonState(buttonId, value) {
var button = $("#" + buttonId); var button = $("#" + buttonId);
if (button.length === 0) { if (button.length === 0) {
button = $("." + buttonId); button = $("." + buttonId);
} }
if (button.length > 0) { if (button.length > 0) {
if (value == 0) { if (value == 0) {
button.hasClass("btn-disabled") ? null : button.addClass("btn-disabled"); button.hasClass("btn-disabled") ? null : button.addClass("btn-disabled");
@@ -1152,7 +1146,7 @@ function toggleForcedStereo() {
function toggleLock(buttonSelector, activeMessage, inactiveMessage, activeLabel, inactiveLabel) { function toggleLock(buttonSelector, activeMessage, inactiveMessage, activeLabel, inactiveLabel) {
let $lockButton = $(buttonSelector); let $lockButton = $(buttonSelector);
if ($lockButton.hasClass('active')) { if ($lockButton.hasClass('active')) {
socket.send(inactiveMessage); socket.send(inactiveMessage);
$lockButton.attr('aria-label', inactiveLabel); $lockButton.attr('aria-label', inactiveLabel);
@@ -1166,17 +1160,17 @@ function toggleLock(buttonSelector, activeMessage, inactiveMessage, activeLabel,
function showTunerDescription() { function showTunerDescription() {
let parentDiv = $("#tuner-name").parent(); let parentDiv = $("#tuner-name").parent();
if (!$("#dashboard-panel-description").is(":visible")) { if (!$("#dashboard-panel-description").is(":visible")) {
parentDiv.css("border-radius", "15px 15px 0 0"); parentDiv.css("border-radius", "15px 15px 0 0");
} }
$("#dashboard-panel-description").slideToggle(300, function() { $("#dashboard-panel-description").slideToggle(300, function() {
if (!$(this).is(":visible")) { if (!$(this).is(":visible")) {
parentDiv.css("border-radius", ""); parentDiv.css("border-radius", "");
} }
}); });
$("#tuner-name i").toggleClass("rotated"); $("#tuner-name i").toggleClass("rotated");
if ($(window).width() < 768) { if ($(window).width() < 768) {
@@ -1187,29 +1181,29 @@ function showTunerDescription() {
function initTooltips(target = null) { function initTooltips(target = null) {
// Define scope: all tooltips or specific one if target is provided // Define scope: all tooltips or specific one if target is provided
const tooltips = target ? $(target) : $('.tooltip'); const tooltips = target ? $(target) : $('.tooltip');
// Unbind existing event handlers before rebinding to avoid duplication // Unbind existing event handlers before rebinding to avoid duplication
tooltips.off('mouseenter mouseleave'); tooltips.off('mouseenter mouseleave');
tooltips.hover(function () { tooltips.hover(function () {
if ($(this).closest('.popup-content').length) { if ($(this).closest('.popup-content').length) {
return; return;
} }
var tooltipText = $(this).data('tooltip'); var tooltipText = $(this).data('tooltip');
var placement = $(this).data('tooltip-placement') || 'top'; // Default to 'top' var placement = $(this).data('tooltip-placement') || 'top'; // Default to 'top'
// Clear existing timeouts // Clear existing timeouts
$(this).data('timeout', setTimeout(() => { $(this).data('timeout', setTimeout(() => {
$('.tooltip-wrapper').remove(); $('.tooltip-wrapper').remove();
var tooltip = $(` var tooltip = $(`
<div class="tooltip-wrapper"> <div class="tooltip-wrapper">
<div class="tooltiptext">${tooltipText}</div> <div class="tooltiptext">${tooltipText}</div>
</div> </div>
`); `);
$('body').append(tooltip); $('body').append(tooltip);
var tooltipEl = $('.tooltiptext'); var tooltipEl = $('.tooltiptext');
var tooltipWidth = tooltipEl.outerWidth(); var tooltipWidth = tooltipEl.outerWidth();
var tooltipHeight = tooltipEl.outerHeight(); var tooltipHeight = tooltipEl.outerHeight();
@@ -1217,7 +1211,7 @@ function initTooltips(target = null) {
var targetOffset = targetEl.offset(); var targetOffset = targetEl.offset();
var targetWidth = targetEl.outerWidth(); var targetWidth = targetEl.outerWidth();
var targetHeight = targetEl.outerHeight(); var targetHeight = targetEl.outerHeight();
// Compute position // Compute position
var posX, posY; var posX, posY;
switch (placement) { switch (placement) {
@@ -1239,7 +1233,7 @@ function initTooltips(target = null) {
posY = targetOffset.top - tooltipHeight - 10; posY = targetOffset.top - tooltipHeight - 10;
break; break;
} }
// Apply positioning // Apply positioning
tooltipEl.css({ top: posY, left: posX, opacity: 1 }); tooltipEl.css({ top: posY, left: posX, opacity: 1 });
@@ -1247,32 +1241,32 @@ function initTooltips(target = null) {
if ((/Mobi|Android|iPhone|iPad|iPod|Opera Mini/i.test(navigator.userAgent)) && ('ontouchstart' in window || navigator.maxTouchPoints)) { if ((/Mobi|Android|iPhone|iPad|iPod|Opera Mini/i.test(navigator.userAgent)) && ('ontouchstart' in window || navigator.maxTouchPoints)) {
setTimeout(() => { $('.tooltiptext').remove(); }, 5000); setTimeout(() => { $('.tooltiptext').remove(); }, 5000);
} }
}, 300)); }, 300));
}, function () { }, function () {
clearTimeout($(this).data('timeout')); clearTimeout($(this).data('timeout'));
setTimeout(() => { setTimeout(() => {
$('.tooltip-wrapper').fadeOut(300, function () { $('.tooltip-wrapper').fadeOut(300, function () {
$(this).remove(); $(this).remove();
}); });
}, 100); }, 100);
}); });
$('.popup-content').off('mouseenter').on('mouseenter', function () { $('.popup-content').off('mouseenter').on('mouseenter', function () {
clearTimeout($('.tooltip').data('timeout')); clearTimeout($('.tooltip').data('timeout'));
$('.tooltip-wrapper').fadeOut(300, function () { $('.tooltip-wrapper').fadeOut(300, function () {
$(this).remove(); $(this).remove();
}); });
}); });
} }
function fillPresets() { function fillPresets() {
let hasAnyPreset = false; let hasAnyPreset = false;
for (let i = 1; i <= 4; i++) { for (let i = 1; i <= 4; i++) {
let presetText = localStorage.getItem(`preset${i}`); let presetText = localStorage.getItem(`preset${i}`);
if (presetText != "null") { if (presetText != "null") {
hasAnyPreset = true; hasAnyPreset = true;
$(`#preset${i}-text`).text(presetText); $(`#preset${i}-text`).text(presetText);
@@ -1283,9 +1277,8 @@ function initTooltips(target = null) {
$(`#preset${i}`).hide(); $(`#preset${i}`).hide();
} }
} }
if (!hasAnyPreset) { if (!hasAnyPreset) {
$('#preset1').parent().hide(); $('#preset1').parent().hide();
} }
} }

View File

@@ -3,15 +3,15 @@ $(document).ready(function() {
var modalPanel = $(".modal-panel"); var modalPanel = $(".modal-panel");
var openBtn = $(".settings"); var openBtn = $(".settings");
var closeBtn = $(".closeModal, .closeModalButton"); var closeBtn = $(".closeModal, .closeModalButton");
initPopups(); initPopups();
openBtn.on("click", function() { openBtn.on("click", function() {
openModal(modalPanel); openModal(modalPanel);
}); });
closeBtn.on("click", closeModal); closeBtn.on("click", closeModal);
function openModal(panel) { function openModal(panel) {
modal.css("display", "block"); modal.css("display", "block");
panel.css("display", "block"); panel.css("display", "block");
@@ -20,7 +20,7 @@ $(document).ready(function() {
modal.css("opacity", 1); modal.css("opacity", 1);
}, 10); }, 10);
} }
function closeModal() { function closeModal() {
modal.css("opacity", 0); modal.css("opacity", 0);
setTimeout(function() { setTimeout(function() {
@@ -28,24 +28,20 @@ $(document).ready(function() {
$("body").removeClass("modal-open"); // Enable body scrolling $("body").removeClass("modal-open"); // Enable body scrolling
}, 300); }, 300);
} }
$(document).on("click", function(event) { // Close the modal when clicking outside of it $(document).on("click", function(event) { // Close the modal when clicking outside of it
if ($(event.target).is(modal)) { if ($(event.target).is(modal)) closeModal();
closeModal();
}
}); });
$(document).on("keydown", function(event) { // Close the modal when pressing ESC key $(document).on("keydown", function(event) { // Close the modal when pressing ESC key
if (event.key === "Escape") { if (event.key === "Escape") closeModal();
closeModal();
}
}); });
$(".tuner-mobile-settings").on("click", function () { $(".tuner-mobile-settings").on("click", function () {
togglePopup("#popup-panel-mobile-settings"); togglePopup("#popup-panel-mobile-settings");
}); });
$("#data-station-others").on("click", function () { $("#data-station-others").on("click", function () {
togglePopup("#popup-panel-transmitters"); togglePopup("#popup-panel-transmitters");
}); });
@@ -54,13 +50,13 @@ $(document).ready(function() {
function initPopups() { function initPopups() {
$(".popup-window").draggable({ $(".popup-window").draggable({
handle: ".popup-header", handle: ".popup-header",
containment: "body" containment: "body"
}).resizable({ }).resizable({
minHeight: 330, minHeight: 330,
minWidth: 350, minWidth: 350,
containment: "body" containment: "body"
}); });
$(".popup-close").on("click", function () { $(".popup-close").on("click", function () {
$(".popup-window").fadeOut(200); $(".popup-window").fadeOut(200);
}); });
@@ -69,9 +65,8 @@ function initPopups() {
function togglePopup(targetSelector) { function togglePopup(targetSelector) {
const $target = $(targetSelector); const $target = $(targetSelector);
if ($target.is(":visible")) { if ($target.is(":visible")) $target.fadeOut(200);
$target.fadeOut(200); else {
} else {
$(".popup-window").fadeOut(200); $(".popup-window").fadeOut(200);
$target.fadeIn(200); $target.fadeIn(200);
} }

View File

@@ -189,9 +189,7 @@ function loadInitialSettings() {
if(signalParameter && !localStorage.getItem('signalUnit')) { if(signalParameter && !localStorage.getItem('signalUnit')) {
signalSelector.find('input').val(signalSelector.find('.option[data-value="' + signalParameter + '"]').text()); signalSelector.find('input').val(signalSelector.find('.option[data-value="' + signalParameter + '"]').text());
localStorage.setItem('signalUnit', signalParameter); localStorage.setItem('signalUnit', signalParameter);
} else { } else signalSelector.find('input').val(signalSelector.find('.option[data-value="' + savedUnit + '"]').text());
signalSelector.find('input').val(signalSelector.find('.option[data-value="' + savedUnit + '"]').text());
}
signalSelector.on('click', '.option', (event) => { signalSelector.on('click', '.option', (event) => {
const selectedSignalUnit = $(event.target).data('value'); const selectedSignalUnit = $(event.target).data('value');

View File

@@ -27,9 +27,7 @@ function mapCreate() {
zoom: 3, zoom: 3,
worldCopyJump: true worldCopyJump: true
}); });
} else { } else map.setZoom(3).panTo([40, 0]);
map.setZoom(3).panTo([40, 0]);
}
L.tileLayer(tilesURL, { L.tileLayer(tilesURL, {
attribution: mapAttrib, attribution: mapAttrib,
@@ -272,9 +270,7 @@ function checkTunnelServers() {
// If this li is the currently selected one, update input text too // If this li is the currently selected one, update input text too
// Note: input.val() holds the label, so match by label is safer // Note: input.val() holds the label, so match by label is safer
if ($li.text() === selectedValue || server.value === selectedValue) { if ($li.text() === selectedValue || server.value === selectedValue) $input.val(server.label);
$input.val(server.label);
}
} }
}); });
}, },

View File

@@ -27,8 +27,6 @@ function navigateStep(isNext) {
currentStep.hide(); currentStep.hide();
targetStep.show(); targetStep.show();
updateProgressBar(targetStep); updateProgressBar(targetStep);
} else if (isNext) { } else if (isNext) submitConfig();
submitConfig();
}
updateWizardContent(); updateWizardContent();
} }

View File

@@ -109,7 +109,7 @@
<a href="https://dnschecker.org/ip-location.php?ip=<%= user.ip.replace('::ffff:', '') %>" target="_blank"> <a href="https://dnschecker.org/ip-location.php?ip=<%= user.ip.replace('::ffff:', '') %>" target="_blank">
<%= user.ip.replace('::ffff:', '') %> <%= user.ip.replace('::ffff:', '') %>
</a> </a>
</td> </td>
<td><%= user.location %></td> <td><%= user.location %></td>
<td><%= user.time %></td> <td><%= user.time %></td>
<td><a href="./kick?ip=<%= user.ip %>">Kick</a></td> <td><a href="./kick?ip=<%= user.ip %>">Kick</a></td>
@@ -121,10 +121,10 @@
</tr> </tr>
<% } %> <% } %>
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
<div class="flex-container"> <div class="flex-container">
<div class="panel-100-real p-bottom-20"> <div class="panel-100-real p-bottom-20">
<h3>Quick settings</h3> <h3>Quick settings</h3>
@@ -132,7 +132,7 @@
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Unlocked Tuner', id: 'publicTuner'}) %> <%- include('_components', {component: 'checkbox', cssClass: '', label: 'Unlocked Tuner', id: 'publicTuner'}) %>
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Admin lock', id: 'lockToAdmin'}) %><br> <%- include('_components', {component: 'checkbox', cssClass: '', label: 'Admin lock', id: 'lockToAdmin'}) %><br>
</div> </div>
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Tune password', id: 'password-tunePass', password: true}) %> <%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Tune password', id: 'password-tunePass', password: true}) %>
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Admin password', id: 'password-adminPass', password: true}) %><br> <%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Admin password', id: 'password-adminPass', password: true}) %><br>
</div> </div>
@@ -156,7 +156,7 @@
<div class="panel-full tab-content no-bg m-0" id="audio" role="tabpanel"> <div class="panel-full tab-content no-bg m-0" id="audio" role="tabpanel">
<h2>Audio settings</h2> <h2>Audio settings</h2>
<div class="flex-container contains-dropdown"> <div class="flex-container contains-dropdown">
<div class="panel-33 p-bottom-20"> <div class="panel-33 p-bottom-20">
<h3>Device</h3> <h3>Device</h3>
@@ -181,14 +181,14 @@
label: `${device.name}` label: `${device.name}`
})) }))
] ]
}) %> }) %>
</div> </div>
<div class="panel-33 p-bottom-20"> <div class="panel-33 p-bottom-20">
<h3>Channels</h3> <h3>Channels</h3>
<p>Audio channel count.<br> <p>Audio channel count.<br>
<span class="text-gray">Choose between Mono / Stereo.</span> <span class="text-gray">Choose between Mono / Stereo.</span>
</p> </p>
<%- include('_components', { component: 'dropdown', id: 'audio-channels-dropdown', inputId: 'audio-audioChannels', label: 'Audio channels', cssClass: '', placeholder: 'Stereo', <%- include('_components', { component: 'dropdown', id: 'audio-channels-dropdown', inputId: 'audio-audioChannels', label: 'Audio channels', cssClass: '', placeholder: 'Stereo',
options: [ options: [
{ value: '2', label: 'Stereo' }, { value: '2', label: 'Stereo' },
{ value: '1', label: 'Mono' } { value: '1', label: 'Mono' }
@@ -200,7 +200,7 @@
<p>The bitrate of the mp3 audio.<br> <p>The bitrate of the mp3 audio.<br>
<span class="text-gray">Minimum: 64 Kbps • Maximum: 320 Kbps</span> <span class="text-gray">Minimum: 64 Kbps • Maximum: 320 Kbps</span>
</p> </p>
<%- include('_components', { component: 'dropdown', id: 'audio-quality-dropdown', inputId: 'audio-audioBitrate', label: 'Audio quality', cssClass: '', placeholder: '128kbps (standard)', <%- include('_components', { component: 'dropdown', id: 'audio-quality-dropdown', inputId: 'audio-audioBitrate', label: 'Audio quality', cssClass: '', placeholder: '128kbps (standard)',
options: [ options: [
{ value: '64k', label: '64kbps (lowest quality)' }, { value: '64k', label: '64kbps (lowest quality)' },
{ value: '96k', label: '96kbps (low quality)' }, { value: '96k', label: '96kbps (low quality)' },
@@ -251,11 +251,11 @@
</div> </div>
<div class="panel-50 p-bottom-20"> <div class="panel-50 p-bottom-20">
<h3>Design</h3> <h3>Design</h3>
<h4>Background image</h4> <h4>Background image</h4>
<%- include('_components', {component: 'text', cssClass: 'br-15', placeholder: 'Direct image link', label: 'Image link', id: 'webserver-bgImage'}) %><br> <%- include('_components', {component: 'text', cssClass: 'br-15', placeholder: 'Direct image link', label: 'Image link', id: 'webserver-bgImage'}) %><br>
<h4 class="top-25">Themes</h4> <h4 class="top-25">Themes</h4>
<%- include('_components', { component: 'dropdown', id: 'server-theme-selector', inputId: 'webserver-defaultTheme', label: 'Default server theme', cssClass: '', placeholder: 'Default', <%- include('_components', { component: 'dropdown', id: 'server-theme-selector', inputId: 'webserver-defaultTheme', label: 'Default server theme', cssClass: '', placeholder: 'Default',
options: [ options: [
{ value: 'theme1', label: 'Mint' }, { value: 'theme1', label: 'Mint' },
{ value: 'theme2', label: 'Cappuccino' }, { value: 'theme2', label: 'Cappuccino' },
@@ -280,17 +280,17 @@
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Antenna 1', id: 'antennas-ant1-enabled'}) %> <%- include('_components', {component: 'checkbox', cssClass: '', label: 'Antenna 1', id: 'antennas-ant1-enabled'}) %>
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: 'Ant A', label: 'Antenna 1 name', id: 'antennas-ant1-name'}) %><br> <%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: 'Ant A', label: 'Antenna 1 name', id: 'antennas-ant1-name'}) %><br>
</div> </div>
<div class="flex-container flex-phone flex-column bottom-20" style="margin-left: 15px; margin-right: 15px;"> <div class="flex-container flex-phone flex-column bottom-20" style="margin-left: 15px; margin-right: 15px;">
<%- include('_components', {component: 'checkbox', cssClass: 'top-25', label: 'Antenna 2', id: 'antennas-ant2-enabled'}) %> <%- include('_components', {component: 'checkbox', cssClass: 'top-25', label: 'Antenna 2', id: 'antennas-ant2-enabled'}) %>
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: 'Ant B', label: 'Antenna 2 name', id: 'antennas-ant2-name'}) %><br> <%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: 'Ant B', label: 'Antenna 2 name', id: 'antennas-ant2-name'}) %><br>
</div> </div>
<div class="flex-container flex-phone flex-column bottom-20" style="margin-left: 15px; margin-right: 15px;"> <div class="flex-container flex-phone flex-column bottom-20" style="margin-left: 15px; margin-right: 15px;">
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Antenna 3', id: 'antennas-ant3-enabled'}) %> <%- include('_components', {component: 'checkbox', cssClass: '', label: 'Antenna 3', id: 'antennas-ant3-enabled'}) %>
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: 'Ant C', label: 'Antenna 3 name', id: 'antennas-ant3-name'}) %><br> <%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: 'Ant C', label: 'Antenna 3 name', id: 'antennas-ant3-name'}) %><br>
</div> </div>
<div class="flex-container flex-phone flex-column bottom-20" style="margin-left: 15px; margin-right: 15px;"> <div class="flex-container flex-phone flex-column bottom-20" style="margin-left: 15px; margin-right: 15px;">
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Antenna 4', id: 'antennas-ant4-enabled'}) %> <%- include('_components', {component: 'checkbox', cssClass: '', label: 'Antenna 4', id: 'antennas-ant4-enabled'}) %>
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: 'Ant D', label: 'Antenna 4 name', id: 'antennas-ant4-name'}) %><br> <%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: 'Ant D', label: 'Antenna 4 name', id: 'antennas-ant4-name'}) %><br>
@@ -337,7 +337,7 @@
<div class="panel-50 p-bottom-20" style="padding-left: 20px; padding-right: 20px; padding-bottom: 80px;"> <div class="panel-50 p-bottom-20" style="padding-left: 20px; padding-right: 20px; padding-bottom: 80px;">
<h3>Transmitter Search Algorithm</h3> <h3>Transmitter Search Algorithm</h3>
<p>Different modes may help with more accurate transmitter identification depending on your region.</p> <p>Different modes may help with more accurate transmitter identification depending on your region.</p>
<%- include('_components', { component: 'dropdown', id: 'server-tx-id-algo', inputId: 'webserver-txIdAlgorithm', label: 'Transmitter ID Algorithm', cssClass: '', placeholder: 'Algorithm 1', <%- include('_components', { component: 'dropdown', id: 'server-tx-id-algo', inputId: 'webserver-txIdAlgorithm', label: 'Transmitter ID Algorithm', cssClass: '', placeholder: 'Algorithm 1',
options: [ options: [
{ value: '0', label: 'Algorithm 1' }, { value: '0', label: 'Algorithm 1' },
{ value: '1', label: 'Algorithm 2' }, { value: '1', label: 'Algorithm 2' },
@@ -354,7 +354,7 @@
<div class="panel-100 p-bottom-20 contains-dropdown" style="z-index: 991;"> <div class="panel-100 p-bottom-20 contains-dropdown" style="z-index: 991;">
<h3>Device type</h3> <h3>Device type</h3>
<div class="flex-center" style="max-width: 520px; margin: 10px auto 0;"> <div class="flex-center" style="max-width: 520px; margin: 10px auto 0;">
<%- include('_components', { component: 'dropdown', id: 'device-selector', inputId: 'device', label: 'Device', cssClass: '', placeholder: 'TEF668x / TEA685x', <%- include('_components', { component: 'dropdown', id: 'device-selector', inputId: 'device', label: 'Device', cssClass: '', placeholder: 'TEF668x / TEA685x',
options: tunerProfiles.map(profile => ({ options: tunerProfiles.map(profile => ({
value: profile.id, value: profile.id,
label: profile.label label: profile.label
@@ -374,7 +374,7 @@
<span> <span>
<span class="left-span">Direct</span> <span class="left-span">Direct</span>
<span class="right-span">TCP/IP</span> <span class="right-span">TCP/IP</span>
</span> </span>
</label> </label>
</div> </div>
<div id="tuner-usb"> <div id="tuner-usb">
@@ -390,9 +390,9 @@
value: serialPort.path, value: serialPort.path,
label: `${serialPort.path} - ${serialPort.friendlyName}` label: `${serialPort.path} - ${serialPort.friendlyName}`
})) }))
}) %> }) %>
</div> </div>
<div id="tuner-wireless"> <div id="tuner-wireless">
<p class="text-gray">If you are connecting your tuner <strong>wirelessly</strong>, enter the tuner IP. <br> If you use <strong>xdrd</strong>, use 127.0.0.1 as your IP.</p> <p class="text-gray">If you are connecting your tuner <strong>wirelessly</strong>, enter the tuner IP. <br> If you use <strong>xdrd</strong>, use 127.0.0.1 as your IP.</p>
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', label: 'xdrd IP address', id: 'xdrd-xdrdIp'}) %> <%- include('_components', {component: 'text', cssClass: 'w-150 br-15', label: 'xdrd IP address', id: 'xdrd-xdrdIp'}) %>
@@ -409,7 +409,7 @@
<input type="range" id="audio-startupVolume" min="0" max="1" step="0.01" value="1" aria-label="Startup Volume slider"> <input type="range" id="audio-startupVolume" min="0" max="1" step="0.01" value="1" aria-label="Startup Volume slider">
</div> </div>
<h4 class="top-10 text-gray" id="volume-percentage-value"></h4> <h4 class="top-10 text-gray" id="volume-percentage-value"></h4>
<hr> <hr>
<h4 class="bottom-20">Default frequency</h4> <h4 class="bottom-20">Default frequency</h4>
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Default frequency for first client', id: 'enableDefaultFreq'}) %><br> <%- include('_components', {component: 'checkbox', cssClass: '', label: 'Default frequency for first client', id: 'enableDefaultFreq'}) %><br>
@@ -468,7 +468,7 @@
<div class="flex-container"> <div class="flex-container">
<div class="panel-50 p-bottom-20"> <div class="panel-50 p-bottom-20">
<h3>Basic info</h3> <h3>Basic info</h3>
<p>Set your tuner name and description here.<br>This info will be visible to anyone who tunes in. </p> <p>Set your tuner name and description here.<br>This info will be visible to anyone who tunes in. </p>
<div class="panel-full no-bg" style="padding-left: 20px; padding-right: 20px;"> <div class="panel-full no-bg" style="padding-left: 20px; padding-right: 20px;">
<label for="identification-tunerName" style="width: 100%;max-width: 768px; margin:auto;">Webserver name:</label> <label for="identification-tunerName" style="width: 100%;max-width: 768px; margin:auto;">Webserver name:</label>
@@ -486,7 +486,7 @@
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Broadcast to map', id: 'identification-broadcastTuner'}) %><br> <%- include('_components', {component: 'checkbox', cssClass: '', label: 'Broadcast to map', id: 'identification-broadcastTuner'}) %><br>
<%- include('_components', {component: 'text', cssClass: 'br-15', placeholder: 'Your e-mail or Discord...', label: 'Owner contact', id: 'identification-contact'}) %> <%- include('_components', {component: 'text', cssClass: 'br-15', placeholder: 'Your e-mail or Discord...', label: 'Owner contact', id: 'identification-contact'}) %>
<%- include('_components', {component: 'text', cssClass: 'br-15', label: 'Proxy address', id: 'identification-proxyIp'}) %> <%- include('_components', {component: 'text', cssClass: 'br-15', label: 'Proxy address', id: 'identification-proxyIp'}) %>
<p>Check your tuner at <strong><a href="https://servers.fmdx.org" target="_blank" class="color-4">servers.fmdx.org</a></strong>.</p> <p>Check your tuner at <strong><a href="https://servers.fmdx.org" target="_blank" class="color-4">servers.fmdx.org</a></strong>.</p>
<p class="text-small text-gray">By activating the <strong>Broadcast to map</strong> option,<br>you agree to the <a href="https://fmdx.org/projects/webserver.php#rules" target="_blank">Terms of Service</a>.</p> <p class="text-small text-gray">By activating the <strong>Broadcast to map</strong> option,<br>you agree to the <a href="https://fmdx.org/projects/webserver.php#rules" target="_blank">Terms of Service</a>.</p>
</div> </div>
@@ -498,7 +498,7 @@
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Latitude', id: 'identification-lat'}) %> <%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Latitude', id: 'identification-lat'}) %>
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Longitude', id: 'identification-lon'}) %> <%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Longitude', id: 'identification-lon'}) %>
<div id="map"></div> <div id="map"></div>
<br> <br>
</div> </div>
@@ -508,7 +508,7 @@
<h2>User management</h2> <h2>User management</h2>
<div class="panel-100"> <div class="panel-100">
<h3>Chat options</h3> <h3>Chat options</h3>
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Chat', id: 'webserver-chatEnabled'}) %> <%- include('_components', {component: 'checkbox', cssClass: '', label: 'Chat', id: 'webserver-chatEnabled'}) %>
</div> </div>
<div class="panel-100 p-bottom-20"> <div class="panel-100 p-bottom-20">
@@ -573,33 +573,33 @@
<p>These settings will be applied after a server launch or restart.</p> <p>These settings will be applied after a server launch or restart.</p>
<div class="flex-container flex-center p-20"> <div class="flex-container flex-center p-20">
<% if (device === 'tef') { %> <% if (device === 'tef') { %>
<%- include('_components', { component: 'dropdown', id: 'ceqStartup-dropdown', inputId: 'ceqStartup', label: 'cEQ', cssClass: '', placeholder: 'Disabled', <%- include('_components', { component: 'dropdown', id: 'ceqStartup-dropdown', inputId: 'ceqStartup', label: 'cEQ', cssClass: '', placeholder: 'Disabled',
options: [ options: [
{ value: '0', label: 'Disabled' }, { value: '0', label: 'Disabled' },
{ value: '1', label: 'Enabled' }, { value: '1', label: 'Enabled' },
] ]
}) %><br> }) %><br>
<%- include('_components', { component: 'dropdown', id: 'imsStartup-dropdown', inputId: 'imsStartup', label: 'iMS', cssClass: '', placeholder: 'Disabled', <%- include('_components', { component: 'dropdown', id: 'imsStartup-dropdown', inputId: 'imsStartup', label: 'iMS', cssClass: '', placeholder: 'Disabled',
options: [ options: [
{ value: '0', label: 'Disabled' }, { value: '0', label: 'Disabled' },
{ value: '1', label: 'Enabled' }, { value: '1', label: 'Enabled' },
] ]
}) %><br> }) %><br>
<% } else if (device === 'xdr') { %> <% } else if (device === 'xdr') { %>
<%- include('_components', { component: 'dropdown', id: 'rfStartup-dropdown', inputId: 'ceqStartup', label: 'RF+', cssClass: '', placeholder: 'Disabled', <%- include('_components', { component: 'dropdown', id: 'rfStartup-dropdown', inputId: 'ceqStartup', label: 'RF+', cssClass: '', placeholder: 'Disabled',
options: [ options: [
{ value: '0', label: 'Disabled' }, { value: '0', label: 'Disabled' },
{ value: '1', label: 'Enabled' }, { value: '1', label: 'Enabled' },
] ]
}) %><br> }) %><br>
<%- include('_components', { component: 'dropdown', id: 'ifStartup-dropdown', inputId: 'imsStartup', label: 'IF+', cssClass: '', placeholder: 'Disabled', <%- include('_components', { component: 'dropdown', id: 'ifStartup-dropdown', inputId: 'imsStartup', label: 'IF+', cssClass: '', placeholder: 'Disabled',
options: [ options: [
{ value: '0', label: 'Disabled' }, { value: '0', label: 'Disabled' },
{ value: '1', label: 'Enabled' }, { value: '1', label: 'Enabled' },
] ]
}) %><br> }) %><br>
<% } %> <% } %>
<%- include('_components', { component: 'dropdown', id: 'stereoStartup-dropdown', inputId: 'stereoStartup', label: 'Stereo Mode', cssClass: '', placeholder: 'Stereo (Default)', <%- include('_components', { component: 'dropdown', id: 'stereoStartup-dropdown', inputId: 'stereoStartup', label: 'Stereo Mode', cssClass: '', placeholder: 'Stereo (Default)',
options: [ options: [
{ value: '0', label: 'Stereo (Default)' }, { value: '0', label: 'Stereo (Default)' },
{ value: '1', label: 'Mono' }, { value: '1', label: 'Mono' },
@@ -607,7 +607,7 @@
}) %><br> }) %><br>
</div> </div>
<div class="panel-100-real p-bottom-20 no-bg"> <div class="panel-100-real p-bottom-20 no-bg">
<%- include('_components', { component: 'dropdown', id: 'antennaStartup-dropdown', inputId: 'antennaStartup', label: 'Antenna', cssClass: '', placeholder: 'Antenna 0 (Default)', <%- include('_components', { component: 'dropdown', id: 'antennaStartup-dropdown', inputId: 'antennaStartup', label: 'Antenna', cssClass: '', placeholder: 'Antenna 0 (Default)',
options: [ options: [
{ value: '0', label: 'Antenna 0 (Default)' }, { value: '0', label: 'Antenna 0 (Default)' },
{ value: '1', label: 'Antenna 1' }, { value: '1', label: 'Antenna 1' },
@@ -623,21 +623,21 @@
<h3>Empty server defaults</h3> <h3>Empty server defaults</h3>
<p>These settings will apply once the last user disconnects from the server, so the server can be ready for a new user with default settings.</p> <p>These settings will apply once the last user disconnects from the server, so the server can be ready for a new user with default settings.</p>
<div class="flex-container flex-center p-20"> <div class="flex-container flex-center p-20">
<%- include('_components', { component: 'dropdown', id: 'bwAutoNoUsers-dropdown', inputId: 'bwAutoNoUsers', label: 'Auto BW', cssClass: '', placeholder: 'Unchanged', <%- include('_components', { component: 'dropdown', id: 'bwAutoNoUsers-dropdown', inputId: 'bwAutoNoUsers', label: 'Auto BW', cssClass: '', placeholder: 'Unchanged',
options: [ options: [
{ value: '0', label: 'Unchanged' }, { value: '0', label: 'Unchanged' },
{ value: '1', label: 'Enabled' }, { value: '1', label: 'Enabled' },
] ]
}) %><br> }) %><br>
<% if (device === 'tef') { %> <% if (device === 'tef') { %>
<%- include('_components', { component: 'dropdown', id: 'ceqNoUsers-dropdown', inputId: 'ceqNoUsers', label: 'cEQ', cssClass: '', placeholder: 'Unchanged', <%- include('_components', { component: 'dropdown', id: 'ceqNoUsers-dropdown', inputId: 'ceqNoUsers', label: 'cEQ', cssClass: '', placeholder: 'Unchanged',
options: [ options: [
{ value: '0', label: 'Unchanged' }, { value: '0', label: 'Unchanged' },
{ value: '1', label: 'Disabled' }, { value: '1', label: 'Disabled' },
{ value: '2', label: 'Enabled' }, { value: '2', label: 'Enabled' },
] ]
}) %><br> }) %><br>
<%- include('_components', { component: 'dropdown', id: 'imsNoUsers-dropdown', inputId: 'imsNoUsers', label: 'iMS', cssClass: '', placeholder: 'Unchanged', <%- include('_components', { component: 'dropdown', id: 'imsNoUsers-dropdown', inputId: 'imsNoUsers', label: 'iMS', cssClass: '', placeholder: 'Unchanged',
options: [ options: [
{ value: '0', label: 'Unchanged' }, { value: '0', label: 'Unchanged' },
{ value: '1', label: 'Disabled' }, { value: '1', label: 'Disabled' },
@@ -645,14 +645,14 @@
] ]
}) %><br> }) %><br>
<% } else if (device === 'xdr') { %> <% } else if (device === 'xdr') { %>
<%- include('_components', { component: 'dropdown', id: 'rfNoUsers-dropdown', inputId: 'ceqNoUsers', label: 'RF+', cssClass: '', placeholder: 'Unchanged', <%- include('_components', { component: 'dropdown', id: 'rfNoUsers-dropdown', inputId: 'ceqNoUsers', label: 'RF+', cssClass: '', placeholder: 'Unchanged',
options: [ options: [
{ value: '0', label: 'Unchanged' }, { value: '0', label: 'Unchanged' },
{ value: '1', label: 'Disabled' }, { value: '1', label: 'Disabled' },
{ value: '2', label: 'Enabled' }, { value: '2', label: 'Enabled' },
] ]
}) %><br> }) %><br>
<%- include('_components', { component: 'dropdown', id: 'ifNoUsers-dropdown', inputId: 'imsNoUsers', label: 'IF+', cssClass: '', placeholder: 'Unchanged', <%- include('_components', { component: 'dropdown', id: 'ifNoUsers-dropdown', inputId: 'imsNoUsers', label: 'IF+', cssClass: '', placeholder: 'Unchanged',
options: [ options: [
{ value: '0', label: 'Unchanged' }, { value: '0', label: 'Unchanged' },
{ value: '1', label: 'Disabled' }, { value: '1', label: 'Disabled' },
@@ -660,7 +660,7 @@
] ]
}) %><br> }) %><br>
<% } %> <% } %>
<%- include('_components', { component: 'dropdown', id: 'stereoNoUsers-dropdown', inputId: 'stereoNoUsers', label: 'Stereo Mode', cssClass: '', placeholder: 'Unchanged', <%- include('_components', { component: 'dropdown', id: 'stereoNoUsers-dropdown', inputId: 'stereoNoUsers', label: 'Stereo Mode', cssClass: '', placeholder: 'Unchanged',
options: [ options: [
{ value: '0', label: 'Unchanged' }, { value: '0', label: 'Unchanged' },
{ value: '1', label: 'Stereo' }, { value: '1', label: 'Stereo' },
@@ -670,7 +670,7 @@
</div> </div>
<div class="panel-100-real p-bottom-20 no-bg"> <div class="panel-100-real p-bottom-20 no-bg">
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Delayed Antenna Change', id: 'antennaNoUsersDelay'}) %><br> <%- include('_components', {component: 'checkbox', cssClass: '', label: 'Delayed Antenna Change', id: 'antennaNoUsersDelay'}) %><br>
<%- include('_components', { component: 'dropdown', id: 'antennaNoUsers-dropdown', inputId: 'antennaNoUsers', label: 'Antenna', cssClass: '', placeholder: 'Unchanged', <%- include('_components', { component: 'dropdown', id: 'antennaNoUsers-dropdown', inputId: 'antennaNoUsers', label: 'Antenna', cssClass: '', placeholder: 'Unchanged',
options: [ options: [
{ value: '0', label: 'Unchanged' }, { value: '0', label: 'Unchanged' },
{ value: '1', label: 'Antenna 0' }, { value: '1', label: 'Antenna 0' },
@@ -705,7 +705,7 @@
<p>You can also get an tunnel from kuba201 discord, one of the contributors of this version of the application.</p> <p>You can also get an tunnel from kuba201 discord, one of the contributors of this version of the application.</p>
<h4>Main tunnel settings</h4> <h4>Main tunnel settings</h4>
<%- include('_components', {component: 'checkbox', cssClass: 'm-right-10', label: 'Enable tunnel', id: 'tunnel-enabled'}) %><br> <%- include('_components', {component: 'checkbox', cssClass: 'm-right-10', label: 'Enable tunnel', id: 'tunnel-enabled'}) %><br>
<%- include('_components', { component: 'dropdown', id: 'tunnel-regionSelect', inputId: 'tunnel-region', label: 'Official server region', cssClass: '', placeholder: 'Europe', <%- include('_components', { component: 'dropdown', id: 'tunnel-regionSelect', inputId: 'tunnel-region', label: 'Official server region', cssClass: '', placeholder: 'Europe',
options: [ options: [
{ value: 'eu', label: 'Europe' }, { value: 'eu', label: 'Europe' },
{ value: 'us', label: 'Americas' }, { value: 'us', label: 'Americas' },

View File

@@ -48,7 +48,7 @@
<h3 class="settings-heading">Tuner type</h3> <h3 class="settings-heading">Tuner type</h3>
<p class="m-0">Settings a proper device type ensures that the correct interface and settings will load.</p> <p class="m-0">Settings a proper device type ensures that the correct interface and settings will load.</p>
<div class="panel-100 no-bg flex-center" style="max-width: 520px; margin: 10px auto 0;"> <div class="panel-100 no-bg flex-center" style="max-width: 520px; margin: 10px auto 0;">
<%- include('_components', { component: 'dropdown', id: 'device-selector', inputId: 'device', label: 'Device', cssClass: '', placeholder: 'TEF668x / TEA685x', <%- include('_components', { component: 'dropdown', id: 'device-selector', inputId: 'device', label: 'Device', cssClass: '', placeholder: 'TEF668x / TEA685x',
options: tunerProfiles.map(profile => ({ options: tunerProfiles.map(profile => ({
value: profile.id, value: profile.id,
label: profile.label label: profile.label
@@ -64,12 +64,12 @@
<span> <span>
<span class="left-span">Direct</span> <span class="left-span">Direct</span>
<span class="right-span">TCP/IP</span> <span class="right-span">TCP/IP</span>
</span> </span>
</label> </label>
</div> </div>
<div id="tuner-usb" class="top-25"> <div id="tuner-usb" class="top-25">
<p>It's time to choose your serial port.</p> <p>It's time to choose your serial port.</p>
<div class="panel-100 no-bg flex-center"> <div class="panel-100 no-bg flex-center">
<%- include('_components', { <%- include('_components', {
component: 'dropdown', component: 'dropdown',
@@ -82,7 +82,7 @@
value: serialPort.path, value: serialPort.path,
label: `${serialPort.path} - ${serialPort.friendlyName}` label: `${serialPort.path} - ${serialPort.friendlyName}`
})) }))
}) %> }) %>
</div> </div>
</div> </div>
<div class="clearfix"></div> <div class="clearfix"></div>
@@ -103,7 +103,7 @@
<p class="m-0">In this section, we will set up the audio.<br> <p class="m-0">In this section, we will set up the audio.<br>
Choose the audio port your tuner is connected to and desired audio settings here.</p> Choose the audio port your tuner is connected to and desired audio settings here.</p>
<p class="text-gray">Recommended defaults have already been set for the audio quality, you can keep them as-is.</p> <p class="text-gray">Recommended defaults have already been set for the audio quality, you can keep them as-is.</p>
<div class="panel-100 no-bg p-bottom-20 flex-container flex-center"> <div class="panel-100 no-bg p-bottom-20 flex-container flex-center">
<%- include('_components', { <%- include('_components', {
component: 'dropdown', component: 'dropdown',
@@ -122,16 +122,16 @@
label: `${device.name}` label: `${device.name}`
})) }))
] ]
}) %> }) %>
<%- include('_components', { component: 'dropdown', id: 'audio-channels-dropdown', inputId: 'audio-audioChannels', label: 'Audio channels', cssClass: '', placeholder: 'Stereo', <%- include('_components', { component: 'dropdown', id: 'audio-channels-dropdown', inputId: 'audio-audioChannels', label: 'Audio channels', cssClass: '', placeholder: 'Stereo',
options: [ options: [
{ value: '2', label: 'Stereo' }, { value: '2', label: 'Stereo' },
{ value: '1', label: 'Mono' } { value: '1', label: 'Mono' }
] ]
}) %> }) %>
<%- include('_components', { component: 'dropdown', id: 'audio-quality-dropdown', inputId: 'audio-audioBitrate', label: 'Audio quality', cssClass: '', placeholder: '128kbps (standard)', <%- include('_components', { component: 'dropdown', id: 'audio-quality-dropdown', inputId: 'audio-audioBitrate', label: 'Audio quality', cssClass: '', placeholder: '128kbps (standard)',
options: [ options: [
{ value: '64k', label: '64kbps (lowest quality)' }, { value: '64k', label: '64kbps (lowest quality)' },
{ value: '96k', label: '96kbps (low quality)' }, { value: '96k', label: '96kbps (low quality)' },
@@ -168,7 +168,7 @@
<br> <br>
<label for="identification-tunerDesc" style="width: 100%;max-width: 768px; margin: auto;">Webserver description:</label> <label for="identification-tunerDesc" style="width: 100%;max-width: 768px; margin: auto;">Webserver description:</label>
<textarea id="identification-tunerDesc" name="webserver-desc" class="br-15" placeholder="Fill the server description here. You can put useful info here such as your antenna setup. You can use simple markdown." maxlength="255"></textarea> <textarea id="identification-tunerDesc" name="webserver-desc" class="br-15" placeholder="Fill the server description here. You can put useful info here such as your antenna setup. You can use simple markdown." maxlength="255"></textarea>
<h3 class="settings-heading">Location</h3> <h3 class="settings-heading">Location</h3>
<p>Location info is useful for automatic identification of stations using RDS.</p> <p>Location info is useful for automatic identification of stations using RDS.</p>
<div class="panel-100 no-bg flex-container flex-center"> <div class="panel-100 no-bg flex-container flex-center">