diff --git a/aiserver.py b/aiserver.py index b6b219fa..2f7f680e 100644 --- a/aiserver.py +++ b/aiserver.py @@ -6075,9 +6075,32 @@ def send_debug(): #==================================================================# @app.route("/popup_test") def popup_test(): - file_popup("Test Popup", "./", "return_event_name", folder_only=False, editable=True, deleteable=True, jailed=False, item_check=check_if_dir_is_model) + file_popup("Test Popup", "./", "return_event_name", renameable=True, folder_only=False, editable=True, deleteable=True, jailed=False, item_check=check_if_dir_is_model) return "ok" +@socketio.on('upload_file') +def upload_file(data): + print("upload_file {}".format(data['filename'])) + if 'current_folder' in session: + path = os.path.join(session['current_folder'], data['filename']) + print("Want to save to {}".format(path)) + if 'popup_jailed_dir' not in session: + print("Someone is trying to upload a file to your server. Blocked.") + elif session['popup_jailed_dir'] is None: + if os.path.exists(path): + emit("error_popup", "The file already exists. Please delete it or rename the file before uploading", room="UI_2"); + else: + with open(path, "wb") as f: + f.write(data['data']) + get_files_folders(session['current_folder']) + elif session['popup_jailed_dir'] in session['current_folder']: + if os.path.exists(path): + emit("error_popup", "The file already exists. Please delete it or rename the file before uploading", room="UI_2"); + else: + with open(path, "wb") as f: + f.write(data['data']) + get_files_folders(session['current_folder']) + @socketio.on('popup_change_folder') def popup_change_folder(data): print("Doing popup change folder: {}".format(data)) @@ -6091,6 +6114,25 @@ def popup_change_folder(data): else: print("User is trying to get at files in your server outside the jail. Blocked. Jailed Dir: {} Requested Dir: {}".format(session['popup_jailed_dir'], data)) +@socketio.on('popup_rename') +def popup_rename(data): + if 'popup_renameable' not in session: + print("Someone is trying to rename a file in your server. Blocked.") + return + if not session['popup_renameable']: + print("Someone is trying to rename a file in your server. Blocked.") + return + + if session['popup_jailed_dir'] is None: + os.rename(data['file'], data['new_name']) + get_files_folders(os.path.dirname(data['file'])) + elif session['popup_jailed_dir'] in data: + os.rename(data['file'], data['new_name']) + get_files_folders(os.path.dirname(data['file'])) + else: + print("User is trying to rename files in your server outside the jail. Blocked. Jailed Dir: {} Requested Dir: {}".format(session['popup_jailed_dir'], data['file'])) + + @socketio.on('popup_delete') def popup_delete(data): if 'popup_deletable' not in session: @@ -6159,7 +6201,7 @@ def popup_change_file(data): else: print("User is trying to delete files in your server outside the jail. Blocked. Jailed Dir: {} Requested Dir: {}".format(session['popup_jailed_dir'], data)) -def file_popup(popup_title, starting_folder, return_event, jailed=True, folder_only=True, deleteable=False, editable=False, show_breadcrumbs=True, item_check=None, show_hidden=False): +def file_popup(popup_title, starting_folder, return_event, upload=True, jailed=True, folder_only=True, renameable=False, deleteable=False, editable=False, show_breadcrumbs=True, item_check=None, show_hidden=False): #starting_folder = The folder we're going to get folders and/or items from #return_event = the socketio event that will be emitted when the load button is clicked #jailed = if set to true will look for the session variable jailed_folder and prevent navigation outside of that folder @@ -6174,19 +6216,22 @@ def file_popup(popup_title, starting_folder, return_event, jailed=True, folder_o else: session['popup_jailed_dir'] = None session['popup_deletable'] = deleteable + session['popup_renameable'] = renameable session['popup_editable'] = editable session['popup_show_hidden'] = show_hidden session['popup_item_check'] = item_check session['popup_folder_only'] = folder_only session['popup_show_breadcrumbs'] = show_breadcrumbs + session['upload'] = upload - socketio.emit("load_popup", {"popup_title": popup_title, "call_back": return_event, "deleteable": deleteable, "editable": editable}, broadcast=True) + socketio.emit("load_popup", {"popup_title": popup_title, "call_back": return_event, "renameable": renameable, "deleteable": deleteable, "editable": editable, 'upload': upload}, broadcast=True) get_files_folders(starting_folder) def get_files_folders(starting_folder): import stat + session['current_folder'] = starting_folder item_check = session['popup_item_check'] show_breadcrumbs = session['popup_show_breadcrumbs'] show_hidden = session['popup_show_hidden'] diff --git a/static/application.js b/static/application.js index a1654f6f..fc55a848 100644 --- a/static/application.js +++ b/static/application.js @@ -2125,6 +2125,7 @@ $(document).ready(function(){ socket.on('popup_items', function(data){popup_items(data);}); socket.on('popup_breadcrumbs', function(data){popup_breadcrumbs(data);}); socket.on('popup_edit_file', function(data){popup_edit_file(data);}); + socket.on('error_popup', function(data){error_popup(data);}); socket.on('from_server', function(msg) { //console.log(msg); @@ -3148,12 +3149,15 @@ $(document).ready(function(){ var popup_deleteable = false; var popup_editable = false; +var popup_renameable = false; function load_popup(data) { - console.log(data); popup_deleteable = data.deleteable; popup_editable = data.editable; + popup_renameable = data.renameable; var popup = document.getElementById("popup"); + var popup_title = document.getElementById("popup_title"); + popup_title.textContent = data.popup_title; var popup_list = document.getElementById("popup_list"); //first, let's clear out our existing data while (popup_list.firstChild) { @@ -3164,24 +3168,48 @@ function load_popup(data) { breadcrumbs.removeChild(breadcrumbs.firstChild); } + if (data.upload) { + const dropArea = document.getElementById('popup_list'); + dropArea.addEventListener('dragover', (event) => { + event.stopPropagation(); + event.preventDefault(); + // Style the drag-and-drop as a "copy file" operation. + event.dataTransfer.dropEffect = 'copy'; + }); + + dropArea.addEventListener('drop', (event) => { + event.stopPropagation(); + event.preventDefault(); + const fileList = event.dataTransfer.files; + for (file of fileList) { + reader = new FileReader(); + reader.onload = function (event) { + socket.emit("upload_file", {'filename': file.name, "data": event.target.result}); + }; + reader.readAsArrayBuffer(file); + } + }); + } else { + + } + popup.classList.remove("hidden"); //adjust accept button - var accept = document.getElementById("popup_accept"); - accept.classList.add("btn-secondary"); - accept.classList.remove("btn-primary"); - accept.setAttribute("emit", data.call_back); - accept.setAttribute("selected_value", ""); - accept.onclick = function () { - socket.emit(this.emit, this.getAttribute("selected_value")); - document.getElementById("popup").classList.add("hidden"); - }; + if (data.call_back == "") { + document.getElementById("popup_load_cancel").classList.add("hidden"); + } else { + document.getElementById("popup_load_cancel").classList.remove("hidden"); + var accept = document.getElementById("popup_accept"); + accept.classList.add("disabled"); + accept.setAttribute("emit", data.call_back); + accept.setAttribute("selected_value", ""); + accept.onclick = function () { + socket.emit(this.emit, this.getAttribute("selected_value")); + document.getElementById("popup").classList.add("hidden"); + }; + } - //adjust cancel button - var cancel = document.getElementById("popup_cancel"); - cancel.onclick = function () { - document.getElementById("popup").classList.add("hidden"); - }; } function popup_items(data) { @@ -3190,6 +3218,7 @@ function popup_items(data) { while (popup_list.firstChild) { popup_list.removeChild(popup_list.firstChild); } + document.getElementById('popup_upload_input').value = ""; for (item of data) { var list_item = document.createElement("span"); @@ -3209,7 +3238,8 @@ function popup_items(data) { edit_icon.classList.add("edit_icon"); if ((popup_editable) && !(item[0])) { edit_icon.classList.add("oi"); - edit_icon.setAttribute('data-glyph', "pencil"); + edit_icon.setAttribute('data-glyph', "spreadsheet"); + edit_icon.title = "Edit" edit_icon.id = item[1]; edit_icon.onclick = function () { socket.emit("popup_edit", this.id); @@ -3217,12 +3247,31 @@ function popup_items(data) { } list_item.append(edit_icon); + //create the rename icon + var rename_icon = document.createElement("span"); + rename_icon.classList.add("rename_icon"); + if ((popup_renameable) && !(item[0])) { + rename_icon.classList.add("oi"); + rename_icon.setAttribute('data-glyph', "pencil"); + rename_icon.title = "Rename" + rename_icon.id = item[1]; + rename_icon.setAttribute("filename", item[2]); + rename_icon.onclick = function () { + var new_name = prompt("Please enter new filename for \n"+ this.getAttribute("filename")); + if (new_name != null) { + socket.emit("popup_rename", {"file": this.id, "new_name": new_name}); + } + }; + } + list_item.append(rename_icon); + //create the delete icon var delete_icon = document.createElement("span"); delete_icon.classList.add("delete_icon"); if (popup_deleteable) { delete_icon.classList.add("oi"); delete_icon.setAttribute('data-glyph', "x"); + delete_icon.title = "Delete" delete_icon.id = item[1]; delete_icon.setAttribute("folder", item[0]); delete_icon.onclick = function () { @@ -3249,14 +3298,12 @@ function popup_items(data) { popup_item.onclick = function () { var accept = document.getElementById("popup_accept"); if (this.getAttribute("valid") == "true") { - accept.classList.remove("btn-secondary"); - accept.classList.add("btn-primary"); + accept.classList.remove("disabled"); accept.setAttribute("selected_value", this.id); } else { console.log("not valid"); accept.setAttribute("selected_value", ""); - accept.classList.add("btn-secondary"); - accept.classList.remove("btn-primary"); + accept.classList.add("disabled"); if (this.getAttribute("folder") == "true") { console.log("folder"); socket.emit("popup_change_folder", this.id); @@ -3320,3 +3367,19 @@ function popup_edit_file(data) { popup_list.append(textarea); } + +function error_popup(data) { + alert(data); +} + +function upload_file(file_box) { + var fileList = file_box.files; + for (file of fileList) { + reader = new FileReader(); + reader.onload = function (event) { + socket.emit("upload_file", {'filename': file.name, "data": event.target.result}); + }; + reader.readAsArrayBuffer(file); + } +} + diff --git a/static/custom.css b/static/custom.css index 22c1078b..10ed2dc6 100644 --- a/static/custom.css +++ b/static/custom.css @@ -1580,8 +1580,8 @@ body.connected .popupfooter, .popupfooter.always-available { background-color: #262626; padding: 2px; display: grid; - grid-template-areas: "folder_icon delete_icon edit_icon file"; - grid-template-columns: 20px 20px 20px auto; + grid-template-areas: "folder_icon delete_icon edit_icon rename_icon file"; + grid-template-columns: 20px 20px 20px 20px auto; } @@ -1593,6 +1593,10 @@ body.connected .popupfooter, .popupfooter.always-available { grid-area: edit_icon; } +.new_popup .item .rename_icon { + grid-area: rename_icon; +} + .new_popup .item .delete_icon { grid-area: delete_icon; } @@ -1605,6 +1609,14 @@ body.connected .popupfooter, .popupfooter.always-available { background-color: #688f1f; } +.new_popup textarea { + grid-area: textarea; + background-color: #404040; + color: white; + resize: none; + width: 100%; +} + .new_popup .popup_load_cancel { text-align: center; background-color: #285070; diff --git a/templates/index.html b/templates/index.html index 20764ac3..97d381b8 100644 --- a/templates/index.html +++ b/templates/index.html @@ -483,9 +483,13 @@
-