Updated setting pane; added contect menu
|
@ -23,3 +23,5 @@ n/a
|
|||
![1 Videos List](images/pic1.png)
|
||||
![2 Video Playing](images/pic2.png)
|
||||
![3 Images List](images/pic3.png)
|
||||
![4 Context menu](images/pic4.png)
|
||||
![5 Settings Pane With Upload And Create Functionality](images/pic5.png)
|
BIN
images/pic1.png
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 1.3 MiB |
BIN
images/pic2.png
Before Width: | Height: | Size: 2.4 MiB After Width: | Height: | Size: 2.7 MiB |
BIN
images/pic3.png
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.7 MiB |
After Width: | Height: | Size: 454 KiB |
After Width: | Height: | Size: 344 KiB |
|
@ -1,8 +1,9 @@
|
|||
# Python imports
|
||||
import os, json, secrets
|
||||
import os, json, secrets, re, shutil
|
||||
|
||||
# Lib imports
|
||||
from flask import request, session, render_template, send_from_directory, redirect
|
||||
from flask_uploads import UploadSet, configure_uploads, ALL
|
||||
from flask_login import current_user
|
||||
|
||||
|
||||
|
@ -14,6 +15,8 @@ from core.utils.shellfm import WindowController # Get file manager controller
|
|||
|
||||
msgHandler = MessageHandler()
|
||||
window_controllers = {}
|
||||
# valid_fname_pat = re.compile(r"/^[a-zA-Z0-9-_\[\]\(\)| ]+$/")
|
||||
valid_fname_pat = re.compile(r"[a-z0-9A-Z-_\[\]\(\)\| ]{4,20}")
|
||||
|
||||
|
||||
def get_window_controller():
|
||||
|
@ -88,13 +91,14 @@ def listFiles(_hash = None):
|
|||
msg = "Can't manage the request type..."
|
||||
return msgHandler.createMessageJSON("danger", msg)
|
||||
|
||||
@app.route('/api/file-manager-action/<_type>/<_hash>')
|
||||
@app.route('/api/file-manager-action/<_type>/<_hash>', methods=['GET', 'POST'])
|
||||
def fileManagerAction(_type, _hash = None):
|
||||
view = get_window_controller().get_window(1).get_view(0)
|
||||
|
||||
if _type == "reset-path" and _hash == None:
|
||||
if _type == "reset-path" and _hash == "None":
|
||||
view.set_to_home()
|
||||
return redirect("/")
|
||||
msg = "Returning to home directory..."
|
||||
return msgHandler.createMessageJSON("success", msg)
|
||||
|
||||
folder = view.get_current_directory()
|
||||
file = view.get_path_part_from_hash(_hash)
|
||||
|
@ -119,6 +123,30 @@ def fileManagerAction(_type, _hash = None):
|
|||
return msgHandler.createMessageJSON("success", msg)
|
||||
|
||||
|
||||
# NOTE: Positionally protecting actions further down that are privlidged
|
||||
# Be aware of ordering!
|
||||
msg = "Log in with an Admin privlidged user to do this action!"
|
||||
if not oidc.user_loggedin:
|
||||
return msgHandler.createMessageJSON("danger", msg)
|
||||
elif oidc.user_loggedin:
|
||||
isAdmin = oidc.user_getfield("isAdmin")
|
||||
if isAdmin != "yes" :
|
||||
return msgHandler.createMessageJSON("danger", msg)
|
||||
|
||||
|
||||
if _type == "delete":
|
||||
try:
|
||||
msg = f"[Success] Deleted the file/folder -->: {file} !"
|
||||
if os.path.isfile(fpath):
|
||||
os.unlink(fpath)
|
||||
else:
|
||||
shutil.rmtree(fpath)
|
||||
return msgHandler.createMessageJSON("success", msg)
|
||||
except Exception as e:
|
||||
msg = "[Error] Unable to delete the file/folder...."
|
||||
return msgHandler.createMessageJSON("danger", msg)
|
||||
|
||||
|
||||
@app.route('/api/list-favorites', methods=['GET', 'POST'])
|
||||
def listFavorites():
|
||||
if request.method == 'POST':
|
||||
|
@ -161,13 +189,91 @@ def manageFavorites(_action):
|
|||
fave = Favorites(link = sub_path)
|
||||
db.session.add(fave)
|
||||
msg = "Added to Favorites successfully..."
|
||||
else:
|
||||
elif ACTION == "delete":
|
||||
fave = db.session.query(Favorites).filter_by(link = sub_path).first()
|
||||
db.session.delete(fave)
|
||||
msg = "Deleted from Favorites successfully..."
|
||||
else:
|
||||
msg = "Couldn't handle action for favorites item..."
|
||||
return msgHandler.createMessageJSON("danger", msg)
|
||||
|
||||
db.session.commit()
|
||||
return msgHandler.createMessageJSON("success", msg)
|
||||
else:
|
||||
msg = "Can't manage the request type..."
|
||||
return msgHandler.createMessageJSON("danger", msg)
|
||||
|
||||
|
||||
@app.route('/api/create/<_type>', methods=['GET', 'POST'])
|
||||
def create_item(_type = None):
|
||||
if request.method == 'POST':
|
||||
msg = "Log in with an Admin privlidged user to upload files!"
|
||||
if not oidc.user_loggedin:
|
||||
return msgHandler.createMessageJSON("danger", msg)
|
||||
elif oidc.user_loggedin:
|
||||
isAdmin = oidc.user_getfield("isAdmin")
|
||||
if isAdmin != "yes" :
|
||||
return msgHandler.createMessageJSON("danger", msg)
|
||||
|
||||
TYPE = _type.strip()
|
||||
FNAME = str(request.values['fname']).strip()
|
||||
|
||||
if not re.fullmatch(valid_fname_pat, FNAME):
|
||||
msg = "A new item name can only contain alphanumeric, -, _, |, [], (), or spaces and must be minimum of 4 and max of 20 characters..."
|
||||
return msgHandler.createMessageJSON("danger", msg)
|
||||
|
||||
view = get_window_controller().get_window(1).get_view(0)
|
||||
folder = view.get_current_directory()
|
||||
new_item = folder + '/' + FNAME
|
||||
|
||||
try:
|
||||
if TYPE == "dir":
|
||||
os.mkdir(new_item)
|
||||
elif TYPE == "file":
|
||||
open(new_item + ".txt", 'a').close()
|
||||
else:
|
||||
msg = "Couldn't handle action type for api create..."
|
||||
return msgHandler.createMessageJSON("danger", msg)
|
||||
except Exception as e:
|
||||
print(repr(e))
|
||||
msg = "Couldn't create file/folder. An unexpected error occured..."
|
||||
return msgHandler.createMessageJSON("danger", msg)
|
||||
|
||||
|
||||
msg = "[Success] created the file/dir..."
|
||||
return msgHandler.createMessageJSON("success", msg)
|
||||
else:
|
||||
msg = "Can't manage the request type..."
|
||||
return msgHandler.createMessageJSON("danger", msg)
|
||||
|
||||
|
||||
@app.route('/upload', methods=['GET', 'POST'])
|
||||
def upload():
|
||||
if request.method == 'POST' and len(request.files) > 0:
|
||||
msg = "Log in with an Admin privlidged user to upload files!"
|
||||
if not oidc.user_loggedin:
|
||||
return msgHandler.createMessageJSON("danger", msg)
|
||||
elif oidc.user_loggedin:
|
||||
isAdmin = oidc.user_getfield("isAdmin")
|
||||
if isAdmin != "yes" :
|
||||
return msgHandler.createMessageJSON("danger", msg)
|
||||
|
||||
view = get_window_controller().get_window(1).get_view(0)
|
||||
folder = view.get_current_directory()
|
||||
UPLOADS_PTH = folder + '/'
|
||||
files = UploadSet('files', ALL, default_dest=lambda x: UPLOADS_PTH)
|
||||
configure_uploads(app, files)
|
||||
|
||||
for file in request.files:
|
||||
try:
|
||||
files.save(request.files[file])
|
||||
except Exception as e:
|
||||
print(repr(e))
|
||||
msg = "[Error] Failed to upload some or all of the file(s)..."
|
||||
return msgHandler.createMessageJSON("danger", msg)
|
||||
|
||||
msg = "[Success] Uploaded file(s)..."
|
||||
return msgHandler.createMessageJSON("success", msg)
|
||||
else:
|
||||
msg = "Can't manage the request type..."
|
||||
return msgHandler.createMessageJSON("danger", msg)
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
.menu {
|
||||
width: 165px;
|
||||
z-index: 999;
|
||||
box-shadow: 0 4px 5px 3px rgba(0, 0, 0, 0.2);
|
||||
background-color: rgba(0, 0, 0, 0.64);
|
||||
position: fixed;
|
||||
display: none;
|
||||
transition: 0.2s display ease-in;
|
||||
}
|
||||
.menu .menu-options {
|
||||
list-style: none;
|
||||
padding: 10px 0;
|
||||
z-index: 1;
|
||||
}
|
||||
.menu .menu-options .menu-option {
|
||||
font-weight: 500;
|
||||
z-index: 1;
|
||||
padding: 10px 40px 10px 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.menu .menu-options .menu-option:hover {
|
||||
background: rgba(255, 255, 255, 0.64);
|
||||
color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
button {
|
||||
background: grey;
|
||||
border: none;
|
||||
}
|
||||
button .next {
|
||||
color: green;
|
||||
}
|
||||
button[disabled="false"]:hover .next {
|
||||
color: red;
|
||||
animation: move 0.5s;
|
||||
animation-iteration-count: 2;
|
||||
}
|
||||
|
||||
@keyframes move {
|
||||
from {
|
||||
transform: translate(0%);
|
||||
}
|
||||
50% {
|
||||
transform: translate(-40%);
|
||||
}
|
||||
to {
|
||||
transform: transform(0%);
|
||||
}
|
||||
}
|
|
@ -1,3 +1,13 @@
|
|||
const goHomeAjax = async (hash) => {
|
||||
const data = "empty=NULL";
|
||||
doAjax("api/file-manager-action/reset-path/None", data, "reset-path");
|
||||
}
|
||||
|
||||
const deleteItemAjax = async (hash) => {
|
||||
const data = "empty=NULL";
|
||||
doAjax("api/file-manager-action/delete/" + hash, data, "delete-file");
|
||||
}
|
||||
|
||||
const listFilesAjax = async (hash) => {
|
||||
const data = "empty=NULL";
|
||||
doAjax("api/list-files/" + hash, data, "list-files");
|
||||
|
@ -19,6 +29,8 @@ const manageFavoritesAjax = async (action) => {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const doAjax = (actionPath, data, action) => {
|
||||
let xhttp = new XMLHttpRequest();
|
||||
|
||||
|
@ -44,6 +56,60 @@ const doAjax = (actionPath, data, action) => {
|
|||
xhttp.send(data);
|
||||
}
|
||||
|
||||
const doAjaxUpload = (actionPath, data, fname, action) => {
|
||||
let bs64 = btoa(unescape(encodeURIComponent(fname))).split("==")[0];
|
||||
const query = '[id="' + bs64 + '"]';
|
||||
let progressbar = document.querySelector(query);
|
||||
let xhttp = new XMLHttpRequest();
|
||||
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState === 4 && this.status === 200) {
|
||||
if (this.responseText != null) { // this.responseXML if getting XML data
|
||||
postAjaxController(JSON.parse(this.responseText), action);
|
||||
} else {
|
||||
msg = "[Fail] Status Code: " + response.status +
|
||||
"\n[Message] --> " + response.statusText;
|
||||
handleMessage('alert-warning', msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// For upload tracking with GET...
|
||||
xhttp.onprogress = function (e) {
|
||||
if (e.lengthComputable) {
|
||||
percent = (e.loaded / e.total) * 100;
|
||||
text = parseFloat(percent).toFixed(2) + '% Complete (' + fname + ')';
|
||||
if (e.loaded !== e.total ) {
|
||||
updateProgressBar(progressbar, text, percent, "info");
|
||||
} else {
|
||||
updateProgressBar(progressbar, text, percent, "success");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For upload tracking with POST...
|
||||
xhttp.upload.addEventListener("progress", function(e){
|
||||
if (e.lengthComputable) {
|
||||
percent = parseFloat( Math.floor(
|
||||
(
|
||||
(e.loaded / e.total) * 100 ).toFixed(2)
|
||||
).toFixed(2)
|
||||
);
|
||||
text = percent + '% Complete (' + fname + ')';
|
||||
if (percent <= 95) {
|
||||
updateProgressBar(progressbar, text, percent, "info");
|
||||
} else {
|
||||
updateProgressBar(progressbar, text, percent, "success");
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
|
||||
xhttp.open("POST", actionPath);
|
||||
// Force return to be JSON NOTE: Use application/xml to force XML
|
||||
xhttp.overrideMimeType('application/json');
|
||||
xhttp.send(data);
|
||||
}
|
||||
|
||||
const fetchData = async (url) => {
|
||||
let response = await fetch(url);
|
||||
return await response.json();
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
const menu = document.querySelector(".menu");
|
||||
let menuVisible = false;
|
||||
let active_card = null;
|
||||
|
||||
const toggleMenu = command => {
|
||||
menu.style.display = command === "show" ? "block" : "none";
|
||||
menu.style.zIndex = "9999";
|
||||
menuVisible = !menuVisible;
|
||||
};
|
||||
|
||||
const setPosition = ({ top, left }) => {
|
||||
menu.style.left = `${left}px`;
|
||||
menu.style.top = `${top}px`;
|
||||
toggleMenu("show");
|
||||
};
|
||||
|
||||
window.addEventListener("click", e => {
|
||||
if(menuVisible) toggleMenu("hide");
|
||||
});
|
||||
|
||||
window.addEventListener("contextmenu", e => {
|
||||
e.preventDefault();
|
||||
|
||||
let target = e.target;
|
||||
let elm = target;
|
||||
while (elm.nodeName != "BODY") {
|
||||
if (!elm.classList.contains("card")) {
|
||||
elm = elm.parentElement;
|
||||
} else {
|
||||
active_card = elm;
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const origin = {
|
||||
left: e.pageX,
|
||||
top: e.pageY
|
||||
};
|
||||
setPosition(origin);
|
||||
return false;
|
||||
});
|
|
@ -0,0 +1,30 @@
|
|||
const createItem = (type) => {
|
||||
if (type == null || type == '') {
|
||||
displayMessage("Create type isn't set...", "danger", 3, "settings-alert-zone-new-items");
|
||||
return ;
|
||||
}
|
||||
|
||||
let newItem = document.getElementById("newItem");
|
||||
let fname = newItem.value;
|
||||
|
||||
const regex = /^[a-z0-9A-Z-_\[\]\(\)\| ]{4,20}$/;
|
||||
if (fname.search(regex) == -1) {
|
||||
displayMessage("A new item name can only contain alphanumeric, -, _, |, [], (), or spaces and must be minimum of 4 and max of 20 characters...", "danger", 3, "settings-alert-zone-new-items");
|
||||
return ;
|
||||
}
|
||||
|
||||
newItem.value = "";
|
||||
createItemAjax(type, fname);
|
||||
}
|
||||
|
||||
|
||||
$( "#toUpload" ).bind( "change", function(eve) {
|
||||
const files = eve.target.files;
|
||||
setUploadListTitles(files);
|
||||
|
||||
});
|
||||
|
||||
$( "#uploadFiles" ).bind( "click", function(eve) {
|
||||
const files = document.getElementById('toUpload').files;
|
||||
uploadFiles(files);
|
||||
});
|
|
@ -1,7 +1,35 @@
|
|||
const postAjaxController = (data, action) => {
|
||||
if (data.message) {
|
||||
message = data.message
|
||||
displayMessage(message.text, message.type);
|
||||
type = data.message.type
|
||||
message = data.message.text
|
||||
|
||||
if (action === "reset-path") {
|
||||
reloadDirectory();
|
||||
return ;
|
||||
}
|
||||
|
||||
if (action === "delete-file") {
|
||||
reloadDirectory();
|
||||
displayMessage(message, type);
|
||||
return ;
|
||||
}
|
||||
|
||||
if (action === "upload-text" || action === "upload-file") {
|
||||
let field = null;
|
||||
if (action === "upload-text") field = "settings-alert-zone-text";
|
||||
if (action === "upload-file") field = "settings-alert-zone-files";
|
||||
displayMessage(message, type, 3, field);
|
||||
reloadDirectory();
|
||||
return ;
|
||||
}
|
||||
|
||||
if (action === "create-item") {
|
||||
displayMessage(message, type, 3, "settings-alert-zone-new-items");
|
||||
reloadDirectory();
|
||||
return ;
|
||||
}
|
||||
|
||||
displayMessage(message, type);
|
||||
return ;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
|
||||
// Uploader Logic
|
||||
const setUploadListTitles = (files = null) => {
|
||||
if (files == null) {
|
||||
return ;
|
||||
}
|
||||
|
||||
let list = document.getElementById('uploadListTitles');
|
||||
clearChildNodes(list);
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
let liTag = document.createElement('LI');
|
||||
let name = document.createTextNode(files[i].name);
|
||||
|
||||
liTag.className = "list-group-item disabled progress-bar";
|
||||
let bs64 = btoa(unescape(encodeURIComponent(files[i].name))).split("==")[0];
|
||||
liTag.setAttribute("id", bs64);
|
||||
liTag.append(name);
|
||||
list.append(liTag);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const uploadFiles = (files = null) => {
|
||||
const size = files.length;
|
||||
|
||||
if (files == null || size < 1) {
|
||||
displayMessage("Nothing to upload...", "warning", "page-alert-zone-2");
|
||||
return ;
|
||||
}
|
||||
|
||||
// Multi-upload...
|
||||
if (size > 1) {
|
||||
for (var i = 0; i < size; i++) {
|
||||
file = files[i];
|
||||
name = file.name;
|
||||
data = createFormDataFiles([file]);
|
||||
doAjaxUpload('upload', data, name, "upload-file");
|
||||
}
|
||||
} else { // Single upload...
|
||||
data = createFormDataFiles(files);
|
||||
name = files[0].name;
|
||||
doAjaxUpload('upload', data, name, "upload-file");
|
||||
}
|
||||
}
|
||||
|
||||
const createFormDataFiles = (files) => {
|
||||
let form = new FormData();
|
||||
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
form.append(files[i].name, files[i]);
|
||||
}
|
||||
return form;
|
||||
}
|
||||
|
||||
// Progressbar handler
|
||||
const updateProgressBar = (progressbar = null, text = "Nothing uploading...",
|
||||
percent = 0, type = "error") => {
|
||||
if (progressbar == null) {
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
if (type == "info") {
|
||||
progressbar.setAttribute("aria-valuenow", percent);
|
||||
progressbar.style.width = percent + "%";
|
||||
// progressbar.innerText = text;
|
||||
progressbar.classList.remove('bg-success');
|
||||
progressbar.classList.add('progress-bar-animated');
|
||||
progressbar.classList.add('bg-info');
|
||||
return ;
|
||||
}
|
||||
|
||||
if (type == "success") {
|
||||
progressbar.setAttribute("aria-valuenow", 100);
|
||||
progressbar.style.width = "100%";
|
||||
// progressbar.innerText = text;
|
||||
progressbar.classList.remove('progress-bar-animated');
|
||||
progressbar.classList.remove('bg-info');
|
||||
progressbar.classList.add('bg-success');
|
||||
return ;
|
||||
}
|
||||
|
||||
progressbar.style.width = "100%";
|
||||
progressbar.innerText = "An Error Occured";
|
||||
progressbar.classList.remove('progress-bar-animated');
|
||||
progressbar.classList.remove('bg-info');
|
||||
progressbar.classList.remove('bg-success');
|
||||
progressbar.classList.add('bg-danger');
|
||||
}
|
|
@ -1,3 +1,37 @@
|
|||
// Context Menu items
|
||||
|
||||
const goHome = () => {
|
||||
goHomeAjax();
|
||||
}
|
||||
|
||||
const clearUlList = () => {
|
||||
const titles = document.getElementById('uploadListTitles');
|
||||
const files = document.getElementById('toUpload');
|
||||
|
||||
files.value = null;
|
||||
clearChildNodes(titles);
|
||||
}
|
||||
|
||||
const downloadItem = (eve) => {
|
||||
let elm = active_card.querySelector('a');
|
||||
elm.click();
|
||||
}
|
||||
|
||||
const deleteItem = (eve) => {
|
||||
let elm = active_card.querySelector('[hash]'); // With attribute named "hash"
|
||||
let elm2 = active_card.querySelector('[title]'); // With attribute named "title"
|
||||
const hash = elm.getAttribute("hash");
|
||||
const title = elm2.getAttribute("title");
|
||||
|
||||
let res = confirm("Delete: " + title + " ?");
|
||||
if (res == true) {
|
||||
deleteItemAjax(hash);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Header menu items
|
||||
const reloadDirectory = () => {
|
||||
const target = document.getElementById('refresh-btn');
|
||||
const hash = target.getAttribute("hash");
|
||||
|
@ -5,7 +39,7 @@ const reloadDirectory = () => {
|
|||
}
|
||||
|
||||
const goUpADirectory = () => {
|
||||
const target = document.getElementById('back-btn')
|
||||
const target = document.getElementById('back-btn');
|
||||
const hash = target.getAttribute("hash");
|
||||
listFilesAjax(hash);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
<!-- Site CSS -->
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css')}}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/context-menu.css')}}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/overrides.css')}}">
|
||||
{% block header_css_additional %}
|
||||
{% endblock header_css_additional %}
|
||||
|
@ -47,11 +48,25 @@
|
|||
</head>
|
||||
{% endblock %}
|
||||
<body>
|
||||
<video id="bg" src="{{ url_for('static', filename='imgs/backgrounds/particles.mp4')}}"
|
||||
<!-- <video id="bg" src="{{ url_for('static', filename='imgs/backgrounds/particles.mp4')}}"
|
||||
poster="{{ url_for('static', filename='imgs/backgrounds/000.png')}}"
|
||||
autoplay loop>
|
||||
</video> -->
|
||||
|
||||
<video id="bg" src="{{ url_for('static', filename='imgs/backgrounds/tendrels.webm')}}"
|
||||
poster="{{ url_for('static', filename='imgs/backgrounds/000.png')}}"
|
||||
autoplay loop>
|
||||
</video>
|
||||
|
||||
<div class="menu">
|
||||
<ul class="menu-options">
|
||||
<li class="menu-option" onclick="goHome()">Home Directory</li>
|
||||
<li class="menu-option" onclick="clearUlList()">Clear Upload List</li>
|
||||
<li class="menu-option" onclick="downloadItem()">Download</li>
|
||||
<li class="menu-option" onclick="deleteItem()">Delete</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{% block body_header %}
|
||||
{% include "body-header.html" %}
|
||||
|
||||
|
@ -115,6 +130,8 @@
|
|||
<!-- Application Imports -->
|
||||
{% block body_scripts_additional %}
|
||||
{% endblock body_scripts_additional%}
|
||||
|
||||
<script src="{{ url_for('static', filename='js/context-menu.js')}}"></script>
|
||||
{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -11,27 +11,33 @@
|
|||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col scroller" style="max-height: 30em; overflow: auto;">
|
||||
|
||||
<!-- <center>
|
||||
<form>
|
||||
<input class="ulFile" type="file" title="files To Upload" name="filesToUpload[]" data-bs-multiple-caption="{count} files selected" multiple />
|
||||
<input type="button" onclick="uploadFiles()" name="UploadFiles" title="Upload File(s)" value="Upload File(s)" />
|
||||
<input type="reset" title="Clear" id="CLEARBTTN" value="Clear" style="display:none;">
|
||||
<input type="text" id="DIRPATHUL" name="DIRPATHUL" value="">
|
||||
</form>
|
||||
<br/>
|
||||
<input type="text" id="NewItem" value=""/>
|
||||
<input type="button" value="New Dir" onclick="createItem('dir')"/>
|
||||
<input type="button" value="New File" onclick="createItem('file')"/>
|
||||
<input type="button" value="Show Server Messages" onclick="tgglElmView('serverMsgView')"/>
|
||||
<br/>
|
||||
<input id="MergeType" type="checkbox" onchange="getDir('./')" />
|
||||
<label for="MergeType">Show seassons in same list.</label>
|
||||
</center> -->
|
||||
|
||||
<div class="row scroller" style="max-height: 30em; overflow: auto;">
|
||||
<!-- File Upload -->
|
||||
<div class="col-md-6 controls-secondary">
|
||||
{% if oidc_loggedin() and oidc_isAdmin() %}
|
||||
<!-- Server Messages -->
|
||||
<div id="settings-alert-zone-files"></div>
|
||||
<!-- To Upload List -->
|
||||
<ul id="uploadListTitles" class="list-group scroller" style="min-height: 286px; max-height: 286px; overflow: hidden auto;">
|
||||
</ul>
|
||||
<input id="toUpload" class="btn btn-dark" type="file" multiple>
|
||||
<button id="uploadFiles" class="btn btn-success">Submit Files...</button>
|
||||
{% else %}
|
||||
<h3>Upload not available to this user...</h3>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-md-6 controls-secondary">
|
||||
{% if oidc_loggedin() and oidc_isAdmin() %}
|
||||
<div id="settings-alert-zone-new-items"></div>
|
||||
<input type="text" id="newItem" placeholder="File name..." value=""/>
|
||||
<input type="button" class="btn btn-dark" value="New Dir" onclick="createItem('dir')"/>
|
||||
<input type="button" class="btn btn-dark" value="New File" onclick="createItem('file')"/>
|
||||
{% endif %}
|
||||
<br/>
|
||||
<!-- <input id="MergeType" type="checkbox" onchange="getDir('./')" />
|
||||
<label for="MergeType">Show seassons in same list.</label> -->
|
||||
</div>
|
||||
<div id="page-alert-zone-2"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|