]>
jfr.im git - uguu.git/blob - static/js/app.js
4 * @copyright Copyright (c) 2022 Go Johansson (nekunekus) <neku@pomf.se> <github.com/nokonoko>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 document
.addEventListener('DOMContentLoaded', function () {
22 * Sets up the elements inside file upload rows.
25 * @return {HTMLLIElement} row
27 function addRow(file
) {
28 var row
= document
.createElement('li');
30 var name
= document
.createElement('span');
31 name
.textContent
= file
.name
;
32 name
.className
= 'file-name';
34 var progressIndicator
= document
.createElement('span');
35 progressIndicator
.className
= 'progress-percent';
36 progressIndicator
.textContent
= '0%';
38 var progressBar
= document
.createElement('progress');
39 progressBar
.className
= 'file-progress';
40 progressBar
.setAttribute('max', '100');
41 progressBar
.setAttribute('value', '0');
43 row
.appendChild(name
);
44 row
.appendChild(progressBar
);
45 row
.appendChild(progressIndicator
);
47 document
.getElementById('upload-filelist').appendChild(row
);
52 * Updates the page while the file is being uploaded.
54 * @param {ProgressEvent} evt
56 function handleUploadProgress(evt
) {
59 var percentIndicator
= xhr
.percent
;
61 /* If we have amounts of work done/left that we can calculate with
62 (which, unless we're uploading dynamically resizing data, is always), calculate the percentage. */
63 if (evt
.lengthComputable
) {
64 var progressPercent
= Math
.floor((evt
.loaded
/ evt
.total
) * 100);
65 bar
.setAttribute('value', progressPercent
);
66 percentIndicator
.textContent
= progressPercent
+ '%';
71 * Complete the uploading process by checking the response status and, if the
72 * upload was successful, writing the URL(s) and creating the copy element(s)
75 * @param {ProgressEvent} evt
77 function handleUploadComplete(evt
) {
81 var percentIndicator
= xhr
.percent
;
83 percentIndicator
.style
.visibility
= 'hidden';
84 bar
.style
.visibility
= 'hidden';
86 row
.removeChild(percentIndicator
);
87 var respStatus
= xhr
.status
;
89 var url
= document
.createElement('span');
90 url
.className
= 'file-url';
93 var link
= document
.createElement('a');
94 if (respStatus
=== 200) {
95 var response
= JSON
.parse(xhr
.responseText
);
96 if (response
.success
) {
97 link
.textContent
= response
.files
[0].url
.replace(/.*?:\/\//g, '');
98 link
.href
= response
.files
[0].url
;
99 url
.appendChild(link
);
100 var copy
= document
.createElement('button');
101 copy
.className
= 'upload-clipboard-btn';
102 var glyph
= document
.createElement('img');
103 glyph
.src
= 'img/glyphicons-512-copy.png';
104 copy
.appendChild(glyph
);
105 url
.appendChild(copy
);
106 copy
.addEventListener("click", function (event
) {
107 /* Why create an element? The text needs to be on screen to be
108 selected and thus copied. The only text we have on-screen is the link
109 without the http[s]:// part. So, this creates an element with the
110 full link for a moment and then deletes it.
112 See the "Complex Example: Copy to clipboard without displaying
113 input" section at: https://stackoverflow.com/a/30810322 */
114 var element
= document
.createElement('a');
115 element
.textContent
= response
.files
[0].url
;
116 link
.appendChild(element
);
117 var range
= document
.createRange();
118 range
.selectNode(element
);
119 window
.getSelection().removeAllRanges();
120 window
.getSelection().addRange(range
);
121 document
.execCommand("copy");
122 link
.removeChild(element
);
125 bar
.innerHTML
= 'Error: ' + response
.description
;
127 } else if (respStatus
=== 413) {
128 link
.textContent
= 'File too big!';
129 url
.appendChild(link
);
131 var response
= JSON
.parse(xhr
.responseText
);
132 link
.textContent
= response
.description
;
133 url
.appendChild(link
);
138 * Updates the page while the file is being uploaded.
141 * @param {HTMLLIElement} row
143 function uploadFile(file
, row
) {
144 var bar
= row
.querySelector('.file-progress');
145 var percentIndicator
= row
.querySelector('.progress-percent');
146 var xhr
= new XMLHttpRequest();
147 xhr
.open('POST', 'upload.php');
151 xhr
['percent'] = percentIndicator
;
152 xhr
.upload
['bar'] = bar
;
153 xhr
.upload
['percent'] = percentIndicator
;
155 xhr
.addEventListener('load', handleUploadComplete
, false);
156 xhr
.upload
.onprogress
= handleUploadProgress
;
158 var form
= new FormData();
159 form
.append('files[]', file
);
164 * Prevents the browser for allowing the normal actions associated with an event.
165 * This is used by event handlers to allow custom functionality without
166 * having to worry about the other consequences of that action.
170 function stopDefaultEvent(evt
) {
171 evt
.stopPropagation();
172 evt
.preventDefault();
176 * Adds 1 to the state and changes the text.
178 * @param {Object} state
179 * @param {HTMLButtonElement} element
180 * @param {DragEvent} evt
182 function handleDrag(state
, element
, evt
) {
183 stopDefaultEvent(evt
);
184 if (state
.dragCount
== 1) {
185 element
.textContent
= 'Drop it here~';
187 state
.dragCount
+= 1;
191 * Subtracts 1 from the state and changes the text back.
193 * @param {Object} state
194 * @param {HTMLButtonElement} element
195 * @param {DragEvent} evt
197 function handleDragAway(state
, element
, evt
) {
198 stopDefaultEvent(evt
);
199 state
.dragCount
-= 1;
200 if (state
.dragCount
== 0) {
201 element
.textContent
= 'Select or drop file(s)';
206 * Prepares files for uploading after being added via drag-drop.
208 * @param {Object} state
209 * @param {HTMLButtonElement} element
210 * @param {DragEvent} evt
212 function handleDragDrop(state
, element
, evt
) {
213 stopDefaultEvent(evt
);
214 handleDragAway(state
, element
, evt
);
215 var len
= evt
.dataTransfer
.files
.length
;
216 for (var i
= 0; i
< len
; i
++) {
217 var file
= evt
.dataTransfer
.files
[i
];
218 var row
= addRow(file
);
219 uploadFile(file
, row
);
224 * Prepares the files to be uploaded when they're added to the <input> element.
226 * @param {InputEvent} evt
228 function uploadFiles(evt
) {
229 var len
= evt
.target
.files
.length
;
230 // For each file, make a row, and upload the file.
231 for (var i
= 0; i
< len
; i
++) {
232 var file
= evt
.target
.files
[i
];
233 var row
= addRow(file
);
234 uploadFile(file
, row
);
239 * Opens up a "Select files.." dialog window to allow users to select files to upload.
241 * @param {HTMLInputElement} target
242 * @param {InputEvent} evt
244 function selectFiles(target
, evt
) {
245 stopDefaultEvent(evt
);
249 /* Handles the pasting function */
250 window
.addEventListener("paste", e
=> {
251 var len
= e
.clipboardData
.files
.length
;
252 for (var i
= 0; i
< len
; i
++) {
253 var file
= e
.clipboardData
.files
[i
];
254 var row
= addRow(file
);
255 uploadFile(file
, row
);
260 /* Set-up the event handlers for the <button>, <input> and the window itself
261 and also set the "js" class on selector "#upload-form", presumably to
262 allow custom styles for clients running javascript. */
263 var state
= {dragCount: 0};
264 var uploadButton
= document
.getElementById('upload-btn');
265 window
.addEventListener('dragenter', handleDrag
.bind(this, state
, uploadButton
), false);
266 window
.addEventListener('dragleave', handleDragAway
.bind(this, state
, uploadButton
), false);
267 window
.addEventListener('drop', handleDragAway
.bind(this, state
, uploadButton
), false);
268 window
.addEventListener('dragover', stopDefaultEvent
, false);
271 var uploadInput
= document
.getElementById('upload-input');
272 uploadInput
.addEventListener('change', uploadFiles
);
273 uploadButton
.addEventListener('click', selectFiles
.bind(this, uploadInput
));
274 uploadButton
.addEventListener('drop', handleDragDrop
.bind(this, state
, uploadButton
), false);
275 document
.getElementById('upload-form').classList
.add('js');