/** * GoingsOn - Emails Render * Row markup for the email/thread list. Extracted from emails.js so the * controller stays focused on data flow. Consumes the shared selection manager * via GoingsOn.emails.selection (resolved lazily at render time). */ (function() { 'use strict'; const esc = GoingsOn.utils.escapeHtml; const escAttr = GoingsOn.utils.escapeAttrValue; const escArg = GoingsOn.utils.escapeHandlerArg; /** * Render one thread row for the virtual scroller. * @param {Object} thread - Thread with mostRecentEmail + threadCount/hasUnread * @param {number} index - Row index (unused; kept for scroller signature parity) * @returns {string} HTML string */ function renderEmailItem(thread, index) { const e = thread.mostRecentEmail; // Use pre-computed field from backend (avoids JS date calculation) const isSnoozed = e.isSnoozed; const isSelected = GoingsOn.emails.selection.isSelected(e.id); const threadBadge = thread.threadCount > 1 ? `${thread.threadCount}` : ''; const labelBadges = (e.labels || []).map(l => `${esc(l)}` ).join(''); return `