bv?sortDir:0})}
function sortBy(key){if(sortKey===key)sortDir*=-1;else{sortKey=key;sortDir=1}render(lastItems)}
function renderSortState(){["name","size","modified"].forEach(k=>{const el=$("sort-"+k);if(el)el.textContent=sortKey===k?(sortDir===1?"↑":"↓"):""})}
function emptyState(title,text,action=""){const writable=currentMask.includes("W");let buttons="";if(action==="folder"&&writable)buttons='新建文件夹 新建文本
';if(action==="upload"&&writable)buttons='上传文件 新建文件夹
';return ''+svgIcon("folder")+'
'+esc(title)+' '+esc(text)+'
'+buttons+'
'}
function render(items){lastItems=sortItems(items);selected=new Set([...selected].filter(p=>lastItems.some(f=>(current?current+"/":"")+f.name===p)));renderList(lastItems);renderGrid(lastItems);updateSelection();renderSortState()}
-function renderList(items){const body=$("files");body.innerHTML=items.length?items.map(f=>{const p=current?current+"/"+f.name:f.name,canRead=(f.mask||"").includes("R"),canWrite=(f.mask||"").includes("W"),canDelete=(f.mask||"").includes("D"),selectedNow=selected.has(p),drag=' draggable="true"';const perms=' ';return ''+iconFor(f)+' '+esc(f.name)+'
'+(f.dir?"—":fmt(f.size))+' '+esc(f.modified||"")+' '+perms+'
'}).join(""):''+emptyState("这个文件夹还是空的","可以上传文件,或者创建一个新的文件夹。","upload")+' '}
-function renderGrid(items){$("grid").innerHTML=items.length?items.map(f=>{const p=current?current+"/"+f.name:f.name,canRead=(f.mask||"").includes("R"),type=fileType(f),selectedNow=selected.has(p),drag=' draggable="true"';let thumb=iconFor(f);if(type==="image"&&canRead)thumb=' ';const tileClass=(f.dir?'folder-tile ':'')+(['video','audio'].includes(type)?'media-tile':'');const meta=f.dir?'文件夹':fmt(f.size);return ''+thumb+'
'+iconFor(f)+'
'+esc(f.name)+'
'+meta+' '+(f.modified?''+esc(f.modified)+' ':'')+'
'}).join(''):emptyState("这个文件夹还是空的","上传文件或创建内容后,它们会显示在这里。","upload")}
+function renderList(items){const body=$("files");body.innerHTML=items.length?items.map(f=>{const p=current?current+"/"+f.name:f.name,canRead=(f.mask||"").includes("R"),canWrite=(f.mask||"").includes("W"),canDelete=(f.mask||"").includes("D"),selectedNow=selected.has(p),drag=' draggable="true"';const perms=' ';return ''+iconFor(f)+' '+esc(f.name)+'
'+(f.dir?"—":fmt(f.size))+' '+esc(f.modified||"")+' '+perms+'
'}).join(""):''+emptyState("这个文件夹还是空的","可以上传文件,或者创建一个新的文件夹。","upload")+' '}
+function renderGrid(items){$("grid").innerHTML=items.length?items.map(f=>{const p=current?current+"/"+f.name:f.name,canRead=(f.mask||"").includes("R"),type=fileType(f),selectedNow=selected.has(p),drag=' draggable="true"';let thumb=iconFor(f);if(type==="image"&&canRead)thumb=' ';const tileClass=(f.dir?'folder-tile ':'')+(['video','audio'].includes(type)?'media-tile':'');const meta=f.dir?'文件夹':fmt(f.size);return ''+thumb+'
'+iconFor(f)+'
'+esc(f.name)+'
'+meta+' '+(f.modified?''+esc(f.modified)+' ':'')+'
'}).join(''):emptyState("这个文件夹还是空的","上传文件或创建内容后,它们会显示在这里。","upload")}
function fileDragStart(e,p){const paths=selected.has(p)?[...selected]:[p];e.dataTransfer.effectAllowed="move";e.dataTransfer.setData("text/chfs-paths",JSON.stringify(paths));e.currentTarget.classList.add("dragging")}
function fileDragEnd(e){e.currentTarget.classList.remove("dragging");document.querySelectorAll('.drop-target').forEach(el=>el.classList.remove('drop-target'))}
function folderDragOver(e,target){if(!e.dataTransfer?.types.includes('text/chfs-paths'))return;e.preventDefault();if(target===current||target===""||[...selected].some(p=>p===target||target.startsWith(p+'/')))return;e.dataTransfer.dropEffect="move";e.currentTarget.classList.add('drop-target')}
@@ -120,7 +123,7 @@ function setupDropZone(){const z=$("dropZone"),main=$("fileCard");let depth=0;[d
function uploadOne(file,row,relativePath=file.name,task=null){return new Promise(resolve=>{const xhr=new XMLHttpRequest(),fd=new FormData();if(task)task.xhr=xhr;const clean=String(relativePath||file.name).replace(/\\/g,'/').replace(/^\/+|\/+$/g,'');const parts=clean.split('/');const name=parts.pop()||file.name;const folder=parts.length?[current,...parts].filter(Boolean).join('/') : current;fd.append("folder",folder);fd.append("file",file,name);const meta=row.querySelector('.meta'),bar=row.querySelector('i');xhr.open('POST','/chfs/upload');xhr.upload.onprogress=e=>{if(e.lengthComputable){const pct=Math.round(e.loaded/e.total*100);bar.style.width=pct+'%';meta.textContent=fmt(file.size)+' · '+pct+'%'}};xhr.onload=()=>{const ok=xhr.status>=200&&xhr.status<300;if(ok){bar.style.width='100%';meta.textContent=fmt(file.size)+' · 完成'}else{meta.textContent='上传失败'+(xhr.status?' · '+xhr.status:'');bar.style.width='0'};if(task)task.xhr=null;resolve(ok)};xhr.onerror=()=>{if(task&&task.state==='cancelled'){meta.textContent=fmt(file.size)+' · 已取消'}else{meta.textContent='网络错误';bar.style.width='0'};if(task)task.xhr=null;resolve(false)};xhr.onabort=()=>{if(task)task.xhr=null;resolve(false)};xhr.send(fd)})}
let searchMode=false,searchItems=[];
$("search").addEventListener("keydown",async e=>{if(e.key!=="Enter")return;const s=e.target.value.trim();if(!s){searchMode=false;searchItems=[];refresh();return}try{const d=await api("/chfs/search?str="+encodeURIComponent(s));renderSearch(d.files||[])}catch(x){fail(x.message)}})
-function renderSearch(items){searchMode=true;searchItems=items;selected.clear();$("crumb").textContent="搜索结果";$("files").parentElement.hidden=false;$("grid").hidden=true;const body=$("files");body.innerHTML=items.length?items.map(f=>{const p=f.path,name=f.name||p.split("/").pop(),parent=p.includes("/")?p.slice(0,p.lastIndexOf("/")):"当前位置";return ''+iconFor(f)+' '+esc(name)+'
'+(f.dir?"—":fmt(f.size))+' '+esc(f.modified||"")+' '+esc(parent)+'
搜索结果
'}).join(""):''+emptyState("没有找到匹配文件","换一个关键词试试,或者清空搜索框返回当前位置。")+' ';updateSelection()}
+function renderSearch(items){searchMode=true;searchItems=items;selected.clear();$("crumb").textContent="搜索结果";$("files").parentElement.hidden=false;$("grid").hidden=true;const body=$("files");body.innerHTML=items.length?items.map(f=>{const p=f.path,name=f.name||p.split("/").pop(),parent=p.includes("/")?p.slice(0,p.lastIndexOf("/")):"当前位置";return ''+iconFor(f)+' '+esc(name)+'
'+(f.dir?"—":fmt(f.size))+' '+esc(f.modified||"")+' '+esc(parent)+'
搜索结果
'}).join(""):''+emptyState("没有找到匹配文件","换一个关键词试试,或者清空搜索框返回当前位置。")+' ';updateSelection()}
function selectSearchItem(p){selected.clear();if(p)selected.add(p);updateSelection()}
function toggleSearchItem(p,checked){if(checked)selected.add(p);else selected.delete(p);updateSelection()}
function searchMenu(e,f){e.preventDefault();selectSearchItem(f.path);let html='';html+='下载 ';if(f.dir)html+='下载 ZIP ';html+='打开 ';$("context").innerHTML=html;$("context").style.left=Math.min(e.clientX,innerWidth-190)+'px';$("context").style.top=Math.min(e.clientY,innerHeight-160)+'px';$("context").style.display='block'}