From 3c5420f8db8f4e46ea0b6c45012868aeac6726be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean=20Charles=20Del=C3=A9pine?= Date: Sat, 27 Jun 2026 12:18:09 +0200 Subject: [PATCH] fix(dynamic): handle dynamically inserted time elements via MutationObserver (#22) --- js/relative_time.js | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/js/relative_time.js b/js/relative_time.js index 2bd4d977b..68289b42f 100644 --- a/js/relative_time.js +++ b/js/relative_time.js @@ -214,12 +214,41 @@ } } - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', sweep); - } else { + + function init() { sweep(); + setTimeout(tick, 60 * 1000); + + // Watch for future DOM insertions (AJAX message loading). + if (window.MutationObserver) { + var observer = new MutationObserver(function(mutations) { + for (var i = 0; i < mutations.length; i++) { + var added = mutations[i].addedNodes; + for (var j = 0; j < added.length; j++) { + var node = added[j]; + if (node.nodeType !== 1) continue; + // The node itself. + if (node.matches && node.matches('time[is="time-ago"]')) { + register(node); + } + // Its descendants. + var children = node.querySelectorAll('time[is="time-ago"]'); + for (var k = 0; k < children.length; k++) { + register(children[k]); + } + } + } + }); + observer.observe(document.body || document.documentElement, { + childList: true, + subtree: true + }); + } } - // Kick off the refresh loop. - setTimeout(tick, 60 * 1000); + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } }());