# aardio 范例: 极简 WebDAV 文件管理器 - DAV123

```aardio
import win.ui;
/*DSG{{*/
mainForm = win.form(text="极简 WebDAV 文件管理器 - DAV123";right=1099;bottom=699)
mainForm.add()
/*}}*/

import fsys;
import fsys.dlg;
import fsys.table;
import string.escape2;
import web.view;
import web.dav.client;

var wb = web.view(mainForm);
var config = fsys.table(io.appData("aardio/std/example/webdav/client-wv"));

var davClient; 
var transferCancelled = thread.var();

// wb.external 必须在加载网页之前先定义
wb.external = {
	cancelTransfer = function(){
		transferCancelled.set(true);//取消上传下载
	};
	
    connect = function(url, username, password){
            
        davClient = web.dav.client(url);
        config.url = url;
        config.username = username; 
 
       	password = string.escape2(password); //解码使用
        config.password = string.escape2(password,'C'/*key*/);	//编码存储 
        config.save()
        
        ..thread.invoke( 
        	function(mainForm,wb,davClient,username, password){
				//登录或匿名登录，多线程共享会话
        		var success,err =  davClient.login(username, password);
        		wb.invoke("onConnected", success,err,davClient.serverRootPath);	
        		mainForm.currentPath = davClient.serverRootPath;
				
        	},mainForm,wb,davClient,username, password );
    };

    listFiles = function(path){  
        
         if(!davClient) return; 
         mainForm.currentPath = path;
         
         ..thread.invoke( 
        	function(wb,davClient,path){
				 var files,err,errCode = davClient.list(path, 1); 
				 wb.invoke("renderFiles", files || []);
				 if(err){
				 	wb.invoke("showToast",err,"error");
				 }
        	},wb,davClient,path);  
    };

    selectAndUpload = function(remotePath,localPath){
        if(!localPath){
        	localPath = fsys.dlg.open("*.*|*.*","选择要上传的文件",,mainForm);
        	if(!localPath) return;	
        }
        
        var fileName = fsys.getFileName(localPath);
        var fileSize = io.getSize(localPath) : 0;
        
        var fullRemotePath = remotePath;
        if(remotePath[#remotePath]!='/'#) fullRemotePath = fullRemotePath + "/";
        fullRemotePath = fullRemotePath ++ fileName; 

        wb.invoke("onUploadStart", fileName, fileSize);
		transferCancelled.set(false);
		
		thread.invoke( 
			function(davClient,wb,fullRemotePath,localPath,transferCancelled){
	 
        		var onSend = function(sendSize, totalSize){
            		if(transferCancelled.get()){
            			return false; //取消时 davClient.upload 返回值为： false,"Cancelled"
            		}
            		
            		if(totalSize > 0){ 
                		var percent = sendSize * 100 / totalSize;
               			wb.invoke("onUploadProgress", percent, sendSize, totalSize);
            		}
        		}; 
        		
        		var ok, err = davClient.upload(fullRemotePath,localPath, ,onSend); 
        		wb.invoke("onUploadEnd", ok, err);
			},davClient,wb,fullRemotePath,localPath,transferCancelled
		)
    };

    downloadFile = function(remotePath){ 
        var fileName = fsys.getFileName(remotePath);
        var localPath = fsys.dlg.save("*.*|*.*", "保存文件",,mainForm,,fileName);
        if(!localPath) return;

        // 通知前端下载开始
        wb.invoke("onDownloadStart", fileName);
        transferCancelled.set(false);
		
		thread.invoke( 
			function(davClient,wb,remotePath,localPath,transferCancelled){

        		var onReceive = function(receivedSize, totalSize){
        		    if(transferCancelled.get()){
            			return false; //取消时 davClient.download 返回值为： false,"Cancelled"
            		}
          		
            		var percent = receivedSize * 100 / totalSize;
                	wb.invoke("onDownloadProgress", percent, receivedSize, totalSize);
        		};
		
        		var ok, err = davClient.download(remotePath,localPath,onReceive); 
		
        		// 通知前端下载结束
        		wb.invoke("onDownloadEnd", ok, err);
        	},davClient,wb,remotePath,localPath,transferCancelled
		)
    };
    
    preview = function(remotePath){ 
      
        // 通知前端下载开始
        wb.invoke("onDownloadStart", fsys.getFileName(remotePath));
        transferCancelled.set(false);
		
		thread.invoke( 
			function(davClient,wb,remotePath,localPath,transferCancelled){

        		var onReceive = function(receivedSize, totalSize){
        		    if(transferCancelled.get()){
            			return false; //取消时 davClient.download 返回值为： false,"Cancelled"
            		}
          		
            		var percent = receivedSize * 100 / totalSize;
                	wb.invoke("onDownloadProgress", percent, receivedSize, totalSize);
        		};
		
        		var data,err = davClient.get(remotePath,onReceive);  
		
        		// 通知前端下载结束
        		wb.invoke("onDownloadEnd", !!data, err);
        		
        		if(data){
        		    var html;
        		    if(..string.endsWith(remotePath,".md",true)){
        				import string.markdown;
        				
        				//为保证安全，屏蔽所有 HTML 标签（1/*_MD_HTML_SKIP_HTML*/）
        				var html = string.markdown(,,1/*_MD_HTML_SKIP_HTML*/).render(data);
        				html = `<html>
