You've already forked fm-dx-webserver
mirror of
https://github.com/KubaPro010/fm-dx-webserver.git
synced 2026-02-27 06:23:53 +01:00
bugfixes / sporadic e logging
This commit is contained in:
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "fm-dx-webserver",
|
"name": "fm-dx-webserver",
|
||||||
"version": "1.3.3.1",
|
"version": "1.3.4",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "fm-dx-webserver",
|
"name": "fm-dx-webserver",
|
||||||
"version": "1.3.3.1",
|
"version": "1.3.4",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mapbox/node-pre-gyp": "1.0.11",
|
"@mapbox/node-pre-gyp": "1.0.11",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "fm-dx-webserver",
|
"name": "fm-dx-webserver",
|
||||||
"version": "1.3.3.1",
|
"version": "1.3.4",
|
||||||
"description": "FM DX Webserver",
|
"description": "FM DX Webserver",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -401,7 +401,7 @@ function handleData(wss, receivedData, rdsWss) {
|
|||||||
// Get the received TX info
|
// Get the received TX info
|
||||||
fetchTx(parseFloat(dataToSend.freq).toFixed(1), dataToSend.pi, dataToSend.ps)
|
fetchTx(parseFloat(dataToSend.freq).toFixed(1), dataToSend.pi, dataToSend.ps)
|
||||||
.then((currentTx) => {
|
.then((currentTx) => {
|
||||||
if (currentTx && currentTx.station !== undefined) {
|
if (currentTx && currentTx.station !== undefined && parseInt(currentTx.distance) < 4000) {
|
||||||
dataToSend.txInfo = {
|
dataToSend.txInfo = {
|
||||||
tx: currentTx.station,
|
tx: currentTx.station,
|
||||||
pol: currentTx.pol,
|
pol: currentTx.pol,
|
||||||
|
|||||||
@@ -21,11 +21,13 @@ router.get('/', (req, res) => {
|
|||||||
let requestIp = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
let requestIp = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
||||||
|
|
||||||
const normalizedIp = requestIp?.replace(/^::ffff:/, '');
|
const normalizedIp = requestIp?.replace(/^::ffff:/, '');
|
||||||
const isBanned = serverConfig.webserver.banlist.some(banEntry => banEntry[0] === normalizedIp);
|
const ipList = normalizedIp.split(',').map(ip => ip.trim()); // in case there are multiple IPs (proxy), we need to check all of them
|
||||||
|
|
||||||
|
const isBanned = ipList.some(ip => serverConfig.webserver.banlist.some(banEntry => banEntry[0] === ip));
|
||||||
|
|
||||||
if (isBanned) {
|
if (isBanned) {
|
||||||
res.render('403');
|
res.render('403');
|
||||||
logInfo(`Web client (${requestIp}) is banned`);
|
logInfo(`Web client (${normalizedIp}) is banned`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,7 +393,8 @@ router.get('/log_fmlist', (req, res) => {
|
|||||||
client: {
|
client: {
|
||||||
request_ip: clientIp
|
request_ip: clientIp
|
||||||
},
|
},
|
||||||
log_msg: "Logged PS: " + dataHandler.dataToSend.ps.replace(/\s+/g, '_') + ", PI: " + dataHandler.dataToSend.pi + ", Signal: " + dataHandler.dataToSend.sig.toFixed(0) + " dBf",
|
type: req.query.type ? req.query.type : 'tropo',
|
||||||
|
log_msg: "Logged PS: " + dataHandler.dataToSend.ps.replace(/\s+/g, '_') + ", PI: " + dataHandler.dataToSend.pi + ", Signal: " + (dataHandler.dataToSend.sig - 11.25).toFixed(0) + " dBµV",
|
||||||
});
|
});
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ async function processData(data, piCode, rdsPs) {
|
|||||||
weightDistance = Math.abs(distance.distanceKm - 1500);
|
weightDistance = Math.abs(distance.distanceKm - 1500);
|
||||||
}
|
}
|
||||||
let erp = station.erp && station.erp > 0 ? station.erp : 1;
|
let erp = station.erp && station.erp > 0 ? station.erp : 1;
|
||||||
let extraWeight = erp > 10 && distance.distanceKm <= 2500 ? 0.3 : 0;
|
let extraWeight = erp >= 10 && distance.distanceKm <= 2500 ? 0.5 : 0;
|
||||||
const score = ((10 * Math.log10(erp * 1000)) / weightDistance) + extraWeight;
|
const score = ((10 * Math.log10(erp * 1000)) / weightDistance) + extraWeight;
|
||||||
if (score > maxScore) {
|
if (score > maxScore) {
|
||||||
maxScore = score;
|
maxScore = score;
|
||||||
|
|||||||
@@ -302,7 +302,7 @@ pre {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
border: 2px solid var(--color-3);
|
border: 2px solid var(--color-text);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -333,6 +333,52 @@ select:hover {
|
|||||||
background: var(--color-5);
|
background: var(--color-5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.popup {
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup .popup-content {
|
||||||
|
visibility: hidden;
|
||||||
|
width: 230px;
|
||||||
|
background-color: var(--color-2-transparent);
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
color: var(--color-text);;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 15px;
|
||||||
|
padding: 8px;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
top: 125%;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -115px;
|
||||||
|
border: 3px solid var(--color-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup .show {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
button[disabled] .popup-content {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup .popup-content::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
bottom: calc(100% + 3px);
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -5px;
|
||||||
|
border-width: 5px;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: transparent transparent var(--color-3) transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@media only screen and (max-width: 768px) {
|
@media only screen and (max-width: 768px) {
|
||||||
#tune-buttons input[type="text"] {
|
#tune-buttons input[type="text"] {
|
||||||
background-color: var(--color-1-transparent);
|
background-color: var(--color-1-transparent);
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ body.modal-open {
|
|||||||
|
|
||||||
.modal-panel, .modal-panel-chat {
|
.modal-panel, .modal-panel-chat {
|
||||||
max-height: 100vh;
|
max-height: 100vh;
|
||||||
overflow-y: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal {
|
.modal {
|
||||||
@@ -99,6 +98,7 @@ body.modal-open {
|
|||||||
width: 64px;
|
width: 64px;
|
||||||
background-color: var(--color-1);
|
background-color: var(--color-1);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-panel-content {
|
.modal-panel-content {
|
||||||
|
|||||||
@@ -70,9 +70,9 @@
|
|||||||
|
|
||||||
<div id="flags-container-desktop" class="panel-33 user-select-none">
|
<div id="flags-container-desktop" class="panel-33 user-select-none">
|
||||||
<h2 class="show-phone">
|
<h2 class="show-phone">
|
||||||
<div class="data-pty text-color-default"></div>
|
<div class="data-pty color-4"></div>
|
||||||
</h2>
|
</h2>
|
||||||
<h3 style="margin-top:0;margin-bottom:0;" class="color-4 flex-center">
|
<h3 style="margin-top:0;margin-bottom:0;" class="text-color-default flex-center">
|
||||||
<span class="data-tp">TP</span>
|
<span class="data-tp">TP</span>
|
||||||
<span style="margin-left: 15px;" class="data-ta">TA</span>
|
<span style="margin-left: 15px;" class="data-ta">TA</span>
|
||||||
<div style="display:inline-block">
|
<div style="display:inline-block">
|
||||||
@@ -231,9 +231,16 @@
|
|||||||
</div>
|
</div>
|
||||||
<% } %>
|
<% } %>
|
||||||
<% if (fmlist_integration == true) { %>
|
<% if (fmlist_integration == true) { %>
|
||||||
<button class="tooltip bg-color-4" id="log-fmlist"
|
<button class="tooltip bg-color-4 popup" id="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"
|
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></button>
|
style="width: 80px; height: 48px;margin-left: 15px !important;">
|
||||||
|
<i class="fa-solid fa-flag fa-lg"></i>
|
||||||
|
<span class="popup-content">
|
||||||
|
Choose the DX propagation type:<br>
|
||||||
|
<a class="top-10 bg-color-3 text-bold" style="padding: 10px; border-radius: 15px 0 0 15px; display: inline-block;" id="log-fmlist-tropo">Tropo</a><!--
|
||||||
|
--><a class="top-10 bg-color-3 text-bold" style="padding: 10px; border-radius: 0 15px 15px 0; display: inline-block;" id="log-fmlist-sporadice">Sporadic-E</a>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
<% } %>
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -461,15 +468,15 @@
|
|||||||
<div class="modal-panel-chat">
|
<div class="modal-panel-chat">
|
||||||
<div class="modal-panel-sidebar hover-brighten flex-center text-medium-big closeModal" role="button" aria-label="Close chat" tabindex="0"><i class="fa-solid fa-chevron-down"></i></div>
|
<div class="modal-panel-sidebar hover-brighten flex-center text-medium-big closeModal" role="button" aria-label="Close chat" tabindex="0"><i class="fa-solid fa-chevron-down"></i></div>
|
||||||
<div class="modal-panel-content text-left">
|
<div class="modal-panel-content text-left">
|
||||||
<div style="text-align: center;">
|
<div style="text-align: center;white-space-collapse: collapse;">
|
||||||
<input type="text" id="chat-nickname" name="chat-nickname" placeholder="Nickname">
|
<input type="text" id="chat-nickname" name="chat-nickname" placeholder="Nickname" style="border-radius: 15px 0 0 15px;padding-top:0;padding-bottom:0;border: 2px solid var(--color-4)">
|
||||||
<button class="br-0 w-100 top-10" style="height: 48px" id="chat-nickname-save">Save</button>
|
<button class="br-0 w-100 top-10" style="height: 48px; border-radius: 0 15px 15px 0;margin-left:-3px;" id="chat-nickname-save">Save</button>
|
||||||
<p style="margin: 5px;">
|
<p style="margin: 5px;" class="text-small">
|
||||||
Current identity: <span style="color: #bada55;" id="chat-admin"></span> <strong id="chat-identity-nickname"></strong>
|
Current identity: <span style="color: #bada55;" id="chat-admin"></span> <strong id="chat-identity-nickname"></strong>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="chat-chatbox" class="bg-color-1" style="height: 270px;padding: 10px;overflow-y: auto;">
|
<div id="chat-chatbox" class="bg-color-1" style="height: 258px;padding: 10px;overflow-y: auto;">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex-container flex-phone" style="align-content: stretch;">
|
<div class="flex-container flex-phone" style="align-content: stretch;">
|
||||||
|
|||||||
@@ -40,12 +40,18 @@ 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 ('audioSession' in navigator) {
|
||||||
|
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 ('audioSession' in navigator) {
|
||||||
|
navigator.audioSession.type = "playback"; // Android background play fix
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$playbutton.addClass('bg-gray').prop('disabled', true);
|
$playbutton.addClass('bg-gray').prop('disabled', true);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|||||||
@@ -42,13 +42,29 @@ function populateFields(data, prefix = "") {
|
|||||||
value = ""; // Convert null to an empty string
|
value = ""; // Convert null to an empty string
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = `${prefix}${prefix ? "-" : ""}${key}`;
|
let id = `${prefix}${prefix ? "-" : ""}${key}`;
|
||||||
const $element = $(`#${id}`);
|
const $element = $(`#${id}`);
|
||||||
|
|
||||||
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
if (typeof value === "object" && value !== null) {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
// Handle arrays correctly
|
||||||
|
value.forEach((item, index) => {
|
||||||
|
const arrayId = `${id}-${index + 1}`;
|
||||||
|
const $arrayElement = $(`#${arrayId}`);
|
||||||
|
|
||||||
|
if ($arrayElement.length) {
|
||||||
|
$arrayElement.val(item);
|
||||||
|
} else {
|
||||||
|
console.log(`Element with id ${arrayId} not found`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// Handle nested objects
|
||||||
populateFields(value, id);
|
populateFields(value, id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!$element.length) {
|
if (!$element.length) {
|
||||||
console.log(`Element with id ${id} not found`);
|
console.log(`Element with id ${id} not found`);
|
||||||
@@ -64,16 +80,6 @@ function populateFields(data, prefix = "") {
|
|||||||
} else {
|
} else {
|
||||||
$element.val(value);
|
$element.val(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key === "plugins" && Array.isArray(value)) {
|
|
||||||
const $options = $element.find('option');
|
|
||||||
$options.each(function() {
|
|
||||||
const dataName = $(this).data('name');
|
|
||||||
if (value.includes(dataName)) {
|
|
||||||
$(this).prop('selected', true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
var currentDate = new Date('Jan 16, 2025 21:00:00');
|
var currentDate = new Date('Feb 9, 2025 18:00:00');
|
||||||
var day = currentDate.getDate();
|
var day = currentDate.getDate();
|
||||||
var month = currentDate.getMonth() + 1; // Months are zero-indexed, so add 1
|
var month = currentDate.getMonth() + 1; // Months are zero-indexed, so add 1
|
||||||
var year = currentDate.getFullYear();
|
var year = currentDate.getFullYear();
|
||||||
var formattedDate = day + '/' + month + '/' + year;
|
var formattedDate = day + '/' + month + '/' + year;
|
||||||
var currentVersion = 'v1.3.3.1 [' + formattedDate + ']';
|
var currentVersion = 'v1.3.4 [' + formattedDate + ']';
|
||||||
|
|
||||||
getInitialSettings();
|
getInitialSettings();
|
||||||
removeUrlParameters();
|
removeUrlParameters();
|
||||||
|
|||||||
@@ -204,33 +204,70 @@ $(document).ready(function () {
|
|||||||
initTooltips();
|
initTooltips();
|
||||||
|
|
||||||
//FMLIST logging
|
//FMLIST logging
|
||||||
|
$('.popup-content').on('click', function(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
$('.popup-content').removeClass('show');
|
||||||
|
});
|
||||||
|
|
||||||
$('#log-fmlist').on('click', function() {
|
$('#log-fmlist').on('click', function() {
|
||||||
|
const logKey = 'fmlistLogChoice';
|
||||||
|
const logTimestampKey = 'fmlistLogTimestamp';
|
||||||
|
const expirationTime = 10 * 60 * 1000;
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
const storedChoice = localStorage.getItem(logKey);
|
||||||
|
const storedTimestamp = localStorage.getItem(logTimestampKey);
|
||||||
|
|
||||||
|
if (storedChoice && storedTimestamp && (now - storedTimestamp < expirationTime)) {
|
||||||
|
sendLog(storedChoice);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsedData.txInfo.dist > 700) {
|
||||||
|
$('#log-fmlist .popup-content').addClass('show'); // Show popup if no valid choice
|
||||||
|
|
||||||
|
$('#log-fmlist-sporadice').off('click').on('click', function () {
|
||||||
|
localStorage.setItem(logKey, './log_fmlist?type=sporadice');
|
||||||
|
localStorage.setItem(logTimestampKey, now);
|
||||||
|
if(parsedData.txInfo.dist > 700) sendLog('./log_fmlist?type=sporadice');
|
||||||
|
$('#log-fmlist .popup-content').removeClass('show');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#log-fmlist-tropo').off('click').on('click', function () {
|
||||||
|
localStorage.setItem(logKey, './log_fmlist?type=tropo');
|
||||||
|
localStorage.setItem(logTimestampKey, now);
|
||||||
|
if(parsedData.txInfo.dist > 700) sendLog('./log_fmlist?type=tropo');
|
||||||
|
$('#log-fmlist .popup-content').removeClass('show');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
sendLog('./log_fmlist');
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendLog(endpoint) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: './log_fmlist',
|
url: endpoint,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
// Show a success toast with the response message
|
|
||||||
sendToast('success', 'Log successful', response, false, true);
|
sendToast('success', 'Log successful', response, false, true);
|
||||||
},
|
},
|
||||||
error: function(xhr) {
|
error: function(xhr) {
|
||||||
let errorMessage;
|
let errorMessage;
|
||||||
|
|
||||||
// Handle different error status codes with custom messages
|
|
||||||
switch (xhr.status) {
|
switch (xhr.status) {
|
||||||
case 429:
|
case 429:
|
||||||
errorMessage = xhr.responseText;
|
errorMessage = xhr.responseText;
|
||||||
break;
|
break;
|
||||||
case 500:
|
case 500:
|
||||||
errorMessage = 'Server error: ' + xhr.responseText || 'Internal Server Error';
|
errorMessage = 'Server error: ' + (xhr.responseText || 'Internal Server Error');
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
errorMessage = xhr.statusText || 'An error occurred';
|
errorMessage = xhr.statusText || 'An error occurred';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show an error toast with the specific error message
|
|
||||||
sendToast('error', 'Log failed', errorMessage, false, true);
|
sendToast('error', 'Log failed', errorMessage, false, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
@@ -1041,39 +1078,54 @@ function toggleLock(buttonSelector, activeMessage, inactiveMessage, activeLabel,
|
|||||||
|
|
||||||
function initTooltips() {
|
function initTooltips() {
|
||||||
$('.tooltip').hover(function (e) {
|
$('.tooltip').hover(function (e) {
|
||||||
|
// Check if hovered element is NOT `.popup-content`
|
||||||
|
if ($(e.target).closest('.popup-content').length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var tooltipText = $(this).data('tooltip');
|
var tooltipText = $(this).data('tooltip');
|
||||||
|
|
||||||
// Add a delay of 500 milliseconds before creating and appending the tooltip
|
// Delay tooltip appearance
|
||||||
$(this).data('timeout', setTimeout(() => {
|
$(this).data('timeout', setTimeout(() => {
|
||||||
var tooltip = $('<div class="tooltiptext"></div>').html(tooltipText);
|
if ($('.tooltip-wrapper').length === 0) {
|
||||||
if ($('.tooltiptext').length === 0) { $('body').append(tooltip); } // Don't allow more than one tooltip
|
var tooltip = $(`
|
||||||
|
<div class="tooltip-wrapper">
|
||||||
|
<div class="tooltiptext">
|
||||||
|
${tooltipText}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
$('body').append(tooltip);
|
||||||
|
}
|
||||||
|
|
||||||
var posX = e.pageX;
|
var posX = e.pageX;
|
||||||
var posY = e.pageY;
|
var posY = e.pageY;
|
||||||
|
var tooltipEl = $('.tooltiptext');
|
||||||
var tooltipWidth = tooltip.outerWidth();
|
var tooltipWidth = tooltipEl.outerWidth();
|
||||||
var tooltipHeight = tooltip.outerHeight();
|
var tooltipHeight = tooltipEl.outerHeight();
|
||||||
posX -= tooltipWidth / 2;
|
posX -= tooltipWidth / 2;
|
||||||
posY -= tooltipHeight + 10;
|
posY -= tooltipHeight + 10;
|
||||||
tooltip.css({ top: posY, left: posX, opacity: 1 }); // Set opacity to 1
|
|
||||||
// For touchscreen devices
|
tooltipEl.css({ top: posY, left: posX, opacity: 1 });
|
||||||
if ((/Mobi|Android|iPhone|iPad|iPod|Opera Mini/i.test(navigator.userAgent)) && ('ontouchstart' in window || navigator.maxTouchPoints)) {
|
|
||||||
setTimeout(() => { $('.tooltiptext').remove(); }, 10000);
|
|
||||||
document.addEventListener('touchstart', function() { setTimeout(() => { $('.tooltiptext').remove(); }, 500); });
|
|
||||||
}
|
|
||||||
}, 500));
|
}, 500));
|
||||||
}, function () {
|
}, function () {
|
||||||
// Clear the timeout if the mouse leaves before the delay completes
|
|
||||||
clearTimeout($(this).data('timeout'));
|
clearTimeout($(this).data('timeout'));
|
||||||
$('.tooltiptext').remove();
|
setTimeout(() => { $('.tooltip-wrapper').remove(); }, 500);
|
||||||
setTimeout(() => { $('.tooltiptext').remove(); }, 500); // Ensure no tooltips remain stuck
|
|
||||||
}).mousemove(function (e) {
|
}).mousemove(function (e) {
|
||||||
var tooltipWidth = $('.tooltiptext').outerWidth();
|
var tooltipEl = $('.tooltiptext');
|
||||||
var tooltipHeight = $('.tooltiptext').outerHeight();
|
var tooltipWidth = tooltipEl.outerWidth();
|
||||||
|
var tooltipHeight = tooltipEl.outerHeight();
|
||||||
var posX = e.pageX - tooltipWidth / 2;
|
var posX = e.pageX - tooltipWidth / 2;
|
||||||
var posY = e.pageY - tooltipHeight - 10;
|
var posY = e.pageY - tooltipHeight - 10;
|
||||||
|
|
||||||
$('.tooltiptext').css({ top: posY, left: posX });
|
tooltipEl.css({ top: posY, left: posX });
|
||||||
|
});
|
||||||
|
|
||||||
|
// Prevent the tooltip from showing when hovering over .popup-content
|
||||||
|
$('.popup-content').on('mouseenter', function (e) {
|
||||||
|
clearTimeout($('.tooltip').data('timeout'));
|
||||||
|
$('.tooltip-wrapper').remove(); // Ensure tooltip does not appear
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -144,6 +144,11 @@
|
|||||||
]
|
]
|
||||||
}) %>
|
}) %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="panel-100 no-bg text-center">
|
||||||
|
<p>If you use an USB audio card on Linux, enabling this option might fix your audio issues.</p>
|
||||||
|
<%- include('_components', {component: 'checkbox', cssClass: 'panel-100 flex-container flex-center', label: 'ALSA Software mode', id: 'audio-softwareMode'}) %>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- AUDIO SETTINGS END -->
|
<!-- AUDIO SETTINGS END -->
|
||||||
|
|||||||
Reference in New Issue
Block a user