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); })();