Skip to content

Commit f0b0f57

Browse files
committed
UiFileManager plugin
1 parent 85790f8 commit f0b0f57

24 files changed

Lines changed: 2541 additions & 0 deletions
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import io
2+
import os
3+
import re
4+
import urllib
5+
6+
from Plugin import PluginManager
7+
from Config import config
8+
from Translate import Translate
9+
10+
plugin_dir = os.path.dirname(__file__)
11+
12+
if "_" not in locals():
13+
_ = Translate(plugin_dir + "/languages/")
14+
15+
16+
@PluginManager.registerTo("UiRequest")
17+
class UiFileManagerPlugin(object):
18+
def actionWrapper(self, path, extra_headers=None):
19+
match = re.match("/list/(.*?)(/.*|)$", path)
20+
if not match:
21+
return super().actionWrapper(path, extra_headers)
22+
23+
if not extra_headers:
24+
extra_headers = {}
25+
26+
request_address, inner_path = match.groups()
27+
28+
script_nonce = self.getScriptNonce()
29+
30+
self.sendHeader(extra_headers=extra_headers, script_nonce=script_nonce)
31+
32+
site = self.server.site_manager.need(request_address)
33+
34+
if not site:
35+
return super().actionWrapper(path, extra_headers)
36+
37+
request_params = urllib.parse.urlencode(
38+
{"address": site.address, "site": request_address, "inner_path": inner_path.strip("/")}
39+
)
40+
41+
is_content_loaded = "content.json" in site.content_manager.contents
42+
43+
return iter([super().renderWrapper(
44+
site, path, "uimedia/plugins/uifilemanager/list.html?%s" % request_params,
45+
"List", extra_headers, show_loadingscreen=not is_content_loaded, script_nonce=script_nonce
46+
)])
47+
48+
def actionUiMedia(self, path, *args, **kwargs):
49+
if path.startswith("/uimedia/plugins/uifilemanager/"):
50+
file_path = path.replace("/uimedia/plugins/uifilemanager/", plugin_dir + "/media/")
51+
if config.debug and (file_path.endswith("all.js") or file_path.endswith("all.css")):
52+
# If debugging merge *.css to all.css and *.js to all.js
53+
from Debug import DebugMedia
54+
DebugMedia.merge(file_path)
55+
56+
if file_path.endswith("js"):
57+
data = _.translateData(open(file_path).read(), mode="js").encode("utf8")
58+
elif file_path.endswith("html"):
59+
if self.get.get("address"):
60+
site = self.server.site_manager.need(self.get.get("address"))
61+
if "content.json" not in site.content_manager.contents:
62+
site.needFile("content.json")
63+
data = _.translateData(open(file_path).read(), mode="html").encode("utf8")
64+
else:
65+
data = open(file_path, "rb").read()
66+
67+
return self.actionFile(file_path, file_obj=io.BytesIO(data), file_size=len(data))
68+
else:
69+
return super().actionUiMedia(path)
70+
71+
def error404(self, path=""):
72+
if not path.endswith("index.html") and not path.endswith("/"):
73+
return super().error404(path)
74+
75+
path_parts = self.parsePath(path)
76+
site = self.server.site_manager.get(path_parts["request_address"])
77+
78+
if not site or not site.content_manager.contents.get("content.json"):
79+
return super().error404(path)
80+
81+
self.sendHeader(200)
82+
path_redirect = "/list" + re.sub("^/media/", "/", path)
83+
self.log.debug("Index.html not found: %s, redirecting to: %s" % (path, path_redirect))
84+
return self.formatRedirect(path_redirect)

