var currentDir = "/"; var listElements; var numberOfSelectedRows = 0; var username = "notaname"; var password = "password"; function relativePath(path) { if (path.startsWith("/")) return path.substr(1); else return path; } function clearContents() { var result = ""; // empty list result += "
" var listElement = document.getElementById("list"); listElement.innerHTML = result; } function loadContents(dir) { numberOfSelectedRows = 0; var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (this.readyState != 4 || this.status != 200) { return; } var list = xhr.responseXML; listElements = list.getElementsByTagName("listentry"); var result = "
"; if (listElements.length == 0) { result += ""; } else { for (var i = 0; i < listElements.length; i++) { var type = listElements[i].getAttribute("type"); if (type == "file") { type = ""; } else if (type == "dir") { type = ""; } else { type = ""; } var selector = ""; if (listElements[i].textContent != "..") { selector = ""; } var mouseupdown = "onmousedown=\"entryMouseDown('" + listElements[i].textContent + "')\" " + "onmouseup=\"entryMouseUp('" + listElements[i].textContent + "')\""; result += "" + selector + "" + ""; } } result += "
(empty)
" + type + "" + listElements[i].textContent + "
To select entry,
click and hold
" var listElement = document.getElementById("list"); listElement.innerHTML = result; } xhr.open("GET", relativePath(dir) + "?command=list", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.send(); } // return list of file names function getFileList() { var result = []; for (var i = 0; i < listElements.length; i++) { result.push(listElements[i].childNodes[0].nodeValue); } return result; } function getFileType(filename) { for (var i = 0; i < listElements.length; i++) { if (listElements[i].childNodes[0].nodeValue == filename) { return listElements[i].getAttribute("type"); } } return ""; } function getRow(filename) { var list = document.getElementById("list"); var rows = list.getElementsByTagName("tr"); for (var i = 0; i < rows.length; i++) { var nameElement = rows[i].getElementsByClassName("name")[0]; if (nameElement.childNodes[0].nodeValue == filename) { return rows[i]; } } return ""; } // return list of files function getSelectedFiles() { var result = []; var list = document.getElementById("list"); var rows = list.getElementsByTagName("tr"); for (var i = 0; i < rows.length; i++) { if (rows[i].classList.contains("selectedrow")) { result.push(rows[i].getElementsByClassName("name")[0].childNodes[0].nodeValue); } } return result; } // As long as this is 1, the mouse was pressed less than 1 second ago var mouseShortFlag = 0; var mouseTimeout = undefined; function getSelection(filename) { var row = getRow(filename); if (row.classList.contains("selectedrow")) { return true; } return false; } function clearSelection(filename) { var row = getRow(filename); if (row.classList.contains("selectedrow")) { row.classList.remove("selectedrow"); numberOfSelectedRows--; } var selectorElement = row.getElementsByClassName("selector")[0]; selectorElement.innerHTML = "☐"; } function setSelection(filename) { if (filename == "..") { // don't select ".." return; } var row = getRow(filename); if (!row.classList.contains("selectedrow")) { row.classList.add("selectedrow"); numberOfSelectedRows++; } var selectorElement = row.getElementsByClassName("selector")[0]; selectorElement.innerHTML = "☑"; } function toggleSelection(filename) { if (filename == "..") { // don't select ".." return; } var row = getRow(filename); var selector_sign; if (row.classList.contains("selectedrow")) { row.classList.remove("selectedrow"); numberOfSelectedRows--; selector_sign = "☐" } else { row.classList.add("selectedrow"); numberOfSelectedRows++; selector_sign = "☑" } var selectorElement = row.getElementsByClassName("selector")[0]; selectorElement.innerHTML = selector_sign; } function mouseTimeoutFunction(filename) { mouseShortFlag = 0; toggleSelection(filename); } function entryMouseDown(filename) { if (mouseTimeout !== undefined) { clearTimeout(mouseTimeout); } if (numberOfSelectedRows > 0) { toggleSelection(filename); } else { mouseShortFlag = 1; mouseTimeout = setTimeout(function(){ mouseTimeoutFunction(filename); }, 1000); } } function entryMouseUp(filename) { if (mouseTimeout !== undefined) { clearTimeout(mouseTimeout); } // short click: download / change dir if (mouseShortFlag) { var type = getFileType(filename); if (type == "file") { download(filename); } else if (type == "dir") { if (filename == "..") { if (!currentDir.includes("/")) { // error: this shouldn't happen alert("Bad path " + currentDir + " for " + filename); return; } currentDir = currentDir.substr(0, currentDir.lastIndexOf("/")); if (currentDir == "") { currentDir = "/"; } setCurrentDir(currentDir); return; } if (!currentDir.endsWith("/")) { currentDir += "/"; } setCurrentDir(currentDir + filename); } } mouseShortFlag = 0; } function showDialog() { document.getElementById("greyout").style.display = 'block'; document.getElementById("dialogwindow").style.display = 'block'; document.getElementById("okbutton").focus(); } function hideDialog() { document.getElementById("greyout").style.display = 'none'; document.getElementById("dialogwindow").style.display = 'none'; } function showMenu() { document.getElementById("greyout").style.display = 'block'; document.getElementById("menuwindow").style.display = 'block'; } function hideMenu() { document.getElementById("greyout").style.display = 'none'; document.getElementById("menuwindow").style.display = 'none'; } // if readOnly = "1", disable respective controls since this setting is global and constant function prepareReadOnly(readOnly) { if (readOnly == "1") { var writecommands = document.getElementsByClassName("writecommand"); for (var i = 0; i < writecommands.length; i++) { writecommands[i].style.display = "none"; } } } function login(title) { showDialog(); document.getElementById("okbutton").onclick = function() { // restore dialog buttons document.getElementById("cancelbutton").style.display = "block"; document.getElementById("okbutton").childNodes[0].nodeValue = "OK"; hideDialog(); username = document.getElementById("loginusername").value; password = document.getElementById("loginpassword").value; initMainpage(); } // rearrange dialog buttons document.getElementById("cancelbutton").style.display = "none"; document.getElementById("okbutton").childNodes[0].nodeValue = "Login"; document.getElementById("dialog").innerHTML = document.getElementById("login-dialog").innerHTML; document.getElementById("logintitle").childNodes[0].nodeValue = title; document.getElementById("loginusername").focus(); document.getElementById("loginusername").onkeydown = function(evt) { if (evt.key == "Enter") { document.getElementById("okbutton").click(); } } document.getElementById("loginpassword").onkeydown = function(evt) { if (evt.key == "Enter") { document.getElementById("okbutton").click(); } } } function initMainpage() { // load title var xhrTitle = new XMLHttpRequest(); xhrTitle.onreadystatechange = function() { if (this.readyState != 4) { return; } if (this.status == 401) { // login error: goto login page var authheader = this.getResponseHeader("WWW-Authenticate"); var title = "Webbox"; // For web servers with standard AUTH BASIC, triggering problems in // client browsers, popping up the browser's "Authenticate" window // but we want our own if (authheader.startsWith("Basic realm=\"") && authheader.endsWith("\"")) { title = authheader.substr(13, authheader.length - 14); } else // Fixed up Apache server if (authheader.startsWith("SR_Basic realm=\"") && authheader.endsWith("\"")) { title = authheader.substr(16, authheader.length - 17); } // enable logout function if logging in document.getElementById("logoutcommand").style.display = "table-row"; login(title); return; } else if (this.status != 200) { document.getElementsByClassName("title")[0].innerHTML = "HTTP error"; return; } var serverInfo = xhrTitle.responseXML; var title = serverInfo.getElementsByTagName("title")[0].textContent; document.getElementsByClassName("title")[0].innerHTML = title; var readOnly = serverInfo.getElementsByTagName("readonly")[0].textContent; prepareReadOnly(readOnly); // if successful: continue loading initMainpage2(); } xhrTitle.open("GET", "?command=server-info", true); xhrTitle.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhrTitle.send(); } // deferred initialization after successful login function initMainpage2() { // fill file list initially setCurrentDir("/"); // load footer var xhrFooter = new XMLHttpRequest(); xhrFooter.onreadystatechange = function() { if (this.readyState != 4 || this.status != 200) { return; } document.getElementsByClassName("footer")[0].innerHTML = xhrFooter.responseText; } xhrFooter.open("GET", "?command=version", true); xhrFooter.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhrFooter.send(); // default action for "Cancel" button: hide dialog window document.getElementById("cancelbutton").onclick = hideDialog; // on click outside of menu, close menu document.getElementById("greyout").onclick = function() { hideDialog(); hideMenu(); } // on Escape, globally hide dialog and menu window document.onkeydown = function(evt) { if (evt.key == "Escape") { hideDialog(); hideMenu(); } } } function setCurrentDir(newDir) { currentDir = newDir; loadContents(newDir); var menu = document.getElementsByClassName("menu")[0]; var firsttd = menu.getElementsByClassName("firsttd")[0]; firsttd.innerHTML = newDir; } function download(filename) { var files = getSelectedFiles(); // if activated via menu, download directly (not as zip) if (files.length == 1 && filename === undefined) { filename = files[0]; } if (filename === undefined) { // download selection as ZIP showDialog(); if (files.length == 0) { document.getElementById("dialog").innerHTML = "No files selected."; document.getElementById("okbutton").onclick = hideDialog; return; } document.getElementById("dialog").innerHTML = document.getElementById("download-zip-dialog").innerHTML; document.getElementById("okbutton").onclick = function() { hideDialog(); // send info request for files var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (this.readyState != 4 || this.status != 200) { return; } var a = document.getElementById("download-a"); a.setAttribute("download", "webbox-download.zip"); var file = new Blob([this.response]); a.href = window.URL.createObjectURL(file); a.click(); progressOff(); } progressOn(); var files = getSelectedFiles(); var parser = new DOMParser(); var xmlDocument = parser.parseFromString("", "text/xml"); var filesElement = xmlDocument.getElementsByTagName("files")[0]; for (var i = 0; i < files.length; i++) { var fileElement = xmlDocument.createElement("file"); fileElement.appendChild(document.createTextNode(files[i])); filesElement.appendChild(fileElement); } xhr.open("POST", relativePath(currentDir) + "?command=download-zip", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.setRequestHeader("Content-type", "text/xml"); xhr.responseType = 'blob'; xhr.send(xmlDocument); } } else { // single file download var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (this.readyState != 4 || this.status != 200) { return; } var a = document.getElementById("download-a"); a.setAttribute("download", filename); var file = new Blob([this.response]); a.href = window.URL.createObjectURL(file); a.click(); progressOff(); } var dir = currentDir; if (dir != "/") { dir += "/" } progressOn(); xhr.open("GET", relativePath(dir) + filename, true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.responseType = 'blob'; xhr.send(); } } function createDir() { showDialog(); // hide dialog when done document.getElementById("okbutton").onclick = function() { // send new folder request for directory var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (this.readyState != 4) { return; } if (this.status != 200) { document.getElementById("dialog").innerHTML = "HTTP error"; } else { document.getElementById("dialog").innerHTML = xhr.responseText; } document.getElementById("okbutton").onclick = hideDialog; document.getElementById("okbutton").focus(); loadContents(currentDir); // load new file list with new dir } var parser = new DOMParser(); var xmlDocument = parser.parseFromString("", "text/xml"); var dirElement = xmlDocument.getElementsByTagName("dirname")[0]; dirElement.appendChild(document.createTextNode(document.getElementById("newdir").value)); xhr.open("POST", relativePath(currentDir) + "?command=newdir", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.setRequestHeader("Content-type", "text/xml"); xhr.send(xmlDocument); } document.getElementById("dialog").innerHTML = document.getElementById("create-dir-dialog").innerHTML; document.getElementById("newdir").focus(); document.getElementById("newdir").onkeydown = function(evt) { if (evt.key == "Enter") { document.getElementById("okbutton").click(); } } } function upload() { var uploadfile = document.getElementById("uploadfile"); uploadfile.click(); } // Callback on selected and uploaded file function onUploadFile() { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (this.readyState != 4) { return; } showDialog(); var message = ""; if (this.status != 200) { message = "HTTP error"; } else { if (xhr.responseText == "") { message = "Upload successful."; loadContents(currentDir); // load new file list with uploaded file } else { message = xhr.responseText; } } document.getElementById("dialog").innerHTML = message; document.getElementById("cancelbutton").style.display = "none"; document.getElementById("okbutton").onclick = function() { hideDialog(); document.getElementById("cancelbutton").style.display = "block"; } document.getElementById("okbutton").focus(); progressOff(); } progressOn(); var uploadfile = document.getElementById("uploadfile"); var formData = new FormData(); for (var i = 0; i < uploadfile.files.length; i++) { formData.append("uploadfile", uploadfile.files[i]); } xhr.open("POST", relativePath(currentDir) + "?command=upload", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.send(formData); } function deleteItems() { showDialog(); var files = getSelectedFiles(); if (files.length == 0) { document.getElementById("dialog").innerHTML = "No files selected."; document.getElementById("okbutton").onclick = hideDialog; return; } var message = "Are sure to delete the following files and directories?

