diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml
index 05e5593f..e9222f63 100644
--- a/.github/workflows/codespell.yml
+++ b/.github/workflows/codespell.yml
@@ -1,6 +1,9 @@
name: Codespell
on:
+ push:
+ branches:
+ - '**'
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
diff --git a/scripts/pi-hole/js/footer.js b/scripts/pi-hole/js/footer.js
index be54e1c1..bddadaa5 100644
--- a/scripts/pi-hole/js/footer.js
+++ b/scripts/pi-hole/js/footer.js
@@ -12,6 +12,24 @@
var settingsLevel = 0;
+const REFRESH_INTERVAL = {
+ logs: 500, // 0.5 sec (logs page)
+ summary: 1000, // 1 sec (dashboard)
+ blocking: 10000, // 10 sec (all pages, sidebar)
+ metrics: 10000, // 10 sec (settings page)
+ system: 20000, // 20 sec (all pages, sidebar)
+ sensors: 20000, // 20 sec (all pages, sidebar)
+ query_types: 60000, // 1 min (dashboard)
+ upstreams: 60000, // 1 min (dashboard)
+ top_lists: 60000, // 1 min (dashboard)
+ messages: 60000, // 1 min (all pages)
+ version: 120000, // 2 min (all pages, footer)
+ ftl: 120000, // 2 min (all pages, sidebar)
+ hosts: 120000, // 2 min (settings page)
+ history: 600000, // 10 min (dashboard)
+ clients: 600000, // 10 min (dashboard)
+};
+
function secondsTimeSpanToHMS(s) {
var h = Math.floor(s / 3600); //Get whole hours
s -= h * 3600;
@@ -86,17 +104,23 @@ function countDown() {
}
function checkBlocking() {
+ // Skip if page is hidden
+ if (document.hidden) {
+ utils.setTimer(checkBlocking, REFRESH_INTERVAL.blocking);
+ return;
+ }
+
$.ajax({
url: "/api/dns/blocking",
method: "GET",
})
.done(function (data) {
piholeChanged(data.blocking);
- setTimeout(checkBlocking, 10000);
+ utils.setTimer(checkBlocking, REFRESH_INTERVAL.blocking);
})
.fail(function (data) {
apiFailure(data);
- setTimeout(checkBlocking, 30000);
+ utils.setTimer(checkBlocking, 3 * REFRESH_INTERVAL.blocking);
});
}
@@ -241,9 +265,8 @@ function updateFtlInfo() {
ftl.allow_destructive ? "" : "Destructive actions are disabled by a config setting"
);
- // Update every 120 seconds
clearTimeout(ftlinfoTimer);
- ftlinfoTimer = setTimeout(updateFtlInfo, 120000);
+ ftlinfoTimer = utils.setTimer(updateFtlInfo, REFRESH_INTERVAL.ftl);
})
.fail(function (data) {
apiFailure(data);
@@ -340,9 +363,9 @@ function updateSystemInfo() {
moment.duration(1000 * system.uptime).humanize() + " (running since " + startdate + ")"
);
$("#sysinfo-system-overlay").hide();
- // Update every 20 seconds
+
clearTimeout(systemTimer);
- systemTimer = setTimeout(updateSystemInfo, 20000);
+ systemTimer = utils.setTimer(updateSystemInfo, REFRESH_INTERVAL.system);
})
.fail(function (data) {
apiFailure(data);
@@ -395,7 +418,7 @@ function updateSensorsInfo() {
// Update every 20 seconds
clearTimeout(sensorsTimer);
- sensorsTimer = setTimeout(updateSensorsInfo, 20000);
+ sensorsTimer = utils.setTimer(updateSensorsInfo, REFRESH_INTERVAL.sensors);
})
.fail(function (data) {
apiFailure(data);
@@ -564,9 +587,8 @@ function updateVersionInfo() {
'To install updates, run pihole -up.'
);
- // Update every 120 seconds
clearTimeout(versionTimer);
- versionTimer = setTimeout(updateVersionInfo, 120000);
+ versionTimer = utils.setTimer(updateVersionInfo, REFRESH_INTERVAL.version);
});
}
@@ -589,8 +611,8 @@ $(function () {
if (window.location.pathname !== "/admin/login") {
// Run check immediately after page loading ...
utils.checkMessages();
- // ... and once again with five seconds delay
- setTimeout(utils.checkMessages, 5000);
+ // ... and then periodically
+ utils.setInter(utils.checkMessages, REFRESH_INTERVAL.messages);
}
});
diff --git a/scripts/pi-hole/js/index.js b/scripts/pi-hole/js/index.js
index 03371648..160f89f0 100644
--- a/scripts/pi-hole/js/index.js
+++ b/scripts/pi-hole/js/index.js
@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
-/* global utils:false, Chart:false, apiFailure:false, THEME_COLORS:false, customTooltips:false, htmlLegendPlugin:false,doughnutTooltip:false, ChartDeferred:false */
+/* global utils:false, Chart:false, apiFailure:false, THEME_COLORS:false, customTooltips:false, htmlLegendPlugin:false,doughnutTooltip:false, ChartDeferred:false, REFRESH_INTERVAL: false */
// Define global variables
var timeLineChart, clientsChart;
@@ -71,16 +71,14 @@ function updateQueriesOverTime() {
timeLineChart.update();
})
.done(function () {
- // Reload graph after 10 minutes
failures = 0;
- setTimeout(updateQueriesOverTime, 600000);
+ utils.setTimer(updateQueriesOverTime, REFRESH_INTERVAL.history);
})
.fail(function () {
failures++;
if (failures < 5) {
- // Try again after 1 minute only if this has not failed more
- // than five times in a row
- setTimeout(updateQueriesOverTime, 60000);
+ // Try again ´only if this has not failed more than five times in a row
+ utils.setTimer(updateQueriesOverTime, 0.1 * REFRESH_INTERVAL.history);
}
})
.fail(function (data) {
@@ -123,8 +121,7 @@ function updateQueryTypesPie() {
queryTypePieChart.update("none");
})
.done(function () {
- // Reload graph after minute
- setTimeout(updateQueryTypesPie, 60000);
+ utils.setTimer(updateQueryTypesPie, REFRESH_INTERVAL.query_types);
})
.fail(function (data) {
apiFailure(data);
@@ -185,14 +182,13 @@ function updateClientsOverTime() {
.done(function () {
// Reload graph after 10 minutes
failures = 0;
- setTimeout(updateClientsOverTime, 600000);
+ utils.setTimer(updateClientsOverTime, REFRESH_INTERVAL.clients);
})
.fail(function () {
failures++;
if (failures < 5) {
- // Try again after 1 minute only if this has not failed more
- // than five times in a row
- setTimeout(updateClientsOverTime, 60000);
+ // Try again only if this has not failed more than five times in a row
+ utils.setTimer(updateClientsOverTime, 0.1 * REFRESH_INTERVAL.clients);
}
})
.fail(function (data) {
@@ -253,8 +249,7 @@ function updateForwardDestinationsPie() {
forwardDestinationPieChart.update("none");
})
.done(function () {
- // Reload graph after one minute
- setTimeout(updateForwardDestinationsPie, 60000);
+ utils.setTimer(updateForwardDestinationsPie, REFRESH_INTERVAL.upstreams);
})
.fail(function (data) {
apiFailure(data);
@@ -382,7 +377,7 @@ function updateTopLists() {
updateTopClientsTable(false);
// Update top lists data every 10 seconds
- setTimeout(updateTopLists, 10000);
+ utils.setTimer(updateTopLists, REFRESH_INTERVAL.top_lists);
}
function glowIfChanged(elem, textData) {
@@ -392,13 +387,7 @@ function glowIfChanged(elem, textData) {
}
}
-function updateSummaryData(runOnce) {
- var setTimer = function (timeInSeconds) {
- if (!runOnce) {
- setTimeout(updateSummaryData, timeInSeconds * 1000);
- }
- };
-
+function updateSummaryData(runOnce = false) {
$.getJSON("/api/stats/summary", function (data) {
var intl = new Intl.NumberFormat();
glowIfChanged($("span#dns_queries"), intl.format(parseInt(data.queries.total, 10)));
@@ -422,10 +411,10 @@ function updateSummaryData(runOnce) {
}, 500);
})
.done(function () {
- setTimer(1);
+ if (!runOnce) utils.setTimer(updateSummaryData, REFRESH_INTERVAL.summary);
})
.fail(function (data) {
- setTimer(300);
+ utils.setTimer(updateSummaryData, 3 * REFRESH_INTERVAL.summary);
apiFailure(data);
});
}
diff --git a/scripts/pi-hole/js/settings-system.js b/scripts/pi-hole/js/settings-system.js
index 4a0844f4..5bbe4e1a 100644
--- a/scripts/pi-hole/js/settings-system.js
+++ b/scripts/pi-hole/js/settings-system.js
@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
-/* global apiFailure:false, Chart:false, THEME_COLORS:false, customTooltips:false, htmlLegendPlugin:false,doughnutTooltip:false, ChartDeferred:false */
+/* global apiFailure:false, Chart:false, THEME_COLORS:false, customTooltips:false, htmlLegendPlugin:false,doughnutTooltip:false, ChartDeferred:false, REFRESH_INTERVAL: false, utils: false */
var hostinfoTimer = null;
var cachePieChart = null;
@@ -105,9 +105,8 @@ function updateHostInfo() {
" " +
uname.machine
);
- // Update every 120 seconds
clearTimeout(hostinfoTimer);
- hostinfoTimer = setTimeout(updateHostInfo, 120000);
+ hostinfoTimer = utils.setTimer(updateHostInfo, REFRESH_INTERVAL.hosts);
})
.fail(function (data) {
apiFailure(data);
@@ -173,9 +172,8 @@ function updateMetrics() {
);
$("div[id^='sysinfo-metrics-overlay']").hide();
- // Update every 10 seconds
clearTimeout(metricsTimer);
- metricsTimer = setTimeout(updateMetrics, 10000);
+ metricsTimer = utils.setTimer(updateMetrics, REFRESH_INTERVAL.metrics);
})
.fail(function (data) {
apiFailure(data);
diff --git a/scripts/pi-hole/js/taillog.js b/scripts/pi-hole/js/taillog.js
index 935cd9cd..486cc321 100644
--- a/scripts/pi-hole/js/taillog.js
+++ b/scripts/pi-hole/js/taillog.js
@@ -5,14 +5,11 @@
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
-/* global moment: false, apiFailure: false, utils: false */
+/* global moment: false, apiFailure: false, utils: false, REFRESH_INTERVAL: false */
var nextID = 0;
var lastPID = -1;
-// Check every 0.5s for fresh data
-const interval = 500;
-
// Maximum number of lines to display
const maxlines = 5000;
@@ -26,7 +23,7 @@ const markUpdates = true;
function getData() {
// Only update when spinner is spinning
if (!$("#feed-icon").hasClass("fa-play")) {
- window.setTimeout(getData, interval);
+ utils.setTimer(getData, REFRESH_INTERVAL.logs);
return;
}
@@ -63,7 +60,7 @@ function getData() {
$("#output").html("*** Log file is empty ***");
}
- window.setTimeout(getData, interval);
+ utils.setTimer(getData, REFRESH_INTERVAL.logs);
return;
}
@@ -107,11 +104,11 @@ function getData() {
// Set filename
$("#filename").text(data.file);
- window.setTimeout(getData, interval);
+ utils.setTimer(getData, REFRESH_INTERVAL.logs);
})
.fail(function (data) {
apiFailure(data);
- window.setTimeout(getData, 5 * interval);
+ utils.setTimer(getData, 5 * REFRESH_INTERVAL.logs);
});
}
diff --git a/scripts/pi-hole/js/utils.js b/scripts/pi-hole/js/utils.js
index 3e1b8af7..4d893111 100644
--- a/scripts/pi-hole/js/utils.js
+++ b/scripts/pi-hole/js/utils.js
@@ -616,6 +616,42 @@ function listAlert(type, items, data) {
);
}
+// Function that calls a function only if the page is currently visible. This is
+// useful to prevent unnecessary API calls when the page is not visible (e.g.
+// when the user is on another tab).
+function callIfVisible(func) {
+ if (document.hidden) {
+ // Page is not visible, try again in 1 second
+ window.setTimeout(callIfVisible, 1000, func);
+ return;
+ }
+
+ // Page is visible, call function instead
+ func();
+}
+
+// Timer that calls a function after milliseconds but only if the
+// page is currently visible. We cancel possibly running timers for the same
+// function before starting a new one to prevent multiple timers running at
+// the same time causing unnecessary identical API calls when the page is
+// visible again.
+function setTimer(func, interval) {
+ // Cancel possibly running timer
+ window.clearTimeout(func.timer);
+ // Start new timer
+ func.timer = window.setTimeout(callIfVisible, interval, func);
+}
+
+// Same as setTimer() but calls the function every milliseconds
+function setInter(func, interval) {
+ // Cancel possibly running timer
+ window.clearTimeout(func.timer);
+ // Start new timer
+ func.timer = window.setTimeout(callIfVisible, interval, func);
+ // Restart timer
+ window.setTimeout(setInter, interval, func, interval);
+}
+
window.utils = (function () {
return {
escapeHtml: escapeHtml,
@@ -649,5 +685,7 @@ window.utils = (function () {
hexEncode: hexEncode,
hexDecode: hexDecode,
listsAlert: listAlert,
+ setTimer: setTimer,
+ setInter: setInter,
};
})();