del useless package: jsda/luci-app-filebrowser
This commit is contained in:
parent
a669acac35
commit
7607bc0485
@ -1,8 +0,0 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_TITLE:=LuCI page for filebrowser
|
||||
LUCI_DEPENDS:=
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
@ -1,20 +0,0 @@
|
||||
# luci-app-filebrowser -- web文件管理
|
||||
|
||||
File browser app for OpenWrt/LEDE Luci backend
|
||||
|
||||
main features
|
||||
|
||||
- spa page with back and forward support
|
||||
- ajax file upload
|
||||
- symbolic link jump
|
||||
- rename and delete
|
||||
|
||||
quick install or upgrade
|
||||
|
||||
>1. ssh to lede
|
||||
>2. download the zipball and unzip it
|
||||
>3. run `sh quick_install`
|
||||
|
||||
[luci-material-theme](https://github.com/LuttyYang/luci-theme-material) recommended
|
||||
|
||||

|
||||
@ -1,12 +0,0 @@
|
||||
Package: luci-app-filebrowser
|
||||
Version: 1.0
|
||||
Description: File browser app for OpenWrt Luci backend.
|
||||
Section: extras
|
||||
Priority: optional
|
||||
Maintainer: giaulo
|
||||
License: CLOSED
|
||||
Architecture: all
|
||||
OE: luci-app-filebrowser
|
||||
Homepage: unknown
|
||||
Depends: luci-base
|
||||
Source: N/A
|
||||
@ -1,68 +0,0 @@
|
||||
.fb-container {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.fb-container .cbi-button {
|
||||
height: 1.8rem;
|
||||
}
|
||||
.fb-container .cbi-input-text {
|
||||
margin-bottom: 1rem;
|
||||
width: 100%;
|
||||
}
|
||||
.fb-container .panel-title {
|
||||
padding-bottom: 0;
|
||||
width: 50%;
|
||||
border-bottom: none;
|
||||
}
|
||||
.fb-container .panel-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-bottom: 1rem;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.fb-container .upload-container {
|
||||
display: none;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
.fb-container .upload-file {
|
||||
margin-right: 2rem;
|
||||
}
|
||||
.fb-container .cbi-value-field {
|
||||
text-align: left;
|
||||
}
|
||||
.fb-container .parent-icon strong {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
.fb-container td[class$="-icon"] {
|
||||
cursor: pointer;
|
||||
}
|
||||
.fb-container .file-icon, .fb-container .folder-icon, .fb-container .link-icon {
|
||||
position: relative;
|
||||
}
|
||||
.fb-container .file-icon:before, .fb-container .folder-icon:before, .fb-container .link-icon:before {
|
||||
display: inline-block;
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
content: '';
|
||||
background-size: contain;
|
||||
margin: 0 0.5rem 0 1rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.fb-container .file-icon:before {
|
||||
background-image: url(file-icon.png);
|
||||
}
|
||||
.fb-container .folder-icon:before {
|
||||
background-image: url(folder-icon.png);
|
||||
}
|
||||
.fb-container .link-icon:before {
|
||||
background-image: url(link-icon.png);
|
||||
}
|
||||
@media screen and (max-width: 480px) {
|
||||
.fb-container .upload-file {
|
||||
width: 14.6rem;
|
||||
}
|
||||
.fb-container .cbi-value-owner,
|
||||
.fb-container .cbi-value-perm {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@ -1,234 +0,0 @@
|
||||
String.prototype.replaceAll = function(search, replacement) {
|
||||
var target = this;
|
||||
return target.replace(new RegExp(search, 'g'), replacement);
|
||||
};
|
||||
(function () {
|
||||
var iwxhr = new XHR();
|
||||
var listElem = document.getElementById("list-content");
|
||||
listElem.onclick = handleClick;
|
||||
var currentPath;
|
||||
var pathElem = document.getElementById("current-path");
|
||||
pathElem.onblur = function () {
|
||||
update_list(this.value.trim());
|
||||
};
|
||||
pathElem.onkeyup = function (evt) {
|
||||
if (evt.keyCode == 13) {
|
||||
this.blur();
|
||||
}
|
||||
};
|
||||
function removePath(filename, isdir) {
|
||||
var c = confirm('确认删除 ' + filename + ' ?');
|
||||
if (c) {
|
||||
iwxhr.get('/cgi-bin/luci/admin/system/filebrowser_delete',
|
||||
{
|
||||
path: concatPath(currentPath, filename),
|
||||
isdir: isdir
|
||||
},
|
||||
function (x, res) {
|
||||
if (res.ec === 0) {
|
||||
refresh_list(res.data, currentPath);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
function renamePath(filename) {
|
||||
var newname = prompt('输入新名字:', filename);
|
||||
if (newname) {
|
||||
newname = newname.trim();
|
||||
if (newname != filename) {
|
||||
var newpath = concatPath(currentPath, newname);
|
||||
iwxhr.get('/cgi-bin/luci/admin/system/filebrowser_rename',
|
||||
{
|
||||
filepath: concatPath(currentPath, filename),
|
||||
newpath: newpath
|
||||
},
|
||||
function (x, res) {
|
||||
if (res.ec === 0) {
|
||||
refresh_list(res.data, currentPath);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function openpath(filename, dirname) {
|
||||
dirname = dirname || currentPath;
|
||||
window.open('/cgi-bin/luci/admin/system/filebrowser_open?path='
|
||||
+ encodeURIComponent(dirname) + '&filename='
|
||||
+ encodeURIComponent(filename));
|
||||
}
|
||||
|
||||
function getFileElem(elem) {
|
||||
if (elem.className.indexOf('-icon') > -1) {
|
||||
return elem;
|
||||
}
|
||||
else if (elem.parentNode.className.indexOf('-icon') > -1) {
|
||||
return elem.parentNode;
|
||||
}
|
||||
}
|
||||
|
||||
function concatPath(path, filename) {
|
||||
if (path === '/') {
|
||||
return path + filename;
|
||||
}
|
||||
else {
|
||||
return path.replace(/\/$/, '') + '/' + filename;
|
||||
}
|
||||
}
|
||||
|
||||
function handleClick(evt) {
|
||||
var targetElem = evt.target;
|
||||
var infoElem;
|
||||
if (targetElem.className.indexOf('cbi-button-remove') > -1) {
|
||||
infoElem = targetElem.parentNode.parentNode;
|
||||
removePath(infoElem.dataset['filename'] , infoElem.dataset['isdir'])
|
||||
}
|
||||
else if (targetElem.className.indexOf('cbi-button-edit') > -1) {
|
||||
renamePath(targetElem.parentNode.parentNode.dataset['filename']);
|
||||
}
|
||||
else if (targetElem = getFileElem(targetElem)) {
|
||||
if (targetElem.className.indexOf('parent-icon') > -1) {
|
||||
update_list(currentPath.replace(/\/[^/]+($|\/$)/, ''));
|
||||
}
|
||||
else if (targetElem.className.indexOf('file-icon') > -1) {
|
||||
openpath(targetElem.parentNode.dataset['filename']);
|
||||
}
|
||||
else if (targetElem.className.indexOf('link-icon') > -1) {
|
||||
infoElem = targetElem.parentNode;
|
||||
var filepath = infoElem.dataset['linktarget'];
|
||||
if (filepath) {
|
||||
if (infoElem.dataset['isdir'] === "1") {
|
||||
update_list(filepath);
|
||||
}
|
||||
else {
|
||||
var lastSlash = filepath.lastIndexOf('/');
|
||||
openpath(filepath.substring(lastSlash + 1), filepath.substring(0, lastSlash));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (targetElem.className.indexOf('folder-icon') > -1) {
|
||||
update_list(concatPath(currentPath, targetElem.parentNode.dataset['filename']))
|
||||
}
|
||||
}
|
||||
}
|
||||
function refresh_list(filenames, path) {
|
||||
var listHtml = '<table class="cbi-section-table"><tbody>';
|
||||
if (path !== '/') {
|
||||
listHtml += '<tr><td class="parent-icon" colspan="6"><strong>..</strong></td></tr>';
|
||||
}
|
||||
if (filenames) {
|
||||
for (var i = 0; i < filenames.length; i++) {
|
||||
var line = filenames[i];
|
||||
if (line) {
|
||||
var f = line.match(/(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+([\S\s]+)/);
|
||||
var isLink = f[1][0] === 'z' || f[1][0] === 'l' || f[1][0] === 'x';
|
||||
var o = {
|
||||
displayname: f[9],
|
||||
filename: isLink ? f[9].split(' -> ')[0] : f[9],
|
||||
perms: f[1],
|
||||
date: f[7] + ' ' + f[6] + ' ' + f[8],
|
||||
size: f[5],
|
||||
owner: f[3],
|
||||
icon: (f[1][0] === 'd') ? "folder-icon" : (isLink ? "link-icon" : "file-icon")
|
||||
};
|
||||
listHtml += '<tr class="cbi-section-table-row cbi-rowstyle-' + (1 + i%2)
|
||||
+ '" data-filename="' + o.filename + '" data-isdir="' + Number(f[1][0] === 'd' || f[1][0] === 'z') + '"'
|
||||
+ ((f[1][0] === 'z' || f[1][0] === 'l') ? (' data-linktarget="' + f[9].split(' -> ')[1]) : '')
|
||||
+ '">'
|
||||
+ '<td class="cbi-value-field ' + o.icon + '">'
|
||||
+ '<strong>' + o.displayname + '</strong>'
|
||||
+ '</td>'
|
||||
+ '<td class="cbi-value-field cbi-value-owner">'+o.owner+'</td>'
|
||||
+ '<td class="cbi-value-field cbi-value-date">'+o.date+'</td>'
|
||||
+ '<td class="cbi-value-field cbi-value-size">'+o.size+'</td>'
|
||||
+ '<td class="cbi-value-field cbi-value-perm">'+o.perms+'</td>'
|
||||
+ '<td class="cbi-section-table-cell"><button class="cbi-button cbi-button-edit">重命名</button>\
|
||||
<button class="cbi-button cbi-button-remove">删除</button></td>'
|
||||
+ '</tr>';
|
||||
}
|
||||
}
|
||||
}
|
||||
listHtml += "</table>";
|
||||
listElem.innerHTML = listHtml;
|
||||
}
|
||||
function update_list(path, opt) {
|
||||
opt = opt || {};
|
||||
path = concatPath(path, '');
|
||||
if (currentPath != path) {
|
||||
iwxhr.get('/cgi-bin/luci/admin/system/filebrowser_list',
|
||||
{path: path},
|
||||
function (x, res) {
|
||||
if (res.ec === 0) {
|
||||
refresh_list(res.data, path);
|
||||
}
|
||||
else {
|
||||
refresh_list([], path);
|
||||
}
|
||||
}
|
||||
);
|
||||
if (!opt.popState) {
|
||||
history.pushState({path: path}, null, '?path=' + path);
|
||||
}
|
||||
currentPath = path;
|
||||
pathElem.value = currentPath;
|
||||
}
|
||||
};
|
||||
|
||||
var uploadToggle = document.getElementById('upload-toggle');
|
||||
var uploadContainer = document.getElementById('upload-container');
|
||||
var isUploadHide = true;
|
||||
uploadToggle.onclick = function() {
|
||||
if (isUploadHide) {
|
||||
uploadContainer.style.display = 'inline-flex';
|
||||
}
|
||||
else {
|
||||
uploadContainer.style.display = 'none';
|
||||
}
|
||||
isUploadHide = !isUploadHide;
|
||||
};
|
||||
var uploadBtn = uploadContainer.getElementsByClassName('cbi-input-apply')[0];
|
||||
uploadBtn.onclick = function (evt) {
|
||||
var uploadinput = document.getElementById('upload-file');
|
||||
var fullPath = uploadinput.value;
|
||||
if (!fullPath) {
|
||||
evt.preventDefault();
|
||||
}
|
||||
else {
|
||||
var formData = new FormData();
|
||||
var startIndex = (fullPath.indexOf('\\') >= 0 ? fullPath.lastIndexOf('\\') : fullPath.lastIndexOf('/'));
|
||||
formData.append('upload-filename', fullPath.substring(startIndex + 1));
|
||||
formData.append('upload-dir', concatPath(currentPath, ''));
|
||||
formData.append('upload-file', uploadinput.files[0]);
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "/cgi-bin/luci/admin/system/filebrowser_upload", true);
|
||||
xhr.onload = function() {
|
||||
if (xhr.status == 200) {
|
||||
var res = JSON.parse(xhr.responseText);
|
||||
refresh_list(res.data, currentPath);
|
||||
uploadinput.value = '';
|
||||
}
|
||||
else {
|
||||
alert('上传失败');
|
||||
}
|
||||
};
|
||||
xhr.send(formData);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function(evt) {
|
||||
var initPath = '/';
|
||||
if (/path=([/\w]+)/.test(location.search)) {
|
||||
initPath = RegExp.$1;
|
||||
}
|
||||
update_list(initPath, {popState: true});
|
||||
});
|
||||
window.addEventListener('popstate', function (evt) {
|
||||
var path = '/';
|
||||
if (evt.state && evt.state.path) {
|
||||
path = evt.state.path;
|
||||
}
|
||||
update_list(path, {popState: true});
|
||||
});
|
||||
|
||||
})();
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.6 KiB |
@ -1,201 +0,0 @@
|
||||
module("luci.controller.filebrowser", package.seeall)
|
||||
|
||||
function index()
|
||||
|
||||
page = entry({"admin", "system", "filebrowser"}, template("filebrowser"), _("文件管理"), 60)
|
||||
page.i18n = "base"
|
||||
page.dependent = true
|
||||
|
||||
page = entry({"admin", "system", "filebrowser_list"}, call("filebrowser_list"), nil)
|
||||
page.leaf = true
|
||||
|
||||
page = entry({"admin", "system", "filebrowser_open"}, call("filebrowser_open"), nil)
|
||||
page.leaf = true
|
||||
|
||||
page = entry({"admin", "system", "filebrowser_delete"}, call("filebrowser_delete"), nil)
|
||||
page.leaf = true
|
||||
|
||||
page = entry({"admin", "system", "filebrowser_rename"}, call("filebrowser_rename"), nil)
|
||||
page.leaf = true
|
||||
|
||||
page = entry({"admin", "system", "filebrowser_upload"}, call("filebrowser_upload"), nil)
|
||||
page.leaf = true
|
||||
|
||||
end
|
||||
|
||||
function list_response(path, success)
|
||||
luci.http.prepare_content("application/json")
|
||||
local result
|
||||
if success then
|
||||
local rv = scandir(path)
|
||||
result = {
|
||||
ec = 0,
|
||||
data = rv
|
||||
}
|
||||
else
|
||||
result = {
|
||||
ec = 1
|
||||
}
|
||||
end
|
||||
luci.http.write_json(result)
|
||||
end
|
||||
|
||||
function filebrowser_list()
|
||||
local path = luci.http.formvalue("path")
|
||||
list_response(path, true)
|
||||
end
|
||||
|
||||
function filebrowser_open()
|
||||
local path = luci.http.formvalue("path")
|
||||
local filename = luci.http.formvalue("filename")
|
||||
local io = require "io"
|
||||
local mime = to_mime(filename)
|
||||
|
||||
file = path..filename
|
||||
|
||||
local download_fpi = io.open(file, "r")
|
||||
luci.http.header('Content-Disposition', 'inline; filename="'..filename..'"' )
|
||||
luci.http.prepare_content(mime)
|
||||
luci.ltn12.pump.all(luci.ltn12.source.file(download_fpi), luci.http.write)
|
||||
end
|
||||
|
||||
function filebrowser_delete()
|
||||
local path = luci.http.formvalue("path")
|
||||
local isdir = luci.http.formvalue("isdir")
|
||||
path = path:gsub("<>", "/")
|
||||
path = path:gsub(" ", "\ ")
|
||||
local success
|
||||
if isdir then
|
||||
success = os.execute('rm -r "'..path..'"')
|
||||
else
|
||||
success = os.remove(path)
|
||||
end
|
||||
list_response(nixio.fs.dirname(path), success)
|
||||
end
|
||||
|
||||
function filebrowser_rename()
|
||||
local filepath = luci.http.formvalue("filepath")
|
||||
local newpath = luci.http.formvalue("newpath")
|
||||
local success = os.execute('mv "'..filepath..'" "'..newpath..'"')
|
||||
list_response(nixio.fs.dirname(filepath), success)
|
||||
end
|
||||
|
||||
function filebrowser_upload()
|
||||
local filecontent = luci.http.formvalue("upload-file")
|
||||
local filename = luci.http.formvalue("upload-filename")
|
||||
local uploaddir = luci.http.formvalue("upload-dir")
|
||||
local filepath = uploaddir..filename
|
||||
|
||||
local fp
|
||||
luci.http.setfilehandler(
|
||||
function(meta, chunk, eof)
|
||||
if not fp and meta and meta.name == "upload-file" then
|
||||
fp = io.open(filepath, "w")
|
||||
end
|
||||
if fp and chunk then
|
||||
fp:write(chunk)
|
||||
end
|
||||
if fp and eof then
|
||||
fp:close()
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
list_response(uploaddir, true)
|
||||
end
|
||||
|
||||
function scandir(directory)
|
||||
local i, t, popen = 0, {}, io.popen
|
||||
|
||||
local pfile = popen("ls -lh \""..directory.."\" | egrep '^d' ; ls -lh \""..directory.."\" | egrep -v '^d|^l'")
|
||||
for fileinfo in pfile:lines() do
|
||||
i = i + 1
|
||||
t[i] = fileinfo
|
||||
end
|
||||
pfile:close()
|
||||
pfile = popen("ls -lh \""..directory.."\" | egrep '^l' ;")
|
||||
for fileinfo in pfile:lines() do
|
||||
i = i + 1
|
||||
linkindex, _, linkpath = string.find(fileinfo, "->%s+(.+)$")
|
||||
local finalpath;
|
||||
if string.sub(linkpath, 1, 1) == "/" then
|
||||
finalpath = linkpath
|
||||
else
|
||||
finalpath = nixio.fs.realpath(directory..linkpath)
|
||||
end
|
||||
local linktype;
|
||||
if not finalpath then
|
||||
finalpath = linkpath;
|
||||
linktype = 'x'
|
||||
elseif nixio.fs.stat(finalpath, "type") == "dir" then
|
||||
linktype = 'z'
|
||||
else
|
||||
linktype = 'l'
|
||||
end
|
||||
fileinfo = string.sub(fileinfo, 2, linkindex - 1)
|
||||
fileinfo = linktype..fileinfo.."-> "..finalpath
|
||||
t[i] = fileinfo
|
||||
end
|
||||
pfile:close()
|
||||
return t
|
||||
end
|
||||
|
||||
MIME_TYPES = {
|
||||
["txt"] = "text/plain";
|
||||
["conf"] = "text/plain";
|
||||
["ovpn"] = "text/plain";
|
||||
["log"] = "text/plain";
|
||||
["js"] = "text/javascript";
|
||||
["json"] = "application/json";
|
||||
["css"] = "text/css";
|
||||
["htm"] = "text/html";
|
||||
["html"] = "text/html";
|
||||
["patch"] = "text/x-patch";
|
||||
["c"] = "text/x-csrc";
|
||||
["h"] = "text/x-chdr";
|
||||
["o"] = "text/x-object";
|
||||
["ko"] = "text/x-object";
|
||||
|
||||
["bmp"] = "image/bmp";
|
||||
["gif"] = "image/gif";
|
||||
["png"] = "image/png";
|
||||
["jpg"] = "image/jpeg";
|
||||
["jpeg"] = "image/jpeg";
|
||||
["svg"] = "image/svg+xml";
|
||||
|
||||
["zip"] = "application/zip";
|
||||
["pdf"] = "application/pdf";
|
||||
["xml"] = "application/xml";
|
||||
["xsl"] = "application/xml";
|
||||
["doc"] = "application/msword";
|
||||
["ppt"] = "application/vnd.ms-powerpoint";
|
||||
["xls"] = "application/vnd.ms-excel";
|
||||
["odt"] = "application/vnd.oasis.opendocument.text";
|
||||
["odp"] = "application/vnd.oasis.opendocument.presentation";
|
||||
["pl"] = "application/x-perl";
|
||||
["sh"] = "application/x-shellscript";
|
||||
["php"] = "application/x-php";
|
||||
["deb"] = "application/x-deb";
|
||||
["iso"] = "application/x-cd-image";
|
||||
["tgz"] = "application/x-compressed-tar";
|
||||
|
||||
["mp3"] = "audio/mpeg";
|
||||
["ogg"] = "audio/x-vorbis+ogg";
|
||||
["wav"] = "audio/x-wav";
|
||||
|
||||
["mpg"] = "video/mpeg";
|
||||
["mpeg"] = "video/mpeg";
|
||||
["avi"] = "video/x-msvideo";
|
||||
}
|
||||
|
||||
function to_mime(filename)
|
||||
if type(filename) == "string" then
|
||||
local ext = filename:match("[^%.]+$")
|
||||
|
||||
if ext and MIME_TYPES[ext:lower()] then
|
||||
return MIME_TYPES[ext:lower()]
|
||||
end
|
||||
end
|
||||
|
||||
return "application/octet-stream"
|
||||
end
|
||||
@ -1,20 +0,0 @@
|
||||
<%+header%>
|
||||
|
||||
<link rel="stylesheet" href="/luci-static/resources/fb/fb.css?v=@ver">
|
||||
<h2 name="content">文件管理</h2>
|
||||
<fieldset class="cbi-section fb-container">
|
||||
<input id="current-path" type="text" class="current-path cbi-input-text" value="/"/>
|
||||
<div class="panel-container">
|
||||
<div class="panel-title">文件列表:</div>
|
||||
<button id="upload-toggle" class="upload-toggle cbi-button cbi-button-edit">上传</button>
|
||||
</div>
|
||||
<div class="upload-container" id="upload-container">
|
||||
<input id="upload-file" name="upload-file" class="upload-file" type="file">
|
||||
<button type="button" class="cbi-button cbi-input-apply">开始</button>
|
||||
</div>
|
||||
<div id="list-content"></div>
|
||||
</fieldset>
|
||||
|
||||
<script src="/luci-static/resources/fb/fb.js?v=@ver"></script>
|
||||
|
||||
<%+footer%>
|
||||
@ -1,13 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cp -R htdocs/luci-static/resources/* /www/luci-static/resources/
|
||||
cp -R luasrc/* /usr/lib/lua/luci/
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
ver=$(date +%s)
|
||||
else
|
||||
ver=$1
|
||||
fi
|
||||
sed -i "s/@ver/$ver/g" /usr/lib/lua/luci/view/filebrowser.htm
|
||||
|
||||
rm -rf /tmp/luci*
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 156 KiB |
Loading…
Reference in New Issue
Block a user