--- /dev/null
+// Handle any tasks which require uploading files to the server (such as attachments)
+// h/t https://www.smashingmagazine.com/2018/01/drag-drop-file-uploader-vanilla-js/ which inspired the design of this module
+//
+// Copyright (c) 2016-2023 by the citadel.org team
+//
+// This program is open source software. Use, duplication, or
+// disclosure are subject to the GNU General Public License v3.
+
+var uploads_in_progress = 0;
+var uploads = [] ; // everything the user has uploaded
+
+
+// Turn the specified div into a place where we can upload. (Note: permanently changes the drag-and-drop behavior of that div.)
+function activate_uploads(parent_div) {
+ document.getElementById(parent_div).innerHTML += `
+ <div class="ctdl-upload" id="ctdl-upload">
+ <div id="ctdl_attachments_title" class="ctdl-compose-attachments-title">
+ <div><h1><i class="fa fa-paperclip" style="color:grey"></i>` + _("Attachments:") + ` <span id="num_attachments">` + uploads.length + `</span></h1></div>
+ <div><h1><i class="fas fa-window-close" style="color:red" onClick="show_or_hide_upload_window()"></i></h1></div>
+ </div>
+ <br>
+ <ul id="ctdl-upload_list">
+ </ul>
+ <br>
+ <div id="drop-area" class="ctdl-upload-drop-area">
+ <form class="ctdl-upload-form">
+ <p>${_("Drop files here to upload")}</p>
+ <input type="file" id="fileElem" multiple accept="*/*" onChange="handle_upload_files(this.files)">
+ </form>
+ </div>
+ </div>
+ `;
+
+ // activate drag and drop
+ let dropArea = document.getElementById(parent_div);
+ ;['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
+ dropArea.addEventListener(eventName, upload_prevent_defaults, false)
+ })
+ ;["dragenter", "dragover"].forEach(eventName => {
+ dropArea.addEventListener(eventName, upload_highlight, false)
+ })
+ ;['dragleave', 'drop'].forEach(eventName => {
+ dropArea.addEventListener(eventName, upload_unhighlight, false)
+ })
+ dropArea.addEventListener('drop', upload_handle_drop, false);
+}
+
+
+// prevent drag and drop events from propagating up through the DOM
+function upload_prevent_defaults(e) {
+ e.preventDefault();
+ e.stopPropagation();
+}
+
+
+function upload_handle_drop(e) {
+ let dt = e.dataTransfer;
+ let files = dt.files;
+ handle_upload_files(files);
+}
+
+
+function handle_upload_files(files) {
+ ([...files]).forEach(upload_file)
+}
+
+
+function upload_file(file) {
+ var url = '/ctdl/a/upload';
+ var xhr = new XMLHttpRequest();
+ var formData = new FormData();
+ xhr.open('POST', url, true);
+
+ xhr.addEventListener('readystatechange', function(e) {
+ if (xhr.readyState == 4 && xhr.status == 200) {
+ // remove the "uploading in progress" message
+ let li = document.getElementById("ctdl_uploading_" + uploads_in_progress.toString());
+ li.parentNode.removeChild(li);
+ uploads_in_progress -= 1;
+
+ // The response body will be a JSON array of completed uploads.
+ var j_response = JSON.parse(xhr.response);
+
+ // Add these uploads to the displayed list
+ j_response.forEach((item) => {
+ let new_upl = document.createElement("li");
+ new_upl.innerHTML = item["tempfilename"] + " " + item["uploadfilename"] + " " + item["contenttype"] + " " + item["contentlength"];
+ document.getElementById("ctdl-upload_list").appendChild(new_upl);
+ });
+
+ // append it to the global list of uploads
+ uploads.push(j_response);
+ document.getElementById("num_attachments").innerHTML = uploads.length;
+ }
+ else if (xhr.readyState == 4 && xhr.status != 200) {
+ // remove the "uploading in progress" message (there was an error, so just let it disappear)
+ let li = document.getElementById("ctdl_uploading_" + uploads_in_progress.toString());
+ li.parentNode.removeChild(li);
+ uploads_in_progress -= 1;
+ }
+ })
+
+ formData.append('file', file);
+ xhr.send(formData);
+ uploads_in_progress += 1;
+
+ // Make an "uploading in progress" message appear in the uploads list!
+ progress = document.createElement("li");
+ progress.setAttribute("id", "ctdl_uploading_" + uploads_in_progress.toString());
+ progress.innerHTML = `<img src="/ctdl/s/images/throbber.gif" /> ` + _("Processing dropped files...");
+ document.getElementById("ctdl-upload_list").appendChild(progress);
+}
+
+
+// called when the user drags a file into the upload area
+function upload_highlight(e) {
+ let dropArea = document.getElementById("ctdl-upload");
+ dropArea.classList.add('highlight')
+
+ document.getElementById("ctdl-upload").style.display = "block"; /* also make it appear */
+}
+
+
+// called when the user is no longer dragging a file into the upload area
+function upload_unhighlight(e) {
+ let dropArea = document.getElementById("ctdl-upload");
+ dropArea.classList.remove('highlight')
+}
+
+
+// Show or hide the attachments window in the composer
+function show_or_hide_upload_window() {
+
+ if (document.getElementById("ctdl-upload").style.display == "block") {
+ document.getElementById("ctdl-upload").style.display = "none"; /* turn it off */
+ }
+ else {
+ document.getElementById("ctdl-upload").style.display = "block"; /* turn it on */
+ }
+}
+
+
+// Flush all uploaded files and close the window
+function flush_uploads() {
+ document.getElementById('ctdl-upload').style.display='none';
+ // FIXME tell the server to delete the files
+ uploads=[];
+}
\ No newline at end of file
NO : 0, // do not perform new mail notifications
YES : 1 // yes, perform new mail notifications
};
-var uploads_in_progress = 0;
-var uploads = [] ; // everything the user has uploaded
// This is the async back end for mail_delete_selected()
<div class="ctdl-compose-toolbar">
<span class="ctdl-msg-button" onclick="mail_send_message()"><i class="fa fa-paper-plane" style="color:green"></i> ${_("Send message")} </span>
<span class="ctdl-msg-button"> ${_("Save to Drafts")} </span>
- <span class="ctdl-msg-button" onClick="show_or_hide_attachments()"><i class="fa fa-paperclip" style="color:grey"></i> ${_("Attachments:")} <span id="ctdl_num_attachments"> ${uploads.length} </span></span>
+ <span class="ctdl-msg-button" onClick="show_or_hide_upload_window()"><i class="fa fa-paperclip" style="color:grey"></i> ${_("Attachments:")} <span id="ctdl_num_attachments"> ${uploads.length} </span></span>
<span class="ctdl-msg-button"> ${_("Contacts")} </span>
- <span class="ctdl-msg-button" onClick="document.getElementById('ctdl-upload').style.display='none';uploads=[];gotoroom(current_room)"><i class="fa fa-trash" style="color:red"></i> ${_("Cancel")} </span>
+ <span class="ctdl-msg-button" onClick="flush_uploads();gotoroom(current_room)"><i class="fa fa-trash" style="color:red"></i> ${_("Cancel")} </span>
</div>`
;
activate_uploads("ctdl-editor-body");
}
-
-// Turn the specified div into a place where we can upload. (Note: permanently changes the drag-and-drop behavior of that div.)
-function activate_uploads(parent_div) {
- document.getElementById(parent_div).innerHTML += `
- <div class="ctdl-upload" id="ctdl-upload">
- <div id="ctdl_attachments_title" class="ctdl-compose-attachments-title">
- <div><h1><i class="fa fa-paperclip" style="color:grey"></i>` + _("Attachments:") + ` <span id="num_attachments">` + uploads.length + `</span></h1></div>
- <div><h1><i class="fas fa-window-close" style="color:red" onClick="show_or_hide_attachments()"></i></h1></div>
- </div>
- <br>
- <ul id="ctdl-upload_list">
- </ul>
- <br>
- <div id="drop-area" class="ctdl-upload-drop-area">
- <form class="my-form">
- <p>${_("Drop files here to upload")}</p>
- <input type="file" id="fileElem" multiple accept="*/*" onChange="handle_upload_files(this.files)">
- </form>
- </div>
- </div>
- `;
-
- // activate drag and drop (shamelessly swiped from https://www.smashingmagazine.com/2018/01/drag-drop-file-uploader-vanilla-js/ )
- let dropArea = document.getElementById(parent_div);
- ;['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
- dropArea.addEventListener(eventName, upload_prevent_defaults, false)
- })
- ;["dragenter", "dragover"].forEach(eventName => {
- dropArea.addEventListener(eventName, upload_highlight, false)
- })
- ;['dragleave', 'drop'].forEach(eventName => {
- dropArea.addEventListener(eventName, upload_unhighlight, false)
- })
- dropArea.addEventListener('drop', upload_handle_drop, false);
-}
-
-
-// prevent drag and drop events from propagating up through the DOM
-function upload_prevent_defaults(e) {
- e.preventDefault();
- e.stopPropagation();
-}
-
-
-function upload_handle_drop(e) {
- let dt = e.dataTransfer;
- let files = dt.files;
- handle_upload_files(files);
-}
-
-
-function handle_upload_files(files) {
- ([...files]).forEach(upload_file)
-}
-
-
-function upload_file(file) {
- var url = '/ctdl/a/upload';
- var xhr = new XMLHttpRequest();
- var formData = new FormData();
- xhr.open('POST', url, true);
-
- xhr.addEventListener('readystatechange', function(e) {
- if (xhr.readyState == 4 && xhr.status == 200) {
- // remove the "uploading in progress" message
- let li = document.getElementById("ctdl_uploading_" + uploads_in_progress.toString());
- li.parentNode.removeChild(li);
- uploads_in_progress -= 1;
-
- // The response body will be a JSON array of completed uploads.
- var j_response = JSON.parse(xhr.response);
-
- // Add these uploads to the displayed list
- j_response.forEach((item) => {
- let new_upl = document.createElement("li");
- new_upl.innerHTML = item["tempfilename"] + " " + item["uploadfilename"] + " " + item["contenttype"] + " " + item["contentlength"];
- document.getElementById("ctdl-upload_list").appendChild(new_upl);
- });
-
- // append it to the global list of uploads
- uploads.push(j_response);
- document.getElementById("num_attachments").innerHTML = uploads.length;
- }
- else if (xhr.readyState == 4 && xhr.status != 200) {
- // remove the "uploading in progress" message (there was an error, so just let it disappear)
- let li = document.getElementById("ctdl_uploading_" + uploads_in_progress.toString());
- li.parentNode.removeChild(li);
- uploads_in_progress -= 1;
- }
- })
-
- formData.append('file', file);
- xhr.send(formData);
- uploads_in_progress += 1;
-
- // Make an "uploading in progress" message appear in the uploads list!
- progress = document.createElement("li");
- progress.setAttribute("id", "ctdl_uploading_" + uploads_in_progress.toString());
- progress.innerHTML = `<img src="/ctdl/s/images/throbber.gif" /> ` + _("Processing dropped files...");
- document.getElementById("ctdl-upload_list").appendChild(progress);
-}
-
-
-function upload_highlight(e) {
- let dropArea = document.getElementById("ctdl-upload");
- dropArea.classList.add('highlight')
-
- document.getElementById("ctdl-upload").style.display = "block"; /* also make it appear */
-}
-
-function upload_unhighlight(e) {
- let dropArea = document.getElementById("ctdl-upload");
- dropArea.classList.remove('highlight')
-}
-
-
-// Show or hide the attachments window in the composer
-function show_or_hide_attachments() {
-
- if (document.getElementById("ctdl-upload").style.display == "block") {
- document.getElementById("ctdl-upload").style.display = "none"; /* turn it off */
- }
- else {
- document.getElementById("ctdl-upload").style.display = "block"; /* turn it on */
- }
-}
-
-
// Called when the user clicks the button to make the hidden "CC" and "BCC" lines appear.
// It is also called automatically during a Reply when CC is pre-populated.
function make_cc_bcc_visible() {