diff --git a/src/core/js/uploader_ext.js b/src/core/js/uploader_ext.js new file mode 100644 index 0000000000000000000000000000000000000000..c952b47da50d04f1840df556c83e25865a3cad48 --- /dev/null +++ b/src/core/js/uploader_ext.js @@ -0,0 +1,196 @@ +/* + * ** header v3.0 + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2021 Research Group Biomedical Physics, + * Max-Planck-Institute for Dynamics and Self-Organization Göttingen + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * ** end header + */ + +"use strict"; + +// Convert callbacks to promise for async programming +// Strongly inspired by: https://stackoverflow.com/questions/45052875/how-to-convert-fileentry-to-standard-javascript-file-object-using-chrome-apps-fi/53113059 +async function getFileWithPromise(fileEntry) { + try { + return await new Promise((success, failure) => + fileEntry.file(success, failure)); + } catch (error) { + console.log(error); + } +} + +async function readEntriesWithPromise(dreader) { + try { + return await new Promise((success, failure) => + dreader.readEntries(success, failure)); + } catch (error) { + console.log(error); + } +} + +/** + * uploader module + */ +var uploader = new function() { + + var walkFiles = async function(el, path) { + var lst = []; + if (el.isFile) { + var file = await getFileWithPromise(el); + lst.push({file: file, filename: file.name, path: path}); + } else if (el.isDirectory) { + var dreader = el.createReader(); + var entries = await readEntriesWithPromise(dreader); + + for (var i=0; i<entries.length; i++) { + var fl = await uploader.walkFiles(entries[i], path + el.name + "/"); + lst = lst.concat(fl); + } + } + return lst; + }; + + /** + lst is a list of the form: + [ + {file: ..., + filename: ..., + path: ...}, + ... + ] + */ + var sendFiles = async function (lst, rootpath) { + var formData = new FormData(); + // taken from fileupload.js + var request = "<Request>"; + var index = 1; + for (const f of lst) { + var identifier = "file" + index; + // var identifier = f.path + f.filename; + request = request + '<File upload="' + identifier + '" name="' + f.filename + '" path="' + rootpath + f.path + f.filename + '">'; + // if (typeof atom_par !== "undefined" && atom_par !== "FILE") { + // // add parent + // request = request + '<Parent name="' + atom_par + '" />'; + // } + request = request + '</File>'; + + + index++; + } + request = request + "</Request>"; + + formData.append("FileRepresentation", request); + + var index = 1; + for (const f of lst) { + var identifier = "file" + index; + formData.append(identifier, f.file, identifier); + index++; + } + + console.log(formData); + + try { + var response = await $.ajax({ + url: connection.getBasePath() + "Entity", + method: 'POST', + dataType: "xml", + contentType: false, + processData: false, + data: formData, + }); + } catch (error) { + if (error.status == 0) { + console.log(error); + } else if (error.status != null) { + throw new Error( + "POST file upload returned with HTTP status " + error.status + + " - " + error.statusText); + } else { + throw error; + } + } + }; + + var process_drop_action = async function(lst) { + var fileList = []; + for (var i=0; i<lst.length; i++) { + var el = lst[i].webkitGetAsEntry(); + if (el) { + var fl = await uploader.walkFiles(el, ""); + fileList = fileList.concat(fl); + } + } + + console.log(fileList); + uploader.sendFiles(fileList, "/DataAnalysis/"); + } + + var setup_drop = function(dropArea) { + dropArea.addEventListener("drop", function(ev) { + ev.stopPropagation(); + ev.preventDefault(); + dropArea.style.border = "1px dotted black"; + + uploader.process_drop_action(ev.dataTransfer.items); + }, false); + + dropArea.addEventListener("dragover", function(ev) { + dropArea.style.border = "2px solid black"; + ev.stopPropagation(); + ev.preventDefault(); + }); + + dropArea.addEventListener("dragleave", function(ev) { + dropArea.style.border = "1px dotted black"; + ev.stopPropagation(); + ev.preventDefault(); + }); + }; + + var init = function () { + var target = $("#top-navbar").find("ul").first(); + var upload_dropper = $('<li><div id="droparea">Drop files here to upload...</div></li>'); + upload_dropper[0].style.padding = "12px"; + upload_dropper[0].style.border = "1px dotted black" + $(target).append(upload_dropper); + + uploader.setup_drop(upload_dropper[0]); + }; + + return { + process_drop_action: process_drop_action, + sendFiles: sendFiles, + setup_drop: setup_drop, + walkFiles: walkFiles, + init: init + }; +}(); + + + + + +/** + * Add the extensions to the webui. + */ +$(document).ready(function() { + // if ("${BUILD_MODULE_EXT_BOTTOM_LINE}" == "ENABLED") { + caosdb_modules.register(uploader); + // } +}); diff --git a/src/core/xsl/main.xsl b/src/core/xsl/main.xsl index 4d4df12a667c0c119e69e714ce0078b690f6457d..fd58b1ae6b908cb0e5b41dfdce2176d380de74e4 100644 --- a/src/core/xsl/main.xsl +++ b/src/core/xsl/main.xsl @@ -285,6 +285,12 @@ <xsl:value-of select="concat($basepath,'webinterface/${BUILD_NUMBER}/js/ext_bookmarks.js')"/> </xsl:attribute> </xsl:element> + + <xsl:element name="script"> + <xsl:attribute name="src"> + <xsl:value-of select="concat($basepath,'webinterface/${BUILD_NUMBER}/js/uploader_ext.js')"/> + </xsl:attribute> + </xsl:element> <!--JS_EXTENSIONS--> </xsl:template> <xsl:template name="caosdb-data-container">