Fix: Apply translations after sidebar load to resolve 'sidebar.screen' display issue

This commit is contained in:
PaulVua
2026-02-17 12:30:14 +01:00
parent f1d716d900
commit aa1b90e3d5
3 changed files with 362 additions and 342 deletions

View File

@@ -140,6 +140,10 @@
const element = document.getElementById(id); const element = document.getElementById(id);
if (element) { if (element) {
element.innerHTML = data; element.innerHTML = data;
// Apply translations after loading dynamic content
if (window.i18n && typeof window.i18n.applyTranslations === 'function') {
window.i18n.applyTranslations();
}
} }
}) })
.catch(error => console.error(`Error loading ${file}:`, error)); .catch(error => console.error(`Error loading ${file}:`, error));

View File

@@ -121,14 +121,15 @@
const element = document.getElementById(id); const element = document.getElementById(id);
if (element) { if (element) {
element.innerHTML = data; element.innerHTML = data;
// Ensure the screen tab is visible here as well if we are on this page, // Apply translations after loading dynamic content
// though index.html handles it globally, sidebar load might reset it. if (window.i18n && typeof window.i18n.applyTranslations === 'function') {
// Ideally sidebar logic should be consistent. window.i18n.applyTranslations();
// For now, if we are ON screen.html, we should show the nav item. }
// Ensure the screen tab is visible here as well
if (id.includes('sidebar')) { if (id.includes('sidebar')) {
setTimeout(() => { setTimeout(() => {
const navScreen = element.querySelector('#nav-screen'); const navScreenElements = element.querySelectorAll('.nav-screen-item');
if (navScreen) navScreen.style.display = 'flex'; // or block navScreenElements.forEach(el => el.style.display = 'flex');
}, 100); }, 100);
} }
} }

View File

