权限与功能改进
This commit is contained in:
143
ui/script.js
143
ui/script.js
@@ -1,4 +1,5 @@
|
||||
afi = {
|
||||
auth: {},
|
||||
consts: {},
|
||||
params: {},
|
||||
elements: {},
|
||||
@@ -9,13 +10,39 @@ afi = {
|
||||
directcall: {},
|
||||
}
|
||||
|
||||
afi.auth = {
|
||||
isLoggedIn: false,
|
||||
|
||||
checkAuth: async function () {
|
||||
try {
|
||||
const res = await fetch(location.origin + afi.params.extraPath + '/auth', {
|
||||
method: 'GET',
|
||||
credentials: 'include'
|
||||
});
|
||||
this.isLoggedIn = (res.status === 200);
|
||||
return this.isLoggedIn;
|
||||
} catch (e) {
|
||||
this.isLoggedIn = false;
|
||||
return false;
|
||||
}
|
||||
},
|
||||
logout: function () {
|
||||
fetch(location.origin + afi.params.extraPath + '/auth', {
|
||||
method: 'GET',
|
||||
headers: { 'Authorization': 'Basic ' + btoa('invalid:invalid') },
|
||||
credentials: 'include'
|
||||
});
|
||||
this.isLoggedIn = false;
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
afi.consts = {
|
||||
leftPageWarn: "确认放弃正在进行的传输?",
|
||||
ensureDrop: () => !confirm('确认移动此对象?')
|
||||
}
|
||||
|
||||
afi.params = {
|
||||
readonly: readonly,
|
||||
extraPath: extraPath
|
||||
}
|
||||
|
||||
@@ -104,7 +131,6 @@ afi.utils = {
|
||||
try {
|
||||
this.getHighlight().classList.remove('highlight')
|
||||
} catch (e) {
|
||||
/* */
|
||||
}
|
||||
},
|
||||
isHelpMode: () => afi.elements.helpPanel.style.display === 'block',
|
||||
@@ -120,18 +146,37 @@ afi.utils = {
|
||||
afi.elements.table.style.display = 'table'
|
||||
afi.elements.helpToggle.innerText = "帮助菜单"
|
||||
afi.elements.helpToggle.onclick = afi.utils.helpOn
|
||||
}
|
||||
},
|
||||
updateButtons: function () {
|
||||
const isLogged = afi.auth.isLoggedIn;
|
||||
document.querySelectorAll('#operations a').forEach(link => {
|
||||
const text = link.innerText.trim();
|
||||
if (text === '登录') {
|
||||
link.style.display = isLogged ? 'none' : 'block';
|
||||
} else if (['上传文件', '新建文件', '新建目录', '移动对象', '递归删除', '登出'].includes(text)) {
|
||||
link.style.display = isLogged ? 'block' : 'none';
|
||||
if (text === '登出' && isLogged) {
|
||||
link.onclick = function (e) {
|
||||
e.preventDefault();
|
||||
afi.auth.logout();
|
||||
return false;
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
afi.rpc = {
|
||||
rpc: function (call, args, cb) {
|
||||
console.log('[AFI] RPC', call, args)
|
||||
const xhr = new XMLHttpRequest()
|
||||
xhr.open('POST', location.origin + afi.params.extraPath + '/rpc')
|
||||
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8')
|
||||
xhr.send(JSON.stringify({ call, args }))
|
||||
xhr.onload = cb
|
||||
xhr.onerror = () => afi.pulsar.pulseFailure()
|
||||
console.log('[AFI] RPC', call, args);
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', location.origin + afi.params.extraPath + '/rpc');
|
||||
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
|
||||
xhr.withCredentials = true;
|
||||
xhr.send(JSON.stringify({ call, args }));
|
||||
xhr.onload = cb;
|
||||
xhr.onerror = () => afi.pulsar.pulseFailure();
|
||||
},
|
||||
|
||||
mkdirCall: function (path, cb) {
|
||||
@@ -173,36 +218,33 @@ afi.uploader = {
|
||||
this.totalUploadedSize = []
|
||||
setTimeout(afi.utils.refresh, 200)
|
||||
afi.elements.barDisplay.style.display = 'none'
|
||||
//afi.elements.barProc.innerText = "传输: 就绪"
|
||||
}
|
||||
},
|
||||
|
||||
updatePercent: function (event) {
|
||||
this.totalUploadedSize[event.target.id] = event.loaded
|
||||
const ttlDone = this.totalUploadedSize.reduce((s, x) => s + x)
|
||||
const percent = Math.min(Math.floor(100 * ttlDone / this.totalUploadsSize), 100) + '%' // 此处消除对小文件元数据上传带来的误差, 理论上是不准的
|
||||
const percent = Math.min(Math.floor(100 * ttlDone / this.totalUploadsSize), 100) + '%'
|
||||
afi.elements.barProc.innerText = "传输: " + percent
|
||||
},
|
||||
|
||||
upload: function (id, what, path, cbDone, cbErr, cbUpdate) {
|
||||
const xhr = new XMLHttpRequest()
|
||||
xhr.open('POST', location.origin + afi.params.extraPath + '/post')
|
||||
xhr.setRequestHeader('afi-path', path)
|
||||
xhr.upload.addEventListener('load', cbDone)
|
||||
xhr.upload.addEventListener('progress', cbUpdate)
|
||||
xhr.upload.addEventListener('error', cbErr)
|
||||
xhr.upload.id = id
|
||||
xhr.send(what)
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', location.origin + afi.params.extraPath + '/post');
|
||||
xhr.setRequestHeader('afi-path', path);
|
||||
xhr.withCredentials = true;
|
||||
xhr.upload.addEventListener('load', cbDone);
|
||||
xhr.upload.addEventListener('progress', cbUpdate);
|
||||
xhr.upload.addEventListener('error', cbErr);
|
||||
xhr.upload.id = id;
|
||||
xhr.send(what);
|
||||
},
|
||||
|
||||
uploadFile: function (file, path) {
|
||||
if (afi.params.readonly) return
|
||||
path = decodeURI(location.pathname).slice(0, -1) + path
|
||||
window.onbeforeunload = afi.consts.leftPageWarn
|
||||
afi.elements.barProc.style.display = afi.elements.barDisplay.style.display = 'block'
|
||||
this.totalUploads += 1
|
||||
this.totalUploadsSize += file.size
|
||||
//this.totalUploadedSize[this.totalUploads] = file.size
|
||||
if (typeof upBarName !== 'undefined') {
|
||||
upBarName.innerText = this.totalUploads > 1 ? this.totalUploads + ' 个文件' : file.name
|
||||
}
|
||||
@@ -310,38 +352,6 @@ afi.directcall = {
|
||||
}
|
||||
}
|
||||
|
||||
afi.checksum = {
|
||||
getSum(type) {
|
||||
upBarPc.style.display = 'block'
|
||||
upBarPc.innerText = '远程求解校验和...'
|
||||
upBarPc.style.width = '100%'
|
||||
sumsOff()
|
||||
sumCall(getASelected().innerText, type, loaded => {
|
||||
navigator.clipboard.writeText(loaded.target.responseText) // 复制到剪贴板
|
||||
upBarPc.style.display = 'none'
|
||||
flicker(okBadge)
|
||||
})
|
||||
},
|
||||
|
||||
isSumsMode: () => sums.style.display === 'block',
|
||||
sumsToggle: () => isSumsMode() ? sumsOff() : sumsOn(),
|
||||
|
||||
sumsOn() {
|
||||
if (isFolder(getASelected())) {
|
||||
alert('无法对目录求解校验和')
|
||||
return
|
||||
}
|
||||
sums.style.display = 'block'
|
||||
table.style.display = 'none'
|
||||
},
|
||||
sumsOff() {
|
||||
if (!isSumsMode()) return
|
||||
sums.style.display = 'none'
|
||||
table.style.display = 'table'
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
afi.elements = {
|
||||
itemlinks: Array.from(document.querySelectorAll('a.item-links')),
|
||||
@@ -357,6 +367,11 @@ function init() {
|
||||
helpPanel: document.getElementById('help-panel'),
|
||||
helpToggle: document.getElementById('help-toggle'),
|
||||
}
|
||||
|
||||
afi.auth.checkAuth().then(() => {
|
||||
afi.utils.updateButtons();
|
||||
});
|
||||
|
||||
afi.interface.setBreadcrumbs()
|
||||
afi.elements.uploader.addEventListener('change', () => {
|
||||
const files = Array.from(afi.elements.uploader.files);
|
||||
@@ -373,7 +388,6 @@ function init() {
|
||||
}
|
||||
let draggingSrc
|
||||
document.ondragenter = e => {
|
||||
if (afi.params.readonly) { return }
|
||||
afi.utils.cancelDefault(e)
|
||||
afi.utils.resetHighlight()
|
||||
if (!draggingSrc) {
|
||||
@@ -393,7 +407,7 @@ function init() {
|
||||
let isDoubleClick = false;
|
||||
|
||||
row.addEventListener('click', (e) => {
|
||||
if (afi.params.readonly || link.innerText === '../') return;
|
||||
if (link.innerText === '../') return;
|
||||
if (clickTimer) {
|
||||
clearTimeout(clickTimer);
|
||||
clickTimer = null;
|
||||
@@ -403,7 +417,7 @@ function init() {
|
||||
if (!isDoubleClick) {
|
||||
e.stopPropagation();
|
||||
if (confirm('确认删除此项目?')) {
|
||||
afi.rpc.rmCall(afi.utils.prependPath(link.href), afi.utils.refresh);
|
||||
afi.rpc.rmCall(afi.utils.prependPath(link.getAttribute('href')), afi.utils.refresh);
|
||||
}
|
||||
}
|
||||
isDoubleClick = false;
|
||||
@@ -421,8 +435,7 @@ function init() {
|
||||
clickTimer = null;
|
||||
}
|
||||
|
||||
if (afi.params.readonly) return;
|
||||
if (link.innerText === '../') return; // 不能操作上级
|
||||
if (link.innerText === '../') return;
|
||||
|
||||
const newName = prompt('新名称或目标地址', link.innerText);
|
||||
if (newName && !afi.utils.isDupe(newName)) {
|
||||
@@ -438,12 +451,11 @@ function init() {
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
document.ondragstart = e => { draggingSrc = e.target.innerHTML } // 记录拖拽源
|
||||
document.ondragend = e => resetHighlight() // 清理高亮
|
||||
document.ondragover = e => { afi.utils.cancelDefault(e); return false } // 允许拖拽
|
||||
document.ondragstart = e => { draggingSrc = e.target.innerHTML }
|
||||
document.ondragend = e => resetHighlight()
|
||||
document.ondragover = e => { afi.utils.cancelDefault(e); return false }
|
||||
|
||||
document.ondrop = e => {
|
||||
if (afi.params.readonly) return
|
||||
|
||||
afi.utils.cancelDefault(e)
|
||||
afi.elements.dropGrid.style.display = 'none'
|
||||
@@ -460,9 +472,6 @@ function init() {
|
||||
draggingSrc = null
|
||||
return false
|
||||
}
|
||||
if (!afi.params.readonly) {
|
||||
afi.elements.barProc.innerText = "传输: 就绪"
|
||||
}
|
||||
console.log('[AFI] Initialized')
|
||||
}
|
||||
|
||||
|
||||
24
ui/ui.html
24
ui/ui.html
@@ -10,7 +10,6 @@
|
||||
css_will_be_here
|
||||
</style>
|
||||
<script>
|
||||
readonly = {{.Ro }}
|
||||
extraPath = {{.ExtraPath }}.slice(0, -1)
|
||||
js_will_be_here
|
||||
</script>
|
||||
@@ -23,18 +22,15 @@
|
||||
<span class="nav" id="nav">{{.Path}}</span>
|
||||
<span id="path" style="display: none;" onclick="return afi.directcall.bread_click(event)">{{.Path}}</span>
|
||||
<div id="operations">
|
||||
{{if not .Ro}}
|
||||
<a onclick="document.getElementById('clickupload').click()" class="operation">上传文件</a>
|
||||
<a onclick="afi.directcall.exec_touch()" class="operation">新建文件</a>
|
||||
<a onclick="afi.directcall.exec_mkdir()" class="operation">新建目录</a>
|
||||
<a onclick="afi.directcall.exec_mv()" class="operation">移动对象</a>
|
||||
<a onclick="afi.directcall.exec_rm()" class="operation">递归删除</a>
|
||||
<a onclick="" class="operation">登出</a>
|
||||
{{end}}
|
||||
{{if .Ro}}
|
||||
<a onclick="" class="operation">登录</a>
|
||||
{{end}}
|
||||
<a onclick="afi.utils.helpOn()" class="operation" id="help-toggle">帮助菜单</a>
|
||||
<a style="display: none;" onclick="document.getElementById('clickupload').click()"
|
||||
class="operation">上传文件</a>
|
||||
<a style="display: none;" onclick="afi.directcall.exec_touch()" class="operation">新建文件</a>
|
||||
<a style="display: none;" onclick="afi.directcall.exec_mkdir()" class="operation">新建目录</a>
|
||||
<a style="display: none;" onclick="afi.directcall.exec_mv()" class="operation">移动对象</a>
|
||||
<a style="display: none;" onclick="afi.directcall.exec_rm()" class="operation">递归删除</a>
|
||||
<a style="display: none;" onclick="afi.auth.logout()" class="operation">登出</a>
|
||||
<a style="display: block;" href="./login" target="_blank" rel="noopener noreferrer" class="operation">登录</a>
|
||||
<a style="user-select: none;" onclick="afi.utils.helpOn()" class="operation" id="help-toggle">帮助菜单</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -201,4 +197,4 @@
|
||||
</footer>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
Reference in New Issue
Block a user