From 559e798265cb0e7c8d5f4997a3fe83287050f781 Mon Sep 17 00:00:00 2001 From: Pithon Kabiro Date: Mon, 11 Oct 2021 16:58:57 +0200 Subject: [PATCH] Rewrite multiple 'if' statements using 'switch' --- public/js/appChart.js | 257 ++++++++++-------- public/js/src_modules/aggregate.mjs | 48 +++- public/js/src_modules/chartColumn.mjs | 9 +- public/js/src_modules/chartHeatmap.mjs | 7 +- public/js/src_modules/chartLine.mjs | 4 +- public/js/src_modules/chartScatterPlot.mjs | 4 +- public/js/src_modules/dropDownListHelpers.mjs | 2 + .../js/src_modules/dropDownListProcessing.mjs | 2 + public/js/src_modules/loadingIndicator.mjs | 29 +- public/js/thirdparty/scripts.js | 43 +-- 10 files changed, 243 insertions(+), 162 deletions(-) diff --git a/public/js/appChart.js b/public/js/appChart.js index f78f42e..5fffe09 100644 --- a/public/js/appChart.js +++ b/public/js/appChart.js @@ -24,6 +24,8 @@ import { drawColumnChartHighcharts } from "./src_modules/chartColumn.mjs"; import { showLoadingSpinner, hideLoadingSpinner, + disableDrawChartButton, + enableDrawChartButton, } from "./src_modules/loadingIndicator.mjs"; import { vanillaSelectBox } from "./thirdparty/vanillaSelectBox.mjs"; @@ -138,7 +140,7 @@ const drawChartUsingSelectedOptions = async function () { const selectedOptionsAllDropDownLists = getSelectedOptionsFromAllDropDownLists(); - // Note: The aggregation type + duration and chart type are the first and + // Note: The chart type amd aggregation type + duration are the first and // third elements respectively, we have ignored the second and fourth elements const [selectedChartTypeArr, , selectedAggregationTypeDurationArr] = selectedOptionsAllDropDownLists; @@ -178,71 +180,74 @@ const drawChartUsingSelectedOptions = async function () { ); // Create copies of the arrays of building(s) + data point(s) + sampling rate - const selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopyArr = [ + const selectedBuildingsDataPointsSamplingRateAbbrevRawObsCopyArr = [ ...selectedBuildingsDataPointsSamplingRateAbbrevNestedArr, ]; - const selectedBuildingsDataPointsSamplingRateAbbrevComputedCopyArr = [ + const selectedBuildingsDataPointsSamplingRateAbbrevTempDiffCopyArr = [ ...selectedBuildingsDataPointsSamplingRateAbbrevNestedArr, ]; - // Check if we have non-computed - const selectedBuildingsDataPointsSamplingRateAbbrevNonComputedArr = + // Check if we have raw observations + const selectedBuildingsDataPointsSamplingRateAbbrevRawObsArr = checkIfSelectedOptionsContainTemperatureDifference( - selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopyArr + selectedBuildingsDataPointsSamplingRateAbbrevRawObsCopyArr ) ? deleteTemperatureDifferenceOptions( - selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopyArr + selectedBuildingsDataPointsSamplingRateAbbrevRawObsCopyArr ) - : selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopyArr; + : selectedBuildingsDataPointsSamplingRateAbbrevRawObsCopyArr; - // Check if we have computed / dT - const selectedBuildingsDataPointsSamplingRateAbbrevComputedArr = + // Check if we have dT (temperature difference) + const selectedBuildingsDataPointsSamplingRateAbbrevTempDiffArr = checkIfSelectedOptionsContainTemperatureDifference( - selectedBuildingsDataPointsSamplingRateAbbrevComputedCopyArr + selectedBuildingsDataPointsSamplingRateAbbrevTempDiffCopyArr ) ? extractTemperatureDifferenceOptions( - selectedBuildingsDataPointsSamplingRateAbbrevComputedCopyArr + selectedBuildingsDataPointsSamplingRateAbbrevTempDiffCopyArr ) : []; // Display the loading indicator showLoadingSpinner(); - // Fetch the observations + metadata / non-computed - const observationsPlusMetadataNonComputedArr = - selectedBuildingsDataPointsSamplingRateAbbrevNonComputedArr.length === 0 + // Disable the 'draw chart' button + disableDrawChartButton(); + + // Fetch the observations + metadata / raw observations + const observationsRawPlusMetadataArr = + selectedBuildingsDataPointsSamplingRateAbbrevRawObsArr.length === 0 ? [[], []] : await getMetadataPlusObservationsFromSingleOrMultipleDatastreams( BASE_URL, QUERY_PARAMS_COMBINED, - selectedBuildingsDataPointsSamplingRateAbbrevNonComputedArr + selectedBuildingsDataPointsSamplingRateAbbrevRawObsArr ); - // Fetch the observations + metadata / computed (dT) - const observationsPlusMetadataComputedArr = - selectedBuildingsDataPointsSamplingRateAbbrevComputedArr.length === 0 + // Fetch the observations + metadata / temperature difference (dT) + const observationsTempDiffPlusMetadataArr = + selectedBuildingsDataPointsSamplingRateAbbrevTempDiffArr.length === 0 ? [[], []] : await calculateVorlaufMinusRuecklaufTemperature( BASE_URL, QUERY_PARAMS_COMBINED, extractBuildingPlusSamplingRate( - selectedBuildingsDataPointsSamplingRateAbbrevComputedArr + selectedBuildingsDataPointsSamplingRateAbbrevTempDiffArr ) ); - // Extract the combined arrays for observations and metadata / non-computed - const [observationsNestedNonComputedArr, metadataNestedNonComputedArr] = - observationsPlusMetadataNonComputedArr; + // Extract the combined arrays for observations and metadata / raw observations + const [observationsRawNestedArr, metadataTempDiffNestedArr] = + observationsRawPlusMetadataArr; - // Extract the combined arrays for observations and metadata / computed (dT) + // Extract the combined arrays for observations and metadata / temperature difference (dT) const [observationsNestedComputedArr, metadataNestedComputedArr] = - observationsPlusMetadataComputedArr; + observationsTempDiffPlusMetadataArr; // Create a combined array of observations and metadata const observationsPlusMetadataCombined = [ - [...observationsNestedNonComputedArr, ...observationsNestedComputedArr], - [...metadataNestedNonComputedArr, ...metadataNestedComputedArr], + [...observationsRawNestedArr, ...observationsNestedComputedArr], + [...metadataTempDiffNestedArr, ...metadataNestedComputedArr], ]; const [observationsComboNestedArr, metadataComboNestedArr] = @@ -253,8 +258,8 @@ const drawChartUsingSelectedOptions = async function () { (metadataObj) => formatDatastreamMetadataForChart(metadataObj) ); - // Extract the formatted metadata properties - used by ALL chart types - const extractedFormattedDatastreamProperties = + // Extract the formatted metadata properties for the raw observations - used by ALL chart types + const rawObservationsExtractedFormattedDatastreamProperties = extractPropertiesFromFormattedDatastreamMetadata( formattedMetadataNestedArr, false @@ -272,111 +277,125 @@ const drawChartUsingSelectedOptions = async function () { const aggregationStartDate = "2020-01-01"; const aggregationEndDate = "2020-12-31"; - // Extract observations within the user-specified start and end date - used by MULTIPLE chart types - const observationsAggregationNestedArr = observationsComboNestedArr.map( - (obsArr) => - extractObservationsWithinDatesInterval( - obsArr, - "60min", - aggregationStartDate, - aggregationEndDate - ) - ); + // Create final array of observations- used by MULTIPLE chart types + // If we are performing aggregation, it was envisioned that the user would + // select observations that fall within a start and end date + const observationsComboNestedFinalArr = + selectedAggregationType === "None (raw data)" + ? observationsComboNestedArr + : observationsComboNestedArr.map((observationsArr) => + extractObservationsWithinDatesInterval( + observationsArr, + selectedSamplingRateAbbrev, + aggregationStartDate, + aggregationEndDate + ) + ); // Unique calendar dates - used by MULTIPLE chart types - const uniqueCalendarDatesNestedArr = observationsAggregationNestedArr.map( + const uniqueCalendarDatesNestedArr = observationsComboNestedFinalArr.map( (observationsArr) => extractUniqueCalendarDatesFromTimestamp(observationsArr) ); for (const selectedChartType of selectedChartTypeArr) { - if (selectedChartType === "Heatmap") { - // We are interested in raw observations - if ( - selectedAggregationOptionsAreValid && - selectedBuildingDataPointsOptionsAreValid - ) { - drawHeatmapBasedOnSelectedOptions( - observationsComboNestedArr, - extractedFormattedDatastreamProperties - ); - } - } - - if (selectedChartType === "Scatter Plot") { - // We are interested in raw observations - if ( - selectedAggregationOptionsAreValid && - selectedBuildingDataPointsOptionsAreValid - ) { - drawScatterPlotFromChartSelection( - observationsComboNestedArr, - extractedFormattedDatastreamProperties - ); - } - } - - if (selectedChartType === "Line") { - // We are interested in raw observations or aggregated observations - - // Raw observations - if (selectedAggregationType === "None (raw data)") { - // Create formatted array(s) for observations - const formattedRawObservationsLineChartNestedArr = - observationsComboNestedArr.map((observationsArr) => - formatSensorThingsApiResponseForLineOrColumnChart(observationsArr) + switch (selectedChartType) { + // We are interested in raw observations ONLY + case "Heatmap": + if ( + selectedAggregationOptionsAreValid && + selectedBuildingDataPointsOptionsAreValid + ) { + drawHeatmapBasedOnSelectedOptions( + observationsComboNestedFinalArr, + rawObservationsExtractedFormattedDatastreamProperties ); - - drawLineChartHighcharts( - formattedRawObservationsLineChartNestedArr, - extractedFormattedDatastreamProperties - ); - } - // Aggregated observations - else { - drawLineChartBasedOnSelectedAggregationOptions( - selectedAggregationType, - selectedAggregationDuration, - observationsAggregationNestedArr, - selectedSamplingRateAbbrev, - uniqueCalendarDatesNestedArr, - formattedMetadataNestedArr - ); - } - } - - if (selectedChartType === "Column") { - // We are interested in raw observations or aggregated observations - - // Raw observations - if (selectedAggregationType === "None (raw data)") { - // Create formatted array(s) for observations - const formattedRawObservationsColumnChartNestedArr = - observationsComboNestedArr.map((observationsArr) => - formatSensorThingsApiResponseForLineOrColumnChart(observationsArr) + } + break; + + // We are interested in raw observations ONLY + case "Scatter Plot": + if ( + selectedAggregationOptionsAreValid && + selectedBuildingDataPointsOptionsAreValid + ) { + drawScatterPlotFromChartSelection( + observationsComboNestedFinalArr, + rawObservationsExtractedFormattedDatastreamProperties + ); + } + break; + + // We are interested in BOTH raw observations and aggregated observations + case "Line": + // Raw observations + if (selectedAggregationType === "None (raw data)") { + // Create formatted array(s) for observations + const formattedRawObservationsLineChartNestedArr = + observationsComboNestedFinalArr.map((observationsArr) => + formatSensorThingsApiResponseForLineOrColumnChart( + observationsArr + ) + ); + + drawLineChartHighcharts( + formattedRawObservationsLineChartNestedArr, + rawObservationsExtractedFormattedDatastreamProperties ); + } + // Aggregated observations + else { + drawLineChartBasedOnSelectedAggregationOptions( + selectedAggregationType, + selectedAggregationDuration, + observationsComboNestedFinalArr, + selectedSamplingRateAbbrev, + uniqueCalendarDatesNestedArr, + formattedMetadataNestedArr + ); + } + break; + + // We are interested in BOTH raw observations and aggregated observations + case "Column": + // Raw observations + if (selectedAggregationType === "None (raw data)") { + // Create formatted array(s) for observations + const formattedRawObservationsColumnChartNestedArr = + observationsComboNestedFinalArr.map((observationsArr) => + formatSensorThingsApiResponseForLineOrColumnChart( + observationsArr + ) + ); + + drawColumnChartHighcharts( + formattedRawObservationsColumnChartNestedArr, + rawObservationsExtractedFormattedDatastreamProperties + ); + } + // Aggregated observations + else { + drawColumnChartBasedOnSelectedAggregationOptions( + selectedAggregationType, + selectedAggregationDuration, + observationsComboNestedFinalArr, + selectedSamplingRateAbbrev, + uniqueCalendarDatesNestedArr, + formattedMetadataNestedArr + ); + } + break; - drawColumnChartHighcharts( - formattedRawObservationsColumnChartNestedArr, - extractedFormattedDatastreamProperties - ); - } - // Aggregated observations - else { - drawColumnChartBasedOnSelectedAggregationOptions( - selectedAggregationType, - selectedAggregationDuration, - observationsAggregationNestedArr, - selectedSamplingRateAbbrev, - uniqueCalendarDatesNestedArr, - formattedMetadataNestedArr - ); - } + default: + throw new Error("None of the chart type options were selected"); } } } catch (err) { console.error(err); } finally { + // Enable the 'draw chart' button + enableDrawChartButton(); + // Hide the loading indicator hideLoadingSpinner(); } diff --git a/public/js/src_modules/aggregate.mjs b/public/js/src_modules/aggregate.mjs index 324716d..02f5998 100644 --- a/public/js/src_modules/aggregate.mjs +++ b/public/js/src_modules/aggregate.mjs @@ -5,6 +5,16 @@ import { extractObservationValuesWithinMonthInterval, } from "./aggregateHelpers.mjs"; +/** + * Remove `null` observation values from an array of observation values + * + * @param {Array} obsValuesArr An array of observation values + * @returns {Array} An array with `null` observation values removed + */ +const filterOutNullObservationValues = function (obsValuesArr) { + return obsValuesArr.filter((obs) => obs !== null); +}; + /** * Calculate the minimum observation values that fall within a time interval delimited by a start date and end date * @param {Array} obsValuesForDaysIntervalArr An array of observation values that fall within our time interval @@ -13,7 +23,10 @@ import { const calculateMinimumObservationValuesWithinDatesInterval = function ( obsValuesForDaysIntervalArr ) { - return Math.min(...obsValuesForDaysIntervalArr); + // If the observation value is `null`, skip the calculation + return obsValuesForDaysIntervalArr.reduce((previousValue, obsValue) => + obsValue === null ? null : Math.min(previousValue, obsValue) + ); }; /** @@ -24,7 +37,10 @@ const calculateMinimumObservationValuesWithinDatesInterval = function ( const calculateMaximumObservationValuesWithinDatesInterval = function ( obsValuesForDaysIntervalArr ) { - return Math.max(...obsValuesForDaysIntervalArr); + // If the observation value is `null`, skip the calculation + return obsValuesForDaysIntervalArr.reduce((previousValue, obsValue) => + obsValue === null ? null : Math.max(previousValue, obsValue) + ); }; /** @@ -35,8 +51,10 @@ const calculateMaximumObservationValuesWithinDatesInterval = function ( const calculateSumOfObservationValuesWithinDatesInterval = function ( obsValuesForDaysIntervalArr ) { - return obsValuesForDaysIntervalArr.reduce( - (accumulator, obsValue) => accumulator + obsValue + // Remove the `null` observation values before calculating the sum + return filterOutNullObservationValues(obsValuesForDaysIntervalArr).reduce( + (previousValue, obsValue) => previousValue + obsValue, + 0 ); }; @@ -48,10 +66,11 @@ const calculateSumOfObservationValuesWithinDatesInterval = function ( const calculateAverageOfObservationValuesWithinDatesInterval = function ( obsValuesForDaysIntervalArr ) { + // The observation values array should only include non-`null` values return ( calculateSumOfObservationValuesWithinDatesInterval( obsValuesForDaysIntervalArr - ) / obsValuesForDaysIntervalArr.length + ) / filterOutNullObservationValues(obsValuesForDaysIntervalArr).length ); }; @@ -63,7 +82,10 @@ const calculateAverageOfObservationValuesWithinDatesInterval = function ( const calculateMinimumObservationValuesWithinMonthInterval = function ( obsValuesForMonthIntervalArr ) { - return Math.min(...obsValuesForMonthIntervalArr); + // If the observation value is `null`, skip the calculation + return obsValuesForMonthIntervalArr.reduce((previousValue, obsValue) => + obsValue === null ? null : Math.min(previousValue, obsValue) + ); }; /** @@ -74,7 +96,10 @@ const calculateMinimumObservationValuesWithinMonthInterval = function ( const calculateMaximumObservationValuesWithinMonthInterval = function ( obsValuesForMonthIntervalArr ) { - return Math.max(...obsValuesForMonthIntervalArr); + // If the observation value is `null`, skip the calculation + return obsValuesForMonthIntervalArr.reduce((previousValue, obsValue) => + obsValue === null ? null : Math.max(previousValue, obsValue) + ); }; /** @@ -85,8 +110,10 @@ const calculateMaximumObservationValuesWithinMonthInterval = function ( const calculateSumOfObservationValuesWithinMonthInterval = function ( obsValuesForMonthIntervalArr ) { - return obsValuesForMonthIntervalArr.reduce( - (accumulator, obsValue) => accumulator + obsValue + // Remove the `null` observation values before calculating the sum + return filterOutNullObservationValues(obsValuesForMonthIntervalArr).reduce( + (previousValue, obsValue) => previousValue + obsValue, + 0 ); }; @@ -98,10 +125,11 @@ const calculateSumOfObservationValuesWithinMonthInterval = function ( const calculateAverageOfObservationValuesWithinMonthInterval = function ( obsValuesForMonthIntervalArr ) { + // The observation values array should only include non-`null` values return ( calculateSumOfObservationValuesWithinMonthInterval( obsValuesForMonthIntervalArr - ) / obsValuesForMonthIntervalArr.length + ) / filterOutNullObservationValues(obsValuesForMonthIntervalArr).length ); }; diff --git a/public/js/src_modules/chartColumn.mjs b/public/js/src_modules/chartColumn.mjs index 8c6de14..35fc3d5 100644 --- a/public/js/src_modules/chartColumn.mjs +++ b/public/js/src_modules/chartColumn.mjs @@ -131,10 +131,12 @@ const drawColumnChartHighcharts = function ( title: { text: textChartTitle, + "align": "center", }, subtitle: { text: textChartSubtitle, + "align": "center", }, xAxis: { @@ -143,7 +145,6 @@ const drawColumnChartHighcharts = function ( }, yAxis: { - min: 0, title: { text: `${phenomenonName} [${unitOfMeasurementSymbol}]`, }, @@ -155,10 +156,10 @@ const drawColumnChartHighcharts = function ( // this.x -- common for all points // this.points -- an array containing properties for each series // Note that our `reduce` method is in this format: - // ((accumulator, currentValue, currentIndex) => {...}, initialValue) + // ((previousValue, currentValue, currentIndex) => {...}, initialValue) return this.points.reduce( - (accumulator, point, i) => - `${accumulator}
${ + (previousValue, point, i) => + `${previousValue}
${ point.series.name }: ${point.y.toFixed(2)} ${ unitOfMeasurementSymbolsArr[i] diff --git a/public/js/src_modules/chartHeatmap.mjs b/public/js/src_modules/chartHeatmap.mjs index 69d77f5..87884e0 100644 --- a/public/js/src_modules/chartHeatmap.mjs +++ b/public/js/src_modules/chartHeatmap.mjs @@ -48,7 +48,8 @@ const calculateMinMaxValuesForHeatmapColorAxis = function ( const maxValue = Math.trunc(Math.max(...obsValueArr)); // Calculate the closest multiple of 5 - const minObsValue = minValue - (minValue % 5); + const minObsValue = + minValue > 0 ? minValue - (minValue % 5) : minValue + (minValue % 5); const maxObsValue = maxValue + (5 - (maxValue % 5)); return { minObsValue, maxObsValue }; @@ -98,13 +99,13 @@ const drawHeatMapHighcharts = function ( title: { text: TEXT_CHART_TITLE, - align: "left", + align: "center", x: 40, }, subtitle: { text: TEXT_CHART_SUBTITLE, - align: "left", + align: "center", x: 40, }, diff --git a/public/js/src_modules/chartLine.mjs b/public/js/src_modules/chartLine.mjs index ba9a2e1..2538662 100644 --- a/public/js/src_modules/chartLine.mjs +++ b/public/js/src_modules/chartLine.mjs @@ -134,12 +134,12 @@ const drawLineChartHighcharts = function ( title: { text: textChartTitle, - "align": "left", + "align": "center", }, subtitle: { text: textChartSubtitle, - align: "left", + align: "center", }, tooltip: { diff --git a/public/js/src_modules/chartScatterPlot.mjs b/public/js/src_modules/chartScatterPlot.mjs index 0cc2bdb..e84e611 100644 --- a/public/js/src_modules/chartScatterPlot.mjs +++ b/public/js/src_modules/chartScatterPlot.mjs @@ -231,12 +231,12 @@ const drawScatterPlotHighcharts = function ( title: { text: CHART_TITLE, - "align": "left", + "align": "center", }, subtitle: { text: CHART_SUBTITLE, - "align": "left", + "align": "center", }, xAxis: { diff --git a/public/js/src_modules/dropDownListHelpers.mjs b/public/js/src_modules/dropDownListHelpers.mjs index f087cdd..b505d7e 100644 --- a/public/js/src_modules/dropDownListHelpers.mjs +++ b/public/js/src_modules/dropDownListHelpers.mjs @@ -1,3 +1,5 @@ +"use strict"; + /** * Get the selected option(s) from a dropdown list * diff --git a/public/js/src_modules/dropDownListProcessing.mjs b/public/js/src_modules/dropDownListProcessing.mjs index 47715ca..123db15 100644 --- a/public/js/src_modules/dropDownListProcessing.mjs +++ b/public/js/src_modules/dropDownListProcessing.mjs @@ -1,3 +1,5 @@ +"use strict"; + import { drawLineChartHighcharts } from "./chartLine.mjs"; import { diff --git a/public/js/src_modules/loadingIndicator.mjs b/public/js/src_modules/loadingIndicator.mjs index c8465f1..c1964b2 100644 --- a/public/js/src_modules/loadingIndicator.mjs +++ b/public/js/src_modules/loadingIndicator.mjs @@ -2,7 +2,7 @@ /** * Show a loading indicator at the start of an async task. The indicator consists of a spinner and a transluscent mask placed on top of page elements - * @returns {undefined} + * @returns {undefined} undefined */ const showLoadingSpinner = function () { const loadingIndicatorMask = document.querySelector("#loadingIndicator"); @@ -14,7 +14,7 @@ const showLoadingSpinner = function () { /** * Hide the loading indicator after completion of the async tasks - * @returns {undefined} + * @returns {undefined} undefined */ const hideLoadingSpinner = function () { const loadingIndicatorMask = document.querySelector("#loadingIndicator"); @@ -24,4 +24,27 @@ const hideLoadingSpinner = function () { loadingIconSpinner.style.display = "none"; }; -export { showLoadingSpinner, hideLoadingSpinner }; +/** + * Disable the button used to trigger the drawing of charts + * + * @returns {undefined} undefined + */ +const disableDrawChartButton = function () { + document.querySelector("#btn-draw-chart").disabled = true; +}; + +/** + * Enable the button used to trigger the drawing of charts + * + * @returns {undefined} undefined + */ +const enableDrawChartButton = function () { + document.querySelector("#btn-draw-chart").disabled = false; +}; + +export { + showLoadingSpinner, + hideLoadingSpinner, + disableDrawChartButton, + enableDrawChartButton, +}; diff --git a/public/js/thirdparty/scripts.js b/public/js/thirdparty/scripts.js index 0b2fd5c..82e16ea 100644 --- a/public/js/thirdparty/scripts.js +++ b/public/js/thirdparty/scripts.js @@ -1,22 +1,27 @@ /*! - * Start Bootstrap - SB Admin v6.0.2 (https://startbootstrap.com/template/sb-admin) - * Copyright 2013-2020 Start Bootstrap - * Licensed under MIT (https://github.com/StartBootstrap/startbootstrap-sb-admin/blob/master/LICENSE) - */ - (function($) { - "use strict"; + * Start Bootstrap - SB Admin v7.0.3 (https://startbootstrap.com/template/sb-admin) + * Copyright 2013-2021 Start Bootstrap + * Licensed under MIT (https://github.com/StartBootstrap/startbootstrap-sb-admin/blob/master/LICENSE) + */ +// +// Scripts +// - // Add active state to sidbar nav links - var path = window.location.href; // because the 'href' property of the DOM element is the absolute path - $("#layoutSidenav_nav .sb-sidenav a.nav-link").each(function() { - if (this.href === path) { - $(this).addClass("active"); - } - }); - - // Toggle the side navigation - $("#sidebarToggle").on("click", function(e) { - e.preventDefault(); - $("body").toggleClass("sb-sidenav-toggled"); +window.addEventListener("DOMContentLoaded", (event) => { + // Toggle the side navigation + const sidebarToggle = document.body.querySelector("#sidebarToggle"); + if (sidebarToggle) { + // Uncomment Below to persist sidebar toggle between refreshes + // if (localStorage.getItem('sb|sidebar-toggle') === 'true') { + // document.body.classList.toggle('sb-sidenav-toggled'); + // } + sidebarToggle.addEventListener("click", (event) => { + event.preventDefault(); + document.body.classList.toggle("sb-sidenav-toggled"); + localStorage.setItem( + "sb|sidebar-toggle", + document.body.classList.contains("sb-sidenav-toggled") + ); }); -})(jQuery); + } +}); -- GitLab