You've already forked fm-dx-webserver
mirror of
https://github.com/KubaPro010/fm-dx-webserver.git
synced 2026-02-26 22:13:53 +01:00
admin dashboard, bugfixes, cleanup
This commit is contained in:
@@ -50,7 +50,7 @@ h4 {
|
||||
border-radius: 30px;
|
||||
padding: 5px 25px;
|
||||
z-index: 1000;
|
||||
opacity:var(--color-main);
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
@@ -248,6 +248,42 @@ label {
|
||||
opacity: 0; /* Make the overlay invisible */
|
||||
}
|
||||
|
||||
.admin-quick-dashboard {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: -96px;
|
||||
width: 96px;
|
||||
height: 286px;
|
||||
background-color: var(--color-2);
|
||||
margin: auto 0;
|
||||
border-radius: 30px;
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.admin-quick-dashboard .icon {
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
margin: 10px auto;
|
||||
color: var(--color-1);
|
||||
background-color: var(--color-3);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 24px;
|
||||
border-radius: 10px;
|
||||
transition: 0.3s ease-in-out background-color;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.admin-quick-dashboard .icon.active {
|
||||
background-color: var(--color-4);
|
||||
}
|
||||
|
||||
.admin-quick-dashboard .icon:hover {
|
||||
background-color: var(--color-5);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
canvas, #flags-container {
|
||||
display: none;
|
||||
|
||||
@@ -52,8 +52,10 @@
|
||||
<audio id="audioTag"></audio>
|
||||
<div id="wrapper">
|
||||
<div class="panel-100 no-bg tuner-info">
|
||||
<h1 id="tuner-name"><%= tunerName %> <% if (!publicTuner) { %><i class="fa-solid fa-key pointer" title="Only people with tune password can tune."></i>
|
||||
<% } else if (tunerLock) { %><i class="fa-solid fa-lock pointer" title="Tuner is currently locked to admin."></i><% } %>
|
||||
<h1 id="tuner-name"><%= tunerName %>
|
||||
<% if (!publicTuner) { %><i class="fa-solid fa-key pointer tooltip" data-tooltip="Only people with tune password can tune."></i>
|
||||
<% } if (tunerLock) { %><i class="fa-solid fa-lock pointer tooltip" data-tooltip="Tuner is currently locked to admin."></i>
|
||||
<% } %>
|
||||
</h1>
|
||||
<p id="tuner-desc">
|
||||
<%- tunerDesc %>
|
||||
@@ -74,7 +76,7 @@
|
||||
<div class="panel-10 no-bg h-100 m-0 m-right-20 hide-phone" style="width: 100px;margin-right: 20px !important;">
|
||||
<button class="playbutton" aria-label="Play / Stop Button"><i class="fa-solid fa-play fa-lg"></i></button>
|
||||
</div>
|
||||
<div class="panel-100 m-0 hover-brighten flex-center" id="ps-container" style="height: 90px;" data-tooltip="Clicking on the RDS PS will copy the RDS info into the clipboard.">
|
||||
<div class="panel-100 m-0 hover-brighten flex-center tooltip" id="ps-container" style="height: 90px;" data-tooltip="Clicking on the RDS PS will copy the RDS info into the clipboard.">
|
||||
<span class="text-big" id="data-ps"></span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -91,7 +93,7 @@
|
||||
</div>
|
||||
<span id="stereo-container" class="pointer" style="position: relative;">
|
||||
<span style="margin-left: 20px;" class="data-st">ST</span>
|
||||
<span class="overlay" data-tooltip="Stereo / Mono toggle. <br><strong>Click to toggle."></span>
|
||||
<span class="overlay tooltip" data-tooltip="Stereo / Mono toggle. <br><strong>Click to toggle."></span>
|
||||
</span>
|
||||
<span style="margin-left: 15px;" class="data-ms">MS</span>
|
||||
</h3>
|
||||
@@ -99,7 +101,7 @@
|
||||
</div>
|
||||
|
||||
<div class="flex-container">
|
||||
<div class="panel-33 hover-brighten" id="pi-code-container" data-tooltip="Clicking on the PI code will show the current station on a map.">
|
||||
<div class="panel-33 hover-brighten tooltip" id="pi-code-container" data-tooltip="Clicking on the PI code will show the current station on a map.">
|
||||
<h2>PI CODE</h2>
|
||||
<span id="data-pi" class="text-big text-uppercase"></span>
|
||||
</div>
|
||||
@@ -144,12 +146,12 @@
|
||||
<% } %>
|
||||
|
||||
<div class="panel-100 no-bg h-100 m-0 button-eq">
|
||||
<% if (device == 'tef') { %><button id="data-eq" style="border-radius: 30px 0px 0px 30px;" 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 == 'xdr') { %><button id="data-eq" style="border-radius: 30px 0px 0px 30px;" aria-label="RF+ Filter" data-tooltip="<strong>The RF+ filter increases gain by 5dB</strong>"><span class="text-bold">RF+</span></button><% } %>
|
||||
<% if (device == 'tef') { %><button id="data-eq" style="border-radius: 30px 0px 0px 30px;" class="tooltip" 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 == 'xdr') { %><button id="data-eq" style="border-radius: 30px 0px 0px 30px;" class="tooltip" aria-label="RF+ Filter" data-tooltip="<strong>The RF+ filter increases gain by 5dB</strong>"><span class="text-bold">RF+</span></button><% } %>
|
||||
</div>
|
||||
<div class="panel-100 no-bg h-100 m-0 button-ims">
|
||||
<% if (device == 'tef') { %><button id="data-ims" style="border-radius: 0px 30px 30px 0px;" aria-label="iMS + Filter" data-tooltip="<strong>The iMS filter reduces multipath audio artifacts.</strong><br><br>It's recommended to leave it on most of the time."><span class="text-bold">iMS</span></button><% } %>
|
||||
<% if (device == 'xdr') { %><button id="data-ims" style="border-radius: 0px 30px 30px 0px;" aria-label="IF+ Filter" data-tooltip="<strong>The IF+ filter increases gain by 6dB</strong>"><span class="text-bold">IF+</span></button><% } %>
|
||||
<% if (device == 'tef') { %><button id="data-ims" style="border-radius: 0px 30px 30px 0px;" class="tooltip" aria-label="iMS + Filter" data-tooltip="<strong>The iMS filter reduces multipath audio artifacts.</strong><br><br>It's recommended to leave it on most of the time."><span class="text-bold">iMS</span></button><% } %>
|
||||
<% if (device == 'xdr') { %><button id="data-ims" style="border-radius: 0px 30px 30px 0px;" class="tooltip" aria-label="IF+ Filter" data-tooltip="<strong>The IF+ filter increases gain by 6dB</strong>"><span class="text-bold">IF+</span></button><% } %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -173,7 +175,7 @@
|
||||
<hr class="hide-desktop">
|
||||
</div>
|
||||
|
||||
<div class="panel-33 hover-brighten" data-tooltip="This panel contains the current TX info when RDS is loaded.<br><strong>Clicking on this panel copies the info into the clipboard.</strong>">
|
||||
<div class="panel-33 hover-brighten tooltip" data-tooltip="This panel contains the current TX info when RDS is loaded.<br><strong>Clicking on this panel copies the info into the clipboard.</strong>">
|
||||
<div id="data-station-container">
|
||||
<h2 style="margin-top: 0;" class="mb-0">
|
||||
<span id="data-station-name"></span>
|
||||
@@ -228,6 +230,20 @@
|
||||
<% } %>
|
||||
<button id="users-online-container" class="hide-phone" aria-label="Online users"><i class="fa-solid fa-user"></i> <span class="users-online"></span></button>
|
||||
|
||||
<% if (isAdminAuthenticated) { %>
|
||||
<div class="admin-quick-dashboard hide-phone">
|
||||
<div class="icon tooltip <% if (tunerLock) { %>active<% } %>" id="dashboard-lock-admin" onClick="toggleAdminLock()" data-tooltip="Toggle admin lock<br>Lasts until restart">
|
||||
<i class="fa-solid fa-lock"></i>
|
||||
</div>
|
||||
<div class="icon tooltip <% if (!publicTuner) { %>active<% } %>" id="dashboard-lock-tune" onClick="togglePasswordLock()" data-tooltip="Toggle password lock<br>Lasts until restart">
|
||||
<i class="fa-solid fa-key"></i>
|
||||
</div>
|
||||
<div class="icon tooltip" data-tooltip="Go to admin menu" onClick="window.open('./setup', '_blank').focus();">
|
||||
<i class="fa-solid fa-user"></i>
|
||||
</div>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
<div id="myModal" class="modal">
|
||||
<div class="modal-panel">
|
||||
<div class="flex-container flex-phone" style="height: calc(100% - 100px)">
|
||||
@@ -285,7 +301,7 @@
|
||||
|
||||
<% if (isAdminAuthenticated) { %>
|
||||
<p>You are logged in as an adminstrator.<br>
|
||||
<a href="./setup">Setup</a> • <a class="logout-link" href="#">Logout</a>
|
||||
<a href="./setup" target="_blank">Setup</a> • <a class="logout-link" href="#">Logout</a>
|
||||
</p>
|
||||
<% } else if (isTuneAuthenticated) { %>
|
||||
<p>You are logged in and can control the receiver.<br><a class="logout-link" href="#">Logout</a></p>
|
||||
@@ -360,9 +376,5 @@
|
||||
</div>
|
||||
|
||||
<script src="js/webserver.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/screenshot-capture/2.0.0/screenshot-capture.min.js"></script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -45,6 +45,8 @@ function submitData() {
|
||||
return $(this).text() === $('#device-type').val();
|
||||
}).data('value') || "tef");
|
||||
|
||||
const softwareMode = $('#audio-software-mode').is("checked") || false;
|
||||
|
||||
const tunerName = $('#webserver-name').val() || 'FM Tuner';
|
||||
const tunerDesc = $('#webserver-desc').val() || 'Default FM tuner description';
|
||||
const broadcastTuner = $("#broadcast-tuner").is(":checked");
|
||||
@@ -84,6 +86,7 @@ function submitData() {
|
||||
audioDevice,
|
||||
audioChannels,
|
||||
audioBitrate,
|
||||
softwareMode,
|
||||
},
|
||||
identification: {
|
||||
tunerName,
|
||||
@@ -202,6 +205,8 @@ function submitData() {
|
||||
$("#audio-quality").val(selectedQuality.text());
|
||||
}
|
||||
|
||||
$('#audio-software-switch').prop("checked", data.audio.softwareMode || false);
|
||||
|
||||
$('#webserver-name').val(data.identification.tunerName);
|
||||
$('#webserver-desc').val(data.identification.tunerDesc);
|
||||
$("#broadcast-tuner").prop("checked", data.identification.broadcastTuner);
|
||||
|
||||
@@ -28,6 +28,21 @@ const usa_programmes = [
|
||||
$(document).ready(function () {
|
||||
var canvas = $('#signal-canvas')[0];
|
||||
|
||||
var $panel = $('.admin-quick-dashboard');
|
||||
var panelWidth = $panel.outerWidth();
|
||||
|
||||
$(document).mousemove(function(e) {
|
||||
var mouseX = e.pageX;
|
||||
var panelLeft = parseInt($panel.css('left'));
|
||||
|
||||
if (mouseX <= 10 || (panelLeft === 4 && mouseX <= 100)) {
|
||||
$panel.css('left', '4px');
|
||||
} else {
|
||||
$panel.css('left', -panelWidth);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
canvas.width = canvas.parentElement.clientWidth;
|
||||
canvas.height = canvas.parentElement.clientHeight;
|
||||
|
||||
@@ -49,9 +64,9 @@ $(document).ready(function () {
|
||||
const textInput = $('#commandinput');
|
||||
|
||||
textInput.on('change', function (event) {
|
||||
const inputValue = textInput.val();
|
||||
const inputValue = Number(textInput.val());
|
||||
// Check if the user agent contains 'iPhone'
|
||||
if (/iPhone/i.test(navigator.userAgent) && socket.readyState === WebSocket.OPEN) {
|
||||
if (/iPhone/i.test(navigator.userAgent)) {
|
||||
socket.send("T" + (inputValue * 1000));
|
||||
// Clear the input field if needed
|
||||
textInput.val('');
|
||||
@@ -384,26 +399,7 @@ function checkKey(e) {
|
||||
case 82: // RDS Reset (R key)
|
||||
tuneTo(Number(currentFreq));
|
||||
break;
|
||||
case 83: // Screenshot (S key)
|
||||
screenshotCapture.capture().then(function (dataUrl) {
|
||||
// Create an input element to hold the data URL temporarily
|
||||
var aux = $('<input>').attr({
|
||||
type: 'text',
|
||||
value: dataUrl
|
||||
});
|
||||
|
||||
// Append the input element to the body, select its contents, and copy them to the clipboard
|
||||
$('body').append(aux);
|
||||
aux.select();
|
||||
document.execCommand('copy');
|
||||
aux.remove();
|
||||
|
||||
// Alert the user that the screenshot has been copied to the clipboard
|
||||
alert('Screenshot copied to clipboard!');
|
||||
}).catch(function (error) {
|
||||
console.error('Error capturing screenshot:', error);
|
||||
});
|
||||
|
||||
case 83: // Screenshot (S key)
|
||||
break;
|
||||
case 38:
|
||||
socket.send("T" + (Math.round(currentFreq*1000) + ((currentFreq > 30) ? 10 : 1)));
|
||||
@@ -758,19 +754,51 @@ function toggleForcedStereo() {
|
||||
socket.send(message);
|
||||
}
|
||||
|
||||
function toggleAdminLock() {
|
||||
let $adminLockButton = $('#dashboard-lock-admin');
|
||||
|
||||
if($adminLockButton.hasClass('active')) {
|
||||
socket.send('wL0');
|
||||
$adminLockButton.removeClass('active');
|
||||
} else {
|
||||
socket.send('wL1');
|
||||
$adminLockButton.addClass('active');
|
||||
}
|
||||
}
|
||||
|
||||
function togglePasswordLock() {
|
||||
let $passwordLockButton = $('#dashboard-lock-tune');
|
||||
|
||||
if($passwordLockButton.hasClass('active')) {
|
||||
socket.send('wT0');
|
||||
$passwordLockButton.removeClass('active');
|
||||
} else {
|
||||
socket.send('wT1');
|
||||
$passwordLockButton.addClass('active');
|
||||
}
|
||||
}
|
||||
|
||||
function initTooltips() {
|
||||
$('[data-tooltip]').hover(function(e){
|
||||
$('.tooltip').hover(function(e){
|
||||
var tooltipText = $(this).data('tooltip');
|
||||
var tooltip = $('<div class="tooltiptext"></div>').html(tooltipText);
|
||||
$('body').append(tooltip);
|
||||
|
||||
// Add a delay of 500 milliseconds before creating and appending the tooltip
|
||||
$(this).data('timeout', setTimeout(() => {
|
||||
var tooltip = $('<div class="tooltiptext"></div>').html(tooltipText);
|
||||
$('body').append(tooltip);
|
||||
|
||||
var tooltipWidth = tooltip.outerWidth();
|
||||
var tooltipHeight = tooltip.outerHeight();
|
||||
var posX = e.pageX - tooltipWidth / 2;
|
||||
var posY = e.pageY - tooltipHeight - 10;
|
||||
var posX = e.pageX;
|
||||
var posY = e.pageY;
|
||||
|
||||
tooltip.css({ top: posY, left: posX, opacity: 0.9 });
|
||||
var tooltipWidth = tooltip.outerWidth();
|
||||
var tooltipHeight = tooltip.outerHeight();
|
||||
posX -= tooltipWidth / 2;
|
||||
posY -= tooltipHeight + 10;
|
||||
tooltip.css({ top: posY, left: posX, opacity: 1 }); // Set opacity to 1
|
||||
}, 500));
|
||||
}, function() {
|
||||
// Clear the timeout if the mouse leaves before the delay completes
|
||||
clearTimeout($(this).data('timeout'));
|
||||
$('.tooltiptext').remove();
|
||||
}).mousemove(function(e){
|
||||
var tooltipWidth = $('.tooltiptext').outerWidth();
|
||||
@@ -780,4 +808,4 @@ function initTooltips() {
|
||||
|
||||
$('.tooltiptext').css({ top: posY, left: posX });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ var day = currentDate.getDate();
|
||||
var month = currentDate.getMonth() + 1; // Months are zero-indexed, so add 1
|
||||
var year = currentDate.getFullYear();
|
||||
var formattedDate = day + '/' + month + '/' + year;
|
||||
var currentVersion = 'v1.1.4 [' + formattedDate + ']';
|
||||
var currentVersion = 'v1.1.5 [' + formattedDate + ']';
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -237,6 +237,11 @@
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group checkbox bottom-20">
|
||||
<input type="checkbox" id="audio-software-switch">
|
||||
<label for="audio-software-switch">ALSA software mode (plughw) - LINUX ONLY</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -352,6 +357,7 @@
|
||||
<li class="option" data-value="tef">TEF668x / TEA685x</li>
|
||||
<li class="option" data-value="xdr">XDR (F1HD / S10HDiP)</li>
|
||||
<li class="option" data-value="sdr">SDR (RTL-SDR / AirSpy)</li>
|
||||
<li class="option" data-value="sdr">Other</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
<li class="option" data-value="tef">TEF668x / TEA685x</li>
|
||||
<li class="option" data-value="xdr">XDR (F1HD / S10HDiP)</li>
|
||||
<li class="option" data-value="sdr">SDR (RTL-SDR / AirSpy)</li>
|
||||
<li class="option" data-value="other">Other</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user