a8c3b9bb8784fb650c4203c4643ee8445b1b26f3
[citadel.git] / webcit-ng / static / js / upload.js
1 // Handle any tasks which require uploading files to the server (such as attachments)
2 // h/t https://www.smashingmagazine.com/2018/01/drag-drop-file-uploader-vanilla-js/ which inspired the design of this module
3 //
4 // Copyright (c) 2016-2023 by the citadel.org team
5 //
6 // This program is open source software.  Use, duplication, or
7 // disclosure are subject to the GNU General Public License v3.
8
9 var uploads_in_progress = 0;
10 var uploads = [] ;                                                              // everything the user has uploaded
11
12
13 // Turn the specified div into a place where we can upload.  (Note: permanently changes the drag-and-drop behavior of that div.)
14 function activate_uploads(parent_div) {
15                 document.getElementById(parent_div).innerHTML += `
16                         <div class="ctdl-upload" id="ctdl-upload">
17                                 <div id="ctdl_attachments_title" class="ctdl-compose-attachments-title">
18                                         <div><h1><i class="fa fa-paperclip" style="color:grey"></i>` + _("Attachments:") + ` <span id="num_attachments">` + uploads.length + `</span></h1></div>
19                                         <div><h1><i class="fas fa-window-close" style="color:red" onClick="show_or_hide_upload_window()"></i></h1></div>
20                                 </div>
21                                 <br>
22                                 <ul id="ctdl-upload_list">
23                                 </ul>
24                                 <br>
25                                 <div id="drop-area" class="ctdl-upload-drop-area">
26                                         <form class="ctdl-upload-form">
27                                                 <p>${_("Drop files here to upload")}</p>
28                                                 <input type="file" id="fileElem" multiple accept="*/*" onChange="handle_upload_files(this.files)">
29                                         </form>
30                                 </div>
31                         </div>
32                 `;
33
34                 // activate drag and drop
35                 let dropArea = document.getElementById(parent_div);
36                 ;['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
37                         dropArea.addEventListener(eventName, upload_prevent_defaults, false)
38                 })
39                 ;["dragenter", "dragover"].forEach(eventName => {
40                         dropArea.addEventListener(eventName, upload_highlight, false)
41                 })
42                 ;['dragleave', 'drop'].forEach(eventName => {
43                         dropArea.addEventListener(eventName, upload_unhighlight, false)
44                 })
45                 dropArea.addEventListener('drop', upload_handle_drop, false);
46 }
47
48
49 // prevent drag and drop events from propagating up through the DOM
50 function upload_prevent_defaults(e) {
51         e.preventDefault();
52         e.stopPropagation();
53 }
54
55
56 function upload_handle_drop(e) {
57         let dt = e.dataTransfer;
58         let files = dt.files;
59         handle_upload_files(files);
60 }
61
62
63 function handle_upload_files(files) {
64         ([...files]).forEach(upload_file)
65 }
66
67
68 function upload_file(file) {
69         var url = '/ctdl/p/';
70         var xhr = new XMLHttpRequest();
71         var formData = new FormData();
72         xhr.open('POST', url, true);
73       
74         xhr.addEventListener('readystatechange', function(e) {
75                 if (xhr.readyState == 4 && xhr.status == 200) {
76                         // remove the "uploading in progress" message
77                         let li = document.getElementById("ctdl_uploading_" + uploads_in_progress.toString());
78                         li.parentNode.removeChild(li);
79                         uploads_in_progress -= 1;
80
81                         // The response body will be a JSON array of completed uploads.
82                         var j_response = JSON.parse(xhr.response);
83
84                         // Add these uploads to the displayed list
85                         j_response.forEach((item) => {
86                                 let new_upl = document.createElement("li");
87                                 new_upl.innerHTML = "Ref: " + item["ref"] + " , Filename: " + item["uploadfilename"] + " , Content-type: " + item["contenttype"] + " , Length: " + item["contentlength"];
88                                 document.getElementById("ctdl-upload_list").appendChild(new_upl);
89                         });
90
91                         // append it to the global list of uploads
92                         uploads.push(j_response);
93                         document.getElementById("num_attachments").innerHTML = uploads.length;
94                 }
95                 else if (xhr.readyState == 4 && xhr.status != 200) {
96                         // remove the "uploading in progress" message (there was an error, so just let it disappear)
97                         let li = document.getElementById("ctdl_uploading_" + uploads_in_progress.toString());
98                         li.parentNode.removeChild(li);
99                         uploads_in_progress -= 1;
100                 }
101         })
102  
103         formData.append('file', file);
104         xhr.send(formData);
105         uploads_in_progress += 1;
106
107         // Make an "uploading in progress" message appear in the uploads list!
108         progress = document.createElement("li");
109         progress.setAttribute("id", "ctdl_uploading_" + uploads_in_progress.toString());
110         progress.innerHTML = `<img src="/ctdl/s/images/dotcrawl.gif" /> ` + _("Processing dropped files...");
111         document.getElementById("ctdl-upload_list").appendChild(progress);
112 }
113
114
115 // called when the user drags a file into the upload area
116 function upload_highlight(e) {
117         let dropArea = document.getElementById("ctdl-upload");
118         dropArea.classList.add('highlight')
119
120         document.getElementById("ctdl-upload").style.display = "block";         /* also make it appear */
121 }
122
123
124 // called when the user is no longer dragging a file into the upload area
125 function upload_unhighlight(e) {
126         let dropArea = document.getElementById("ctdl-upload");
127         dropArea.classList.remove('highlight')
128 }
129
130
131 // Show or hide the attachments window in the composer
132 function show_or_hide_upload_window() {
133
134         if (document.getElementById("ctdl-upload").style.display == "block") {
135                 document.getElementById("ctdl-upload").style.display = "none";          /* turn it off */
136         }
137         else {
138                 document.getElementById("ctdl-upload").style.display = "block";         /* turn it on */
139         }
140 }
141
142
143 // Flush all uploaded files and close the window
144 function flush_uploads() {
145         document.getElementById('ctdl-upload').style.display='none';
146         // FIXME tell the server to delete the files
147         uploads=[];
148 }