"; for (var i = 0; i < files.length; i++) { message += files[i] + "
"; } document.getElementById("dialog").innerHTML = message; document.getElementById("okbutton").onclick = function() { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (this.readyState != 4) { return; } if (this.status != 200) { document.getElementById("dialog").innerHTML = "HTTP error"; } else { document.getElementById("dialog").innerHTML = xhr.responseText; } document.getElementById("okbutton").onclick = hideDialog; loadContents(currentDir); // load new file list with deleted items } var parser = new DOMParser(); var xmlDocument = parser.parseFromString("", "text/xml"); var filesElement = xmlDocument.getElementsByTagName("files")[0]; for (var i = 0; i < files.length; i++) { var fileElement = xmlDocument.createElement("file"); fileElement.appendChild(document.createTextNode(files[i])); filesElement.appendChild(fileElement); } xhr.open("POST", relativePath(currentDir) + "?command=delete", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.setRequestHeader("Content-type", "text/xml"); xhr.send(xmlDocument); } } function move() { showDialog(); var files = getSelectedFiles(); if (files.length == 0) { document.getElementById("dialog").innerHTML = "No files selected."; document.getElementById("okbutton").onclick = hideDialog; return; } var message = ""; for (var i = 0; i < files.length; i++) { message += files[i] + "
"; } document.getElementById("dialog").innerHTML = document.getElementById("move-dialog").innerHTML; document.getElementById("movedir").focus(); document.getElementById("movedir").onkeydown = function(evt) { if (evt.key == "Enter") { document.getElementById("okbutton").click(); } } document.getElementById("movefiles").innerHTML = message; document.getElementById("okbutton").onclick = function() { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (this.readyState != 4) { return; } if (this.status != 200) { document.getElementById("dialog").innerHTML = "HTTP error"; } else { document.getElementById("dialog").innerHTML = xhr.responseText; } document.getElementById("okbutton").onclick = hideDialog; document.getElementById("okbutton").focus(); loadContents(currentDir); // load new file list with deleted items } var parser = new DOMParser(); var xmlDocument = parser.parseFromString("", "text/xml"); var filesElement = xmlDocument.getElementsByTagName("request")[0]; var targetElement = xmlDocument.createElement("target"); targetElement.appendChild(document.createTextNode(document.getElementById("movedir").value)); filesElement.appendChild(targetElement); for (var i = 0; i < files.length; i++) { var fileElement = xmlDocument.createElement("file"); fileElement.appendChild(document.createTextNode(files[i])); filesElement.appendChild(fileElement); } xhr.open("POST", relativePath(currentDir) + "?command=move", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.setRequestHeader("Content-type", "text/xml"); xhr.send(xmlDocument); } } function rename() { showDialog(); var files = getSelectedFiles(); if (files.length == 0) { document.getElementById("dialog").innerHTML = "No files selected."; document.getElementById("okbutton").onclick = hideDialog; return; } if (files.length > 1) { document.getElementById("dialog").innerHTML = "Only one file can be renamed at once."; document.getElementById("okbutton").onclick = hideDialog; return; } document.getElementById("renameold").innerHTML = files[0]; document.getElementById("dialog").innerHTML = document.getElementById("rename-dialog").innerHTML; document.getElementById("renamenew").value = files[0]; document.getElementById("renamenew").focus(); document.getElementById("renamenew").onkeydown = function(evt) { if (evt.key == "Enter") { document.getElementById("okbutton").click(); } } document.getElementById("okbutton").onclick = function() { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (this.readyState != 4) { return; } if (this.status != 200) { document.getElementById("dialog").innerHTML = "HTTP error"; } else { document.getElementById("dialog").innerHTML = xhr.responseText; } document.getElementById("okbutton").onclick = hideDialog; document.getElementById("okbutton").focus(); loadContents(currentDir); // load new file list with deleted items } var parser = new DOMParser(); var xmlDocument = parser.parseFromString("", "text/xml"); var filesElement = xmlDocument.getElementsByTagName("request")[0]; var oldnameElement = xmlDocument.createElement("oldname"); oldnameElement.appendChild(document.createTextNode(document.getElementById("renameold").childNodes[0].nodeValue)); filesElement.appendChild(oldnameElement); var newnameElement = xmlDocument.createElement("newname"); newnameElement.appendChild(document.createTextNode(document.getElementById("renamenew").value)); filesElement.appendChild(newnameElement); xhr.open("POST", relativePath(currentDir) + "?command=rename", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.setRequestHeader("Content-type", "text/xml"); xhr.send(xmlDocument); } } // File info: date, size, type function info() { showDialog(); document.getElementById("cancelbutton").style.display = "none"; // hide "cancel" button in info dialog, only provide "OK" // hide dialog when done document.getElementById("okbutton").onclick = function() { hideDialog(); document.getElementById("cancelbutton").style.display = "block"; } var files = getSelectedFiles(); if (files.length == 0) { document.getElementById("dialog").innerHTML = "No files selected."; return; } // send info request for files var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (this.readyState != 4) { return; } if (this.status != 200) { document.getElementById("dialog").innerHTML = "HTTP error"; } else { document.getElementById("dialog").innerHTML = xhr.responseText; } } var parser = new DOMParser(); var xmlDocument = parser.parseFromString("", "text/xml"); var filesElement = xmlDocument.getElementsByTagName("files")[0]; for (var i = 0; i < files.length; i++) { var fileElement = xmlDocument.createElement("file"); fileElement.appendChild(document.createTextNode(files[i])); filesElement.appendChild(fileElement); } xhr.open("POST", relativePath(currentDir) + "?command=info", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.setRequestHeader("Content-type", "text/xml"); xhr.send(xmlDocument); } // select all files, except if all are selected, unselect all function selectAll() { var files = getFileList(); var allSelected = true; for (var i = 0; i < files.length; i++) { if (getSelection(files[i]) === false && files[i] != "..") { allSelected = false; } } for (var i = 0; i < files.length; i++) { if (allSelected) { clearSelection(files[i]); } else { setSelection(files[i]); } } } function refresh() { loadContents(currentDir); // load new file list } function logout() { showDialog(); document.getElementById("okbutton").onclick = function() { hideDialog(); var menu = document.getElementsByClassName("menu")[0]; var firsttd = menu.getElementsByClassName("firsttd")[0]; firsttd.innerHTML = "/"; clearContents(); username = "notaname"; password = "password"; initMainpage(); } document.getElementById("dialog").innerHTML = document.getElementById("logout-dialog").innerHTML; } // Progress indication function drawDot(c, offsetx, offsety, radius, distance, phase) { c.beginPath(); c.arc(distance * Math.sin(phase) + offsetx, - distance * Math.cos(phase) + offsety, radius, 0, 2 * Math.PI); c.fill(); } function drawLogo(canvasid, rotation) { var canvas = document.getElementById(canvasid); var height = canvas.height; var width = canvas.width; var radius = height * 0.1; var distance = height * 0.1 * 4 / 3; var c = canvas.getContext("2d"); c.clearRect(0, 0, width, height); c.fillStyle = "#1132A7"; drawDot(c, width / 2, height / 2, radius, distance, rotation); drawDot(c, width / 2, height / 2, radius, distance, rotation + 2 * Math.PI / 3); drawDot(c, width / 2, height / 2, radius, distance, rotation + 2 * Math.PI / 3 * 2); drawDot(c, width / 2, height / 2, radius, distance * 2, rotation + Math.PI); drawDot(c, width / 2, height / 2, radius, distance * 2, rotation + Math.PI + 2 * Math.PI / 3); drawDot(c, width / 2, height / 2, radius, distance * 2, rotation + Math.PI + 2 * Math.PI / 3 * 2); } var progressState = 0; function drawAni(timeStamp) { var rotation = timeStamp / 1000 * 6; drawLogo("progresscanvas", rotation); if (progressState == 1) { requestAnimationFrame(drawAni); } } function progressOn() { progressState = 1; document.getElementById("progresswindow").style.display = "block"; requestAnimationFrame(drawAni); } function progressOff() { progressState = 0; document.getElementById("progresswindow").style.display = "none"; }