<head>
<meta charset="utf-8">
<meta http-equiv='content-language' content='zh-cn'>
<link rel="stylesheet" href="/zh-cn/doc/css/markdown.css">
<script src="/zh-cn/doc/js/prism.js"></script>
<link rel="stylesheet" href="https://lib.baomitu.com/font-awesome/6.6.0/css/fontawesome.min.css">
<link rel="stylesheet" href="https://lib.baomitu.com/font-awesome/6.6.0/css/solid.min.css">
</head>
<body class="markdown-body">`+html+`</body> 
</html>`
						wb.davPreview(html);
					} 
					
        		}
        	},davClient,wb,remotePath,localPath,transferCancelled
		)
    };

    deleteItem = function(path){
        var ok, err = davClient.delete(path,token);
        if(ok){
            wb.invoke("refresh");
        } else {
            mainForm.msgbox("删除失败,状态码：" + (err || "未知错误"));
        } 
    };

    createFolder = function(parentPath, name){
        var fullPath = parentPath;
        if(!string.endsWith(fullPath, "/")) fullPath = fullPath + "/";
        fullPath = fullPath + name;

        var ok, err = davClient.mkdir(fullPath);
        if(ok){
            wb.invoke("refresh");
        } else {
            mainForm.msgbox("创建文件夹失败,状态码：" + (err || "未知错误"));
        }
    };

    renameItem = function(oldPath, parentPath, newName){
        var newPath = parentPath;
        if(!string.endsWith(newPath, "/")) newPath = newPath + "/";
        newPath = newPath + newName;

        // 如果原路径以 / 结尾（是目录）,新路径也要以 / 结尾
        if(string.endsWith(oldPath, "/")){
            newPath = newPath + "/";
        }

        var ok, err = davClient.move(oldPath, newPath, true);
        if(ok){
            wb.invoke("refresh");
        } else {
            mainForm.msgbox("重命名失败,状态码：" + (err || "未知错误"));
        }
    };
};

wb.html = $"/client.ui.html";

wb.davPreview = function(html){

	var frmPreview = win.form(text="Markdown 预览";
		right=671;bottom=645,parent=mainForm;exmode="none";mode="popup") 

	import web.view;
	var wb2 = web.view(frmPreview);
	wb2.html = html;
	
	frmPreview.show();
}

wb.onNewWindow = function(url){
	
	return function(){ 
 		var filePath = inet.url.getFilePath(url)
 		if(filePath){
 			wb.external.selectAndUpload( wb.eval("currentPath"),filePath);
 		}
 	}
}

wb.wait();
wb.invoke(`(url,uid,pwd)=>{
	serverUrl.value=url;
	username.value=uid;
	password.value=pwd;
}`,config.url || 'https://rebun.infini-cloud.net/dav/'
,config.username || "aardio"
,config.password || "jpg3mPzMa25JG7SX"); 

mainForm.show();
win.loopMessage();
```