plugins/UiFileManager/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import UiFileManagerPlugin
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"New file name:": "Új fájl neve:",
3+
"Delete": "Törlés",
4+
"Cancel": "Mégse",
5+
"Selected:": "Köjelölt:",
6+
"Delete and remove optional:": "Törlés és opcionális fájl eltávolítása",
7+
" files": " fájl",
8+
" (modified)": " (módostott)",
9+
" (new)": " (új)",
10+
" (optional)": " (opcionális)",
11+
" (ignored from content.json)": " (content.json-ból kihagyott)",
12+
"Total: ": "Összesen: ",
13+
" dir, ": " könyvtár, ",
14+
" file in ": " fájl, ",
15+
"+ New": "+ Új",
16+
"Edit": "Módosít",
17+
"View": "Megnyit",
18+
"Save": "Mentés",
19+
"Save: done!": "Mentés: Kész!"
20+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
.menu {
2+
background-color: white; padding: 10px 0px; position: absolute; top: 0px; max-height: 0px; overflow: hidden; transform: translate(-100%, -30px); pointer-events: none;
3+
box-shadow: 0px 2px 8px rgba(0,0,0,0.3); border-radius: 2px; opacity: 0; transition: opacity 0.2s ease-out, transform 1s ease-out, max-height 0.2s ease-in-out; z-index: 99;
4+
display: inline-block; z-index: 999; transform-style: preserve-3d;
5+
}
6+
.menu.menu-left { transform: translate(0%, -30px); }
7+
.menu.menu-left.visible { transform: translate(0%, 0px); }
8+
.menu.visible {
9+
opacity: 1; transform: translate(-100%, 0px); pointer-events: all;
10+
transition: opacity 0.1s ease-out, transform 0.3s ease-out, max-height 0.3s cubic-bezier(0.86, 0, 0.07, 1);
11+
}
12+
13+
.menu-item {
14+
display: block; text-decoration: none; color: black; padding: 6px 24px; transition: all 0.2s; border-bottom: none; font-weight: normal;
15+
max-height: 150px; overflow: hidden; text-overflow: ellipsis; -webkit-line-clamp: 6; -webkit-box-orient: vertical; display: -webkit-box;
16+
}
17+
.menu-item-separator { margin-top: 3px; margin-bottom: 3px; border-top: 1px solid #eee }
18+
19+
.menu-item.noaction { cursor: default }
20+
.menu-item:hover:not(.noaction) { background-color: #F6F6F6; transition: none; color: inherit; cursor: pointer; color: black }
21+
.menu-item:active:not(.noaction), .menu-item:focus:not(.noaction) { background-color: #AF3BFF !important; color: white !important; transition: none }
22+
.menu-item.selected:before {
23+
content: "L"; display: inline-block; transform: rotateZ(45deg) scaleX(-1);
24+
font-weight: bold; position: absolute; margin-left: -14px; font-size: 12px; margin-top: 2px;
25+
}
26+
27+
.menu-radio { white-space: normal; line-height: 26px }
28+
.menu-radio a {
29+
background-color: #EEE; width: 18.5%;; text-align: center; margin-top: 2px; margin-bottom: 2px; color: #666; font-weight: bold;
30+
text-decoration: none; font-size: 13px; transition: all 0.3s; text-transform: uppercase; display: inline-block;
31+
}
32+
.menu-radio a:hover, .menu-radio a.selected { transition: none; background-color: #AF3BFF !important; color: white !important }
33+
.menu-radio a.long { font-size: 10px; vertical-align: -1px; }
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
.selectbar.visible { margin-top: 0px; visibility: visible }
2+
.selectbar {
3+
position: fixed; top: 0; left: 0; background-color: white; box-shadow: 0px 0px 25px rgba(22, 39, 97, 0.2); margin-top: -75px;
4+
transition: all 0.3s; visibility: hidden; z-index: 9999; color: black; border-left: 5px solid #ede1f582; width: 100%;
5+
padding: 13px; font-size: 13px; font-weight: lighter; backface-visibility: hidden;
6+
}
7+
8+
.selectbar .num { margin-left: 15px; min-width: 30px; text-align: right; display: inline-block; }
9+
.selectbar .size { margin-left: 10px; color: #9f9ba2; min-width: 75px; display: inline-block; }
10+
.selectbar .actions { display: inline-block; margin-left: 20px; font-size: 13px; text-transform: uppercase; line-height: 20px; }
11+
.selectbar .action { padding: 5px 20px; border: 1px solid #edd4ff; margin-left: 10px; border-radius: 30px; color: #af3bff; text-decoration: none; transition: all 0.3s }
12+
.selectbar .action:hover { border-color: #c788f3; transition: none; color: #9700ff }
13+
.selectbar .delete { color: #AAA; border-color: #DDD; }
14+
.selectbar .delete:hover { color: #333; border-color: #AAA }
15+
.selectbar .action:active { background-color: #af3bff; color: white; border-color: #af3bff; transition: none }
16+
.selectbar .cancel { margin: 20px; font-size: 10px; text-decoration: none; color: #999; text-transform: uppercase; }
17+
.selectbar .cancel:hover { color: #333; transition: none }
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
body { background-color: #EEEEF5; font-family: "Segoe UI", Helvetica, Arial; height: 95000px; overflow: hidden; }
2+
body.loaded { height: auto; overflow: auto }
3+
h1 { font-weight: lighter; }
4+
5+
a { color: #333 }
6+
a:hover { text-decoration: none }
7+
input::placeholder { color: rgba(255, 255, 255, 0.3) }
8+
9+
h2 { font-weight: lighter; }
10+
11+
.link { background-color: transparent; outline: 5px solid transparent; transition: all 0.3s }
12+
.link:active { background-color: #fbf5ff; outline: 5px solid #fbf5ff; transition: none }
13+
14+
.manager.editing .files { float: left; width: 280px; }
15+
16+
.sidebar-button {
17+
display: inline-block; padding: 25px 19px; text-decoration: none; position: absolute;
18+
border-right: 1px solid #EEE; line-height: 10px; color: #7801F5; transition: all 0.3s
19+
}
20+
.sidebar-button:active { background-color: #f5e7ff; transition: none }
21+
/*.sidebar-button:hover { background-color: #fbf5ff; }*/
22+
.sidebar-button span { transition: 1s all; transform-origin: 2.5px 7px; display: inline-block; }
23+
.manager.sidebar_closed .sidebar-button span { transform: rotateZ(180deg); }
24+
.manager.sidebar_closed .files { margin-left: -300px; }
25+
.manager.sidebar_closed .editor { width: 100%; }
26+
27+
.button {
28+
padding: 5px 10px; margin-left: 10px; background-color: #752ff2; border-bottom: 2px solid #caadff; background-position: -50px center;
29+
border-radius: 2px; text-decoration: none; transition: all 0.5s ease-out; display: inline-block;
30+
color: #333; font-size: 12px; vertical-align: 2px; text-transform: uppercase; color: white; max-width: 100px;
31+
}
32+
.button:hover { background-color: #9e71ed; transition: none; }
33+
.button:active { position: relative; top: 1px }
34+
.button.loading, .button.disabled { color: rgba(255,255,255,0.7);; pointer-events: none; border-bottom: 2px solid #666; background-color: #999; }
35+
.button.loading { background: #999 url(../img/loading.gif) no-repeat center center; transition: all 0.5s ease-out; color: rgba(0,0,0,0); }
36+
.button.done { background-color: #4dc758; transition: all 0.3s; border-color: #4dc758; pointer-events: none; }
37+
.button.hidden { max-width: 0px; display: inline-block; padding-left: 0px; padding-right: 0px; margin: 0px; }
38+
39+
/* List */
40+
41+
.files {
42+
width: 97%; box-sizing: border-box; color: #555; position: relative; z-index: 1; transition: all 0.6s;
43+
font-size: 14px; box-shadow: 0px 9px 20px -15px #a5cbec; max-width: 400px; border: 1px solid #EEEEF5;
44+
}
45+
.files .tr { white-space: nowrap }
46+
.files .td { display: inline-block; width: 60px }
47+
.files .tbody .td { line-height: 18px; vertical-align: bottom; }
48+
.files .td.name { min-width: 100px }
49+
.files .td.size { width: 60px; text-align: right; padding-left: 5px; }
50+
.files .td.status { text-align: right; }
51+
.files .td.peer { width: 60px }
52+
.files .td.uploaded { width: 130px; text-align: right; }
53+
.files .td.added { width: 90px }
54+
.files .orderby { color: inherit; text-decoration: none; transition: all 0.3s; outline: 5px solid transparent; }
55+
.files .orderby:hover { text-decoration: underline; }
56+
.files .orderby .icon-arrow-down { opacity: 0; transition: all 0.3s ease-in-out; }
57+
.files .orderby.selected .icon-arrow-down { opacity: 0.3; }
58+
.files .orderby:active { background-color: rgba(133, 239, 255, 0.09); outline: 5px solid rgba(133, 239, 255, 0.09); transition: none; }
59+
.files .orderby:hover .icon-arrow-down { opacity: 0.5; }
60+
.files .orderby:not(.desc) .icon-arrow-down { transform: rotateZ(180deg); }
61+
.files .tr.editing .td { background-color: #ede1f582; border-top-color: #ece9ef; }
62+
.files .thead { /*background: linear-gradient(358deg, #e7f1f7, #e9f2f72e);*/ }
63+
.files .thead .td {
64+
border-top: none; color: #8984c2; background-color: #f7f7fc;
65+
font-size: 12px; /*text-transform: uppercase; background-color: transparent; font-weight: bold;*/
66+
}
67+
.files .thead .td a:last-of-type { font-weight: bold; }
68+
.files .thead .td a { text-decoration: none; }
69+
.files .thead .td a:hover { text-decoration: underline; }
70+
.files .tbody { max-height: calc(100vh - 100x); overflow-y: auto; overflow-x: hidden; }
71+
.files .tr { background-color: white; }
72+
.files .td { padding: 10px 20px; border-top: 1px solid #EEE; font-size: 13px; white-space: nowrap; }
73+
.files .td.full { width: 100%; box-sizing: border-box; white-space: pre-line; }
74+
.files .td.pre { width: 0px; color: transparent; padding-left: 0px; border-left: 2px solid transparent; }
75+
.files .tbody .td { height: 18px; }
76+
.files .tbody .td.full { height: auto; }
77+
.files .td.pre .checkbox-outer { opacity: 0.6; margin-left: -11px; margin-top: -15px; width: 18px; height: 12px; display: inline-block; }
78+
.files .tr.modified .td.pre { border-left-color: #7801F5 }
79+
.files .tr.added .td.pre { border-left-color: #00ec93 }
80+
.files .tr.ignored .td.pre { border-left-color: #999; }
81+
.files .tr.ignored { opacity: 0.5; }
82+
.files .tr.optional { background: linear-gradient(90deg, #fff6dd, 30%, white, 10%, white); }
83+
.files .tr.optional_empty { color: #999; font-style: italic; }
84+
.files .td.error { background-color: #F44336; color: white; }
85+
.files .td.site { width: 70px }
86+
.files .td.site .link { color: inherit; text-decoration: none }
87+
.files .td.status .percent {
88+
transition: all 1s ease-in-out; display: inline-block; width: 80px; background-color: #EEE; font-size: 10px;
89+
height: 15px; line-height: 15px; text-align: center; margin-right: 20px;
90+
}
91+
.files .td.name { padding-left: 10px; width: calc(100% - 167px); max-height: 18px; padding-right: 10px; }
92+
.files .tr.nobuttons .td.name { width: calc(100% - 127px); }
93+
.files .tr.nobuttons .td.buttons { width: 0px; }
94+
.files .td.name .title { color: inherit; text-decoration: none }
95+
.files .td.name .link { display: inline-block; overflow: hidden; text-overflow: ellipsis; vertical-align: -4px; max-width: 100%; }
96+
.files .pinned .td.name .link { max-width: calc(100% - 40px); }
97+
.files .thead .td.uploaded { text-align: left }
98+
.files .thead .td.uploaded .title { padding-left: 7px; }
99+
.files .peer .icon-profile { background: currentColor; color: #47d094; font-size: 10px; top: 1px; margin-right: 13px }
100+
.files .peer .icon-profile:before { background: currentColor }
101+
.files .peer .num { color: #969696; }
102+
.files .uploaded .uploaded-text { display: inline-block; text-align: right; }
103+
.files .uploaded .dots-container { display: inline-block; width: 0px; padding-right: 65px;; }
104+
.files .td.buttons { width: 40px; padding-left: 0px; padding-right: 0px; }
105+
.files .td.buttons .edit {
106+
background-color: #2196f336; border-radius: 15px; padding: 1px 9px; font-size: 80%; text-decoration: none; color: #1976D2;
107+
}
108+
.files .checkbox-outer { padding: 15px; padding-left: 20px; padding-right: 0px; }
109+
.files .checkbox {
110+
display: inline-block; width: 12px; height: 12px; border: 2px solid #00000014;
111+
border-radius: 3px; vertical-align: -3px; margin-right: 10px;
112+
}
113+
.files .selected .checkbox { border-color: #dedede }
114+
.files .selected .checkbox:after {
115+
background-color: #dedede; content: ""; text-decoration: none; display: block; width: 10px; height: 10px; margin-left: 1px; margin-top: 1px;
116+
}
117+
.files .tbody .td.size { font-size: 13px }
118+
.files .tbody .td.added, #PageFiles .files .td.access { font-size: 12px; color: #999 }
119+
.files .tr.type-dir .name { font-weight: bold; }
120+
.files .tr.type-parent .name .link { display: inline-block; width: 100%; padding: 5px; margin-top: -5px; }
121+
.files .foot .td { color: #a4a4a4; background-color: #f7f7fc; }
122+
.files .foot .create { float: right; text-decoration: none; position: relative; }
123+
.files .foot .create .link { color: #8c42ed; text-decoration: none; }
124+
.files .foot .create .link:active { background-color: #8c42ed3b; outline: 5px solid #8c42ed3b; }
125+
.files .foot .create .menu { top: 40px; }
126+
127+
128+
/* Editor */
129+
130+
.editor { background-color: #F7F7FC; float: left; width: calc(100% - 280px); box-sizing: border-box; transition: all 0.6s; }
131+
.editor .CodeMirror { height: calc(100vh - 73px); visibility: hidden; }
132+
.editor textarea { width: 100%; height: 800px; white-space: pre; }
133+
.editor .title { margin-left: 20px; }
134+
.editor .editor-head {
135+
padding: 15px 20px; padding-left: 45px; font-size: 18px; font-weight: lighter; border: 1px solid #EEEEF5;
136+
white-space: nowrap; overflow: hidden;
137+
}
138+
.editor.loaded .CodeMirror { visibility: inherit; }
139+
.editor.error .CodeMirror { display: none; }
140+
.editor .button.save { min-width: 30px; text-align: center; transition: all 0.3s; }
141+
.editor .button.save.done { min-width: 80px; }
142+
.editor .error-message { text-align: center; padding: 50px; }
143+
144+
.editor .CodeMirror-foldmarker {
145+
line-height: .3; cursor: pointer; background-color: #ffeb3b61; text-shadow: none; font-family: inherit;
146+
color: #050505; border: 1px solid #ffdf7f; padding: 0px 5px;
147+
}
148+
.editor .CodeMirror-activeline-background { background-color: #F6F6F6 !important; }
723 Bytes
Loading

0 commit comments

Comments
 (0)