(() => { const badges = document.querySelectorAll('[data-share-unread-count]'); if (!badges.length) return; const workspace = document.querySelector('[data-share-read-url]'); const scroller = workspace?.querySelector('[data-conversation]'); const countUrl = badges[0].dataset.countUrl; let running = false; const cookie = name => document.cookie.split('; ').find(row => row.startsWith(`${name}=`))?.split('=').slice(1).join('=') || ''; const refresh = async () => { if (running || document.visibilityState !== 'visible') return; running = true; try { const ids = []; if (scroller) { const bounds = scroller.getBoundingClientRect(); scroller.querySelectorAll('[data-message-id]').forEach(message => { const box = message.getBoundingClientRect(); if (box.bottom > Math.max(bounds.top, 0) && box.top < Math.min(bounds.bottom, innerHeight)) ids.push(message.dataset.messageId); }); } const body = new URLSearchParams(); ids.forEach(id => body.append('message_ids', id)); const response = await fetch(workspace?.dataset.shareReadUrl || countUrl, workspace ? { method: 'POST', body, headers: {'X-CSRFToken': cookie('csrftoken')}, cache: 'no-store', credentials: 'same-origin' } : {cache: 'no-store', credentials: 'same-origin'}); if (response.status === 403 && workspace) { scroller.querySelectorAll('[data-message], .date-divider, .conversation-empty').forEach(item => item.remove()); const notice = document.createElement('p'); notice.className = 'conversation-empty'; notice.textContent = 'دسترسی به این اشتراک لغو شده است.'; scroller.append(notice); workspace.removeAttribute('data-poll-url'); const counts = await fetch(countUrl, {cache: 'no-store', credentials: 'same-origin'}); if (counts.ok) { const data = await counts.json(); badges.forEach(badge => {badge.textContent = data.unread_shares; badge.hidden = !data.unread_shares;}); } return; } if (!response.ok) return; const data = await response.json(); badges.forEach(badge => {badge.textContent = data.unread_shares; badge.hidden = !data.unread_shares;}); } catch (_) { // A failed request leaves the count and read status available for retry. } finally { running = false; } }; scroller?.addEventListener('scroll', refresh, {passive: true}); document.addEventListener('visibilitychange', refresh); window.addEventListener('pageshow', refresh); window.addEventListener('focus', refresh); document.body.addEventListener('htmx:afterSwap', refresh); setInterval(refresh, workspace ? 3000 : 15000); refresh(); })();