2 lines
6.2 KiB
JavaScript
2 lines
6.2 KiB
JavaScript
export const torrentTableRendererSource = " function renderMobile(){\n const list=$('mobileList');\n if(!list) return;\n const src=mobileVisibleRows();\n const rows=src.slice(0,250);\n renderMobileFilters(src);\n list.innerHTML=rows.map(t=>{\n const errorLog=torrentErrorLog(t);\n const op=activeOperationFor(t);\n const classes=[selected.has(t.hash)?'selected':'', op?'torrent-operating':'', errorLog?'torrent-warning':''].filter(Boolean).join(' ');\n const lines=mobileInfoLines(t);\n // Note: Mobile details use a separate corner button so user-configurable action buttons keep their current order.\n return `<div class=\"mobile-card ${classes}\" data-hash=\"${esc(t.hash)}\" title=\"${esc(errorLog||op?.label||'')}\"><div class=\"mobile-card-header\"><div class=\"name\">${torrentNameStatusIcon(t)}${esc(t.name)}</div><button class=\"btn btn-xs btn-outline-info mobile-details-btn\" type=\"button\" title=\"Torrent details\" aria-label=\"Open torrent details\"><i class=\"fa-solid fa-circle-info\"></i></button></div>${lines.primary?`<div class=\"small text-muted\">${lines.primary}</div>`:''}${lines.secondary?`<div class=\"small\">${lines.secondary}</div>`:''}${mobileColumns.path?`<div class=\"small text-truncate\">${esc(t.path)}</div>`:''}<div class=\"mobile-actions\"><button class=\"btn btn-xs btn-outline-success\" data-action=\"start\" title=\"Start\"><i class=\"fa-solid fa-play\"></i></button><button class=\"btn btn-xs btn-outline-warning\" data-action=\"pause\" title=\"Pause\"><i class=\"fa-solid fa-pause\"></i></button><button class=\"btn btn-xs btn-outline-secondary\" data-action=\"stop\" title=\"Stop\"><i class=\"fa-solid fa-stop\"></i></button><button class=\"btn btn-xs btn-outline-primary\" data-action=\"move\" title=\"Move\"><i class=\"fa-solid fa-folder-open\"></i></button><button class=\"btn btn-xs btn-outline-primary\" data-mobile-modal=\"label\" title=\"Set label\"><i class=\"fa-solid fa-tag\"></i></button><button class=\"btn btn-xs btn-outline-info\" data-action=\"recheck\" title=\"Force recheck\"><i class=\"fa-solid fa-rotate\"></i></button><button class=\"btn btn-xs btn-outline-primary\" data-action=\"reannounce\" title=\"Reannounce\"><i class=\"fa-solid fa-bullhorn\"></i></button><button class=\"btn btn-xs btn-outline-danger\" data-action=\"remove\" title=\"Remove\"><i class=\"fa-solid fa-trash-can\"></i></button></div>${mobileColumns.progress?`<div class=\"mobile-progress\">${progress(t)}</div>`:''}</div>`;\n }).join('') || (hasTorrentSnapshot ? `<div class=\"empty\">No torrents.</div>` : loadingMarkup('Loading torrents...'));\n }\n function renderTable(){ updateBulkBar(); syncActiveFilterSelection(); renderCounts(); renderLabelFilters(); if(typeof renderHealthDashboard==='function') renderHealthDashboard(); if(typeof renderSmartViewsManager==='function') renderSmartViewsManager(); updateSortHeaders(); buildVisibleRows(); renderMobile(); const body=$('torrentBody'); if(!visibleRows.length){ body.innerHTML=hasTorrentSnapshot?`<tr><td colspan=\"${torrentColumnSpan()}\" class=\"empty\">No torrents for this filter.</td></tr>`:loadingTableRow('Loading torrents...'); return; } const wrap=$('tableWrap'); const rowHeight=torrentRowHeight(); const start=Math.max(0,Math.floor((wrap?.scrollTop||0)/rowHeight)-OVERSCAN); const count=Math.ceil((wrap?.clientHeight||500)/rowHeight)+OVERSCAN*2; const end=Math.min(visibleRows.length,start+count); const sig=`${renderVersion}:${start}:${end}:${visibleRows.length}:${sortState.key}:${sortState.dir}:${selected.size}:${activeFilter}:${activeTrackerFilter}:${compactTorrentListEnabled?1:0}:${$('searchBox')?.value||''}:${[...selected].slice(0,30).join(',')}`; if(sig===lastRenderSignature) return; lastRenderSignature=sig; const top=start*rowHeight,bottom=Math.max(0,(visibleRows.length-end)*rowHeight); body.innerHTML=(top?`<tr class=\"virtual-spacer\"><td colspan=\"${torrentColumnSpan()}\" style=\"height:${top}px\"></td></tr>`:'')+visibleRows.slice(start,end).map(renderRow).join('')+(bottom?`<tr class=\"virtual-spacer\"><td colspan=\"${torrentColumnSpan()}\" style=\"height:${bottom}px\"></td></tr>`:''); applyColumnVisibility(); }\n function scheduleRender(force=false){ if(force){lastRenderSignature='';renderVersion++;} if(renderPending)return; renderPending=true; requestAnimationFrame(()=>{renderPending=false;renderTable();}); }\n function patchRows(msg){ if(msg.summary) torrentSummary=msg.summary; (msg.removed||[]).forEach(h=>{torrents.delete(h);selected.delete(h);activeOperations.delete(h);if(selectedHash===h)selectedHash=null;}); (msg.added||[]).forEach(t=>torrents.set(t.hash,t)); (msg.updated||[]).forEach(p=>torrents.set(p.hash,{...(torrents.get(p.hash)||{}),...p})); if(msg.speed_status) applyLiveSpeedStats(msg.speed_status); else updateBrowserSpeedTitle(); scheduleRender(true); if(selectedHash&&torrents.has(selectedHash)&&activeTab()==='general') renderGeneral(); }\n function applyLiveTorrentStats(msg){ (msg.updated||[]).forEach(p=>{ if(torrents.has(p.hash)) torrents.set(p.hash,{...(torrents.get(p.hash)||{}),...p}); }); if(msg.speed_status) applyLiveSpeedStats(msg.speed_status); else updateBrowserSpeedTitle(); scheduleRender(true); if(selectedHash&&torrents.has(selectedHash)&&activeTab()==='general') renderGeneral(); }\n function selectedHashes(){ return [...selected]; }\n function updateBulkBar(){\n const bar=$(\"bulkBar\");\n if(!bar) return;\n // Note: The desktop bulk toolbar is hidden in mobile mode; mobile has its own compact actions in the filter bar.\n const isMobileMode = document.body.classList.contains('mobile-mode');\n const show = selected.size > 1 && !isMobileMode;\n bar.classList.toggle(\"d-none\", !show);\n bar.setAttribute('aria-hidden', show ? 'false' : 'true');\n const c=$(\"bulkSelectedCount\");\n if(c) c.textContent=selected.size;\n }\n function setSelectionRange(hash, keepExisting=false){ const current=visibleRows.findIndex(t=>t.hash===hash); const last=visibleRows.findIndex(t=>t.hash===lastSelectedHash); if(current<0 || last<0){ selected.add(hash); lastSelectedHash=hash; return; } if(!keepExisting) selected.clear(); const a=Math.min(current,last), b=Math.max(current,last); visibleRows.slice(a,b+1).forEach(t=>selected.add(t.hash)); selectedHash=hash; }\n";
|