// MusicRoom - Track Component // Pure rendering for track rows - no event handlers attached (function() { const M = window.MusicRoom; // Single source of truth for a track's display title function getTitle(track) { return track?.title?.trim() || (track?.filename || track?.id || "Unknown").replace(/\.[^.]+$/, ""); } /** * Render a track row element (pure rendering, no handlers) * @param {Object} track - Track object with id, title, filename, duration * @param {Object} config - Configuration options * @param {string} config.view - 'queue' | 'library' | 'playlist' * @param {number} config.index - Index in the list * @param {number} [config.displayIndex] - Display number (1-based) * @param {boolean} config.isSelected - Whether track is selected * @param {boolean} config.isCached - Whether track is cached locally * @param {boolean} config.isActive - Whether this is the currently playing track * @param {boolean} config.draggable - Whether element is draggable * @returns {HTMLElement} */ function render(track, config) { const { view, index, displayIndex, isSelected, isCached, isActive, draggable } = config; const div = document.createElement("div"); const trackId = track.id || track.filename; // Build class list const classes = ["track"]; if (isActive) classes.push("active"); if (isCached) classes.push("cached"); else classes.push("not-cached"); if (isSelected) classes.push("selected"); div.className = classes.join(" "); // Store data attributes div.dataset.index = index; div.dataset.trackId = trackId; div.dataset.view = view; // Build title const title = getTitle(track); div.title = title; // Build HTML const checkmark = isSelected ? '' : ''; const trackNum = displayIndex != null ? `${displayIndex}.` : ''; div.innerHTML = ` ${checkmark} ${trackNum} ${M.escapeHtml(title)} ${M.fmt(track.duration)} `; if (draggable) { div.draggable = true; } return div; } // Export M.trackComponent = { render, getTitle, escapeHtml: M.escapeHtml }; })();