@@ -1,5 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -9,31 +10,39 @@
body { body {
overflow-x: hidden; overflow-x: hidden;
} }
#sidebar a.nav-link { #sidebar a.nav-link {
position: relative; position: relative;
display: flex; display: flex;
align-items: center; align-items: center;
} }
#sidebar a.nav-link:hover { #sidebar a.nav-link:hover {
background-color: rgba(0, 0, 0, 0.5); background-color: rgba(0, 0, 0, 0.5);
} }
#sidebar a.nav-link svg { #sidebar a.nav-link svg {
margin-right: 8px; /* Add spacing between icons and text */ margin-right: 8px;
/* Add spacing between icons and text */
} }
#sidebar { #sidebar {
transition: transform 0.3s ease-in-out; transition: transform 0.3s ease-in-out;
} }
.offcanvas-backdrop { .offcanvas-backdrop {
z-index: 1040; z-index: 1040;
} }
</style> </style>
</head> </head>
<body> <body>
<!-- Topbar --> <!-- Topbar -->
<span id="topbar"></span> <span id="topbar"></span>
<!-- Sidebar Offcanvas for Mobile --> <!-- Sidebar Offcanvas for Mobile -->
<div class="offcanvas offcanvas-start text-white bg-dark" tabindex="-1" id="sidebarOffcanvas" aria-labelledby="sidebarOffcanvasLabel"> <div class="offcanvas offcanvas-start text-white bg-dark" tabindex="-1" id="sidebarOffcanvas"
aria-labelledby="sidebarOffcanvasLabel">
<div class="offcanvas-header"> <div class="offcanvas-header">
<h5 class="offcanvas-title" id="sidebarOffcanvasLabel">NebuleAir</h5> <h5 class="offcanvas-title" id="sidebarOffcanvasLabel">NebuleAir</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="offcanvas" aria-label="Close"></button> <button type="button" class="btn-close btn-close-white" data-bs-dismiss="offcanvas" aria-label="Close"></button>
@@ -50,7 +59,8 @@
<!-- Main content --> <!-- Main content -->
<main class="col-md-10 ms-sm-auto col-lg-11 offset-md-2 offset-lg-1 px-md-4"> <main class="col-md-10 ms-sm-auto col-lg-11 offset-md-2 offset-lg-1 px-md-4">
<h1 class="mt-4" data-i18n="sensors.title">Les sondes de mesure</h1> <h1 class="mt-4" data-i18n="sensors.title">Les sondes de mesure</h1>
<p data-i18n="sensors.description">Votre capteur NebuleAir est équipé de une ou plusieurs sondes qui permettent de mesurer certaines variables environnementales. La mesure <p data-i18n="sensors.description">Votre capteur NebuleAir est équipé de une ou plusieurs sondes qui permettent
de mesurer certaines variables environnementales. La mesure
est automatique mais vous pouvez ici vous assurer de leur bon fonctionnement. est automatique mais vous pouvez ici vous assurer de leur bon fonctionnement.
</p> </p>
<div class="row mb-3" id="card-container"></div> <div class="row mb-3" id="card-container"></div>
@@ -58,17 +68,17 @@
</div> </div>
</div> </div>
<!-- JAVASCRIPT --> <!-- JAVASCRIPT -->
<!-- Link Ajax locally --> <!-- Link Ajax locally -->
<script src="assets/jquery/jquery-3.7.1.min.js"></script> <script src="assets/jquery/jquery-3.7.1.min.js"></script>
<!-- Link Bootstrap JS and Popper.js locally --> <!-- Link Bootstrap JS and Popper.js locally -->
<script src="assets/js/bootstrap.bundle.js"></script> <script src="assets/js/bootstrap.bundle.js"></script>
<!-- i18n translation system --> <!-- i18n translation system -->
<script src="assets/js/i18n.js"></script> <script src="assets/js/i18n.js"></script>
<script src="assets/js/topbar-logo.js"></script> <script src="assets/js/topbar-logo.js"></script>
<script> <script>
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
const elementsToLoad = [ const elementsToLoad = [
{ id: 'topbar', file: 'topbar.html' }, { id: 'topbar', file: 'topbar.html' },
@@ -83,28 +93,32 @@
const element = document.getElementById(id); const element = document.getElementById(id);
if (element) { if (element) {
element.innerHTML = data; element.innerHTML = data;
// Apply translations after loading dynamic content
if (window.i18n && typeof window.i18n.applyTranslations === 'function') {
window.i18n.applyTranslations();
}
} }
}) })
.catch(error => console.error(`Error loading ${file}:`, error)); .catch(error => console.error(`Error loading ${file}:`, error));
}); });
}); });
function getNPM_values(port){ function getNPM_values(port) {
console.log("Data from NPM (port "+port+"):"); console.log("Data from NPM (port " + port + "):");
$("#loading_"+port).show(); $("#loading_" + port).show();
$.ajax({ $.ajax({
url: 'launcher.php?type=npm&port='+port, url: 'launcher.php?type=npm&port=' + port,
dataType: 'json', // Specify that you expect a JSON response dataType: 'json', // Specify that you expect a JSON response
method: 'GET', // Use GET or POST depending on your needs method: 'GET', // Use GET or POST depending on your needs
success: function(response) { success: function (response) {
console.log(response); console.log(response);
const tableBody = document.getElementById("data-table-body_"+port); const tableBody = document.getElementById("data-table-body_" + port);
tableBody.innerHTML = ""; tableBody.innerHTML = "";
$("#loading_"+port).hide(); $("#loading_" + port).hide();
// Create an array of the desired keys // Create an array of the desired keys
const keysToShow = ["PM1", "PM25", "PM10","message"]; const keysToShow = ["PM1", "PM25", "PM10", "message"];
// Error messages mapping // Error messages mapping
const errorMessages = { const errorMessages = {
"notReady": "Sensor is not ready", "notReady": "Sensor is not ready",
@@ -119,7 +133,7 @@ function getNPM_values(port){
keysToShow.forEach(key => { keysToShow.forEach(key => {
if (response[key] !== undefined) { // Check if the key exists in the response if (response[key] !== undefined) { // Check if the key exists in the response
const value = response[key]; const value = response[key];
$("#data-table-body_"+port).append(` $("#data-table-body_" + port).append(`
<tr> <tr>
<td>${key}</td> <td>${key}</td>
<td>${value} µg/m³</td> <td>${value} µg/m³</td>
@@ -140,40 +154,40 @@ function getNPM_values(port){
} }
}); });
}, },
error: function(xhr, status, error) { error: function (xhr, status, error) {
console.error('AJAX request failed:', status, error); console.error('AJAX request failed:', status, error);
} }
}); });
} }
function getNPM_firmware(port){ function getNPM_firmware(port) {
console.log("Firmware version from NPM (port "+port+"):"); console.log("Firmware version from NPM (port " + port + "):");
$("#loading_fw_"+port).show(); $("#loading_fw_" + port).show();
$.ajax({ $.ajax({
url: 'launcher.php?type=npm_firmware&port='+port, url: 'launcher.php?type=npm_firmware&port=' + port,
dataType: 'json', dataType: 'json',
method: 'GET', method: 'GET',
success: function(response) { success: function (response) {
console.log(response); console.log(response);
$("#loading_fw_"+port).hide(); $("#loading_fw_" + port).hide();
const fwSpan = document.getElementById("fw_version_"+port); const fwSpan = document.getElementById("fw_version_" + port);
if (response.firmware_version !== undefined) { if (response.firmware_version !== undefined) {
fwSpan.innerHTML = '<span class="badge bg-success">Firmware: ' + response.firmware_version + '</span>'; fwSpan.innerHTML = '<span class="badge bg-success">Firmware: ' + response.firmware_version + '</span>';
} else { } else {
fwSpan.innerHTML = '<span class="badge bg-danger">Error reading firmware</span>'; fwSpan.innerHTML = '<span class="badge bg-danger">Error reading firmware</span>';
} }
}, },
error: function(xhr, status, error) { error: function (xhr, status, error) {
console.error('AJAX request failed:', status, error); console.error('AJAX request failed:', status, error);
$("#loading_fw_"+port).hide(); $("#loading_fw_" + port).hide();
const fwSpan = document.getElementById("fw_version_"+port); const fwSpan = document.getElementById("fw_version_" + port);
fwSpan.innerHTML = '<span class="badge bg-danger">Error</span>'; fwSpan.innerHTML = '<span class="badge bg-danger">Error</span>';
} }
}); });
} }
function getENVEA_values(port, name){ function getENVEA_values(port, name) {
console.log("Data from Envea " + name + " (port " + port + "):"); console.log("Data from Envea " + name + " (port " + port + "):");
$("#loading_envea" + name).show(); $("#loading_envea" + name).show();
@@ -181,7 +195,7 @@ function getENVEA_values(port, name){
url: 'launcher.php?type=envea&port=' + port + '&name=' + name, url: 'launcher.php?type=envea&port=' + port + '&name=' + name,
dataType: 'json', dataType: 'json',
method: 'GET', method: 'GET',
success: function(response) { success: function (response) {
console.log(response); console.log(response);
const tableBody = document.getElementById("data-table-body_envea" + name); const tableBody = document.getElementById("data-table-body_envea" + name);
tableBody.innerHTML = ""; tableBody.innerHTML = "";
@@ -201,7 +215,7 @@ function getENVEA_values(port, name){
} }
}); });
}, },
error: function(xhr, status, error) { error: function (xhr, status, error) {
console.error('AJAX request failed:', status, error); console.error('AJAX request failed:', status, error);
const tableBody = document.getElementById("data-table-body_envea" + name); const tableBody = document.getElementById("data-table-body_envea" + name);
$("#loading_envea" + name).hide(); $("#loading_envea" + name).hide();
@@ -216,9 +230,9 @@ function getENVEA_values(port, name){
`; `;
} }
}); });
} }
function getENVEA_debug_values(){ function getENVEA_debug_values() {
console.log("Getting debug data from all Envea sensors"); console.log("Getting debug data from all Envea sensors");
$("#loading_envea_debug").show(); $("#loading_envea_debug").show();
@@ -226,7 +240,7 @@ function getENVEA_debug_values(){
url: 'launcher.php?type=envea_debug', url: 'launcher.php?type=envea_debug',
dataType: 'text', dataType: 'text',
method: 'GET', method: 'GET',
success: function(response) { success: function (response) {
console.log("Envea debug output:", response); console.log("Envea debug output:", response);
const outputDiv = document.getElementById("envea-debug-output"); const outputDiv = document.getElementById("envea-debug-output");
$("#loading_envea_debug").hide(); $("#loading_envea_debug").hide();
@@ -234,7 +248,7 @@ function getENVEA_debug_values(){
// Display raw output in a pre block // Display raw output in a pre block
outputDiv.innerHTML = `<pre style="background-color: #f5f5f5; padding: 10px; border-radius: 5px; max-height: 500px; overflow-y: auto; font-size: 12px;">${response}</pre>`; outputDiv.innerHTML = `<pre style="background-color: #f5f5f5; padding: 10px; border-radius: 5px; max-height: 500px; overflow-y: auto; font-size: 12px;">${response}</pre>`;
}, },
error: function(xhr, status, error) { error: function (xhr, status, error) {
console.error('AJAX request failed:', status, error); console.error('AJAX request failed:', status, error);
const outputDiv = document.getElementById("envea-debug-output"); const outputDiv = document.getElementById("envea-debug-output");
$("#loading_envea_debug").hide(); $("#loading_envea_debug").hide();
@@ -247,10 +261,10 @@ function getENVEA_debug_values(){
`; `;
} }
}); });
} }
function getNoise_values(){ function getNoise_values() {
console.log("Data from I2C Noise Sensor:"); console.log("Data from I2C Noise Sensor:");
$("#loading_noise").show(); $("#loading_noise").show();
@@ -258,7 +272,7 @@ function getNoise_values(){
url: 'launcher.php?type=noise', url: 'launcher.php?type=noise',
dataType: 'text', dataType: 'text',
method: 'GET', // Use GET or POST depending on your needs method: 'GET', // Use GET or POST depending on your needs
success: function(response) { success: function (response) {
console.log(response); console.log(response);
const tableBody = document.getElementById("data-table-body_noise"); const tableBody = document.getElementById("data-table-body_noise");
tableBody.innerHTML = ""; tableBody.innerHTML = "";
@@ -279,13 +293,13 @@ function getNoise_values(){
} }
}); });
}, },
error: function(xhr, status, error) { error: function (xhr, status, error) {
console.error('AJAX request failed:', status, error); console.error('AJAX request failed:', status, error);
} }
}); });
} }
function getMHZ19_values(){ function getMHZ19_values() {
console.log("Data from MH-Z19 CO2 sensor:"); console.log("Data from MH-Z19 CO2 sensor:");
$("#loading_mhz19").show(); $("#loading_mhz19").show();
@@ -293,7 +307,7 @@ function getMHZ19_values(){
url: 'launcher.php?type=mhz19', url: 'launcher.php?type=mhz19',
dataType: 'json', dataType: 'json',
method: 'GET', method: 'GET',
success: function(response) { success: function (response) {
console.log(response); console.log(response);
const tableBody = document.getElementById("data-table-body_mhz19"); const tableBody = document.getElementById("data-table-body_mhz19");
tableBody.innerHTML = ""; tableBody.innerHTML = "";
@@ -316,7 +330,7 @@ function getMHZ19_values(){
`); `);
} }
}, },
error: function(xhr, status, error) { error: function (xhr, status, error) {
console.error('AJAX request failed:', status, error); console.error('AJAX request failed:', status, error);
$("#loading_mhz19").hide(); $("#loading_mhz19").hide();
const tableBody = document.getElementById("data-table-body_mhz19"); const tableBody = document.getElementById("data-table-body_mhz19");
@@ -331,7 +345,7 @@ function getMHZ19_values(){
}); });
} }
function getBME280_values(){ function getBME280_values() {
console.log("Data from I2C BME280:"); console.log("Data from I2C BME280:");
$("#loading_BME280").show(); $("#loading_BME280").show();
@@ -340,7 +354,7 @@ function getBME280_values(){
dataType: 'text', dataType: 'text',
method: 'GET', // Use GET or POST depending on your needs method: 'GET', // Use GET or POST depending on your needs
success: function(response) { success: function (response) {
console.log(response); console.log(response);
const tableBody = document.getElementById("data-table-body_BME280"); const tableBody = document.getElementById("data-table-body_BME280");
@@ -370,24 +384,24 @@ function getBME280_values(){
} }
}); });
}, },
error: function(xhr, status, error) { error: function (xhr, status, error) {
console.error('AJAX request failed:', status, error); console.error('AJAX request failed:', status, error);
} }
}); });
} }
window.onload = function() { window.onload = function () {
//NEW way to get config (SQLite) //NEW way to get config (SQLite)
let mainConfig = {}; // Store main config for use in sensor card creation let mainConfig = {}; // Store main config for use in sensor card creation
$.ajax({ $.ajax({
url: 'launcher.php?type=get_config_sqlite', url: 'launcher.php?type=get_config_sqlite',
dataType:'json', dataType: 'json',
//dataType: 'json', // Specify that you expect a JSON response //dataType: 'json', // Specify that you expect a JSON response
method: 'GET', // Use GET or POST depending on your needs method: 'GET', // Use GET or POST depending on your needs
success: function(response) { success: function (response) {
console.log("Getting SQLite config table:"); console.log("Getting SQLite config table:");
console.log(response); console.log(response);
@@ -419,9 +433,9 @@ $.ajax({
createSensorCards(mainConfig); createSensorCards(mainConfig);
}, },
error: function(xhr, status, error) { error: function (xhr, status, error) {
console.error('AJAX request failed:', status, error); console.error('AJAX request failed:', status, error);
} }
});//end AJAX });//end AJAX
//Function to create sensor cards based on config //Function to create sensor cards based on config
@@ -538,9 +552,9 @@ error: function(xhr, status, error) {
//getting config_scripts table //getting config_scripts table
$.ajax({ $.ajax({
url: 'launcher.php?type=get_envea_sondes_table_sqlite', url: 'launcher.php?type=get_envea_sondes_table_sqlite',
dataType:'json', dataType: 'json',
method: 'GET', method: 'GET',
success: function(sondes) { success: function (sondes) {
console.log("Getting SQLite envea sondes table:"); console.log("Getting SQLite envea sondes table:");
console.log(sondes); console.log(sondes);
const ENVEA_sensors = sondes.filter(sonde => sonde.connected); // Filter only connected sondes const ENVEA_sensors = sondes.filter(sonde => sonde.connected); // Filter only connected sondes
@@ -571,7 +585,7 @@ error: function(xhr, status, error) {
i18n.applyTranslations(); i18n.applyTranslations();
}, },
error: function(xhr, status, error) { error: function (xhr, status, error) {
console.error('AJAX request failed:', status, error); console.error('AJAX request failed:', status, error);
} }
});//end AJAX envea Sondes });//end AJAX envea Sondes
@@ -588,19 +602,20 @@ error: function(xhr, status, error) {
url: 'launcher.php?type=RTC_time', url: 'launcher.php?type=RTC_time',
dataType: 'text', // Specify that you expect a JSON response dataType: 'text', // Specify that you expect a JSON response
method: 'GET', // Use GET or POST depending on your needs method: 'GET', // Use GET or POST depending on your needs
success: function(response) { success: function (response) {
console.log("Local RTC: " + response); console.log("Local RTC: " + response);
const RTC_Element = document.getElementById("RTC_time"); const RTC_Element = document.getElementById("RTC_time");
RTC_Element.textContent = response; RTC_Element.textContent = response;
}, },
error: function(xhr, status, error) { error: function (xhr, status, error) {
console.error('AJAX request failed:', status, error); console.error('AJAX request failed:', status, error);
} }
}); });
} //end windows onload } //end windows onload
</script> </script>
</body> </body>
</html> </html>