diff --git a/views/layout_footer.php b/views/layout_footer.php
index e10a1ce..144b561 100644
--- a/views/layout_footer.php
+++ b/views/layout_footer.php
@@ -235,11 +235,12 @@
}
function loadNotifications() {
- fetch('/api/notifications.php', { credentials: 'same-origin' })
+ return fetch('/api/notifications.php', { credentials: 'same-origin' })
.then(function(r) { return r.json(); })
- .then(renderNotifications)
+ .then(function(data) { renderNotifications(data); return true; })
.catch(function() {
list.innerHTML = '
Could not load
';
+ return false;
});
}
@@ -261,9 +262,34 @@
document.addEventListener('click', function(e) { if (_open && wrapEl && !wrapEl.contains(e.target)) closePanel(); });
document.addEventListener('keydown', function(e) { if (e.key === 'Escape' && _open) closePanel(); });
- // Initial badge count + poll every 60s
+ // Poll every 60s while the tab is visible, backing off (up to 5 min) on
+ // repeated failures, and resuming immediately when the tab regains focus.
+ var POLL_INTERVAL = 60000;
+ var MAX_POLL_INTERVAL = 300000;
+ var _pollTimer = null;
+ var _failCount = 0;
+
+ function scheduleNextPoll(delay) {
+ clearTimeout(_pollTimer);
+ _pollTimer = setTimeout(pollNotifications, delay);
+ }
+
+ function pollNotifications() {
+ if (document.hidden) return;
+ loadNotifications().then(function(ok) {
+ _failCount = ok ? 0 : _failCount + 1;
+ var delay = ok ? POLL_INTERVAL : Math.min(POLL_INTERVAL * Math.pow(2, _failCount), MAX_POLL_INTERVAL);
+ scheduleNextPoll(delay);
+ });
+ }
+
+ document.addEventListener('visibilitychange', function() {
+ if (!document.hidden) pollNotifications();
+ });
+
+ // Initial badge count, then start the poll cycle
loadNotifications();
- setInterval(loadNotifications, 60000);
+ scheduleNextPoll(POLL_INTERVAL);
})();