]>
jfr.im git - uguu.git/blob - src/static/js/uguu.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
29 const row
= document
.createElement('li');
31 const name
= document
.createElement('span');
32 name
.textContent
= file
.name
;
33 name
.className
= 'file-name';
35 const progressIndicator
= document
.createElement('span');
36 progressIndicator
.className
= 'progress-percent';
37 progressIndicator
.textContent
= '0%';
39 const progressBar
= document
.createElement('progress');
40 progressBar
.className
= 'file-progress';
41 progressBar
.setAttribute('max', '100');
42 progressBar
.setAttribute('value', '0');
44 row
.appendChild(name
);
45 row
.appendChild(progressBar
);
46 row
.appendChild(progressIndicator
);
48 document
.getElementById('upload-filelist').appendChild(row
);
53 * Updates the page while the file is being uploaded.
55 * @param {ProgressEvent} evt
57 function handleUploadProgress(evt
)
61 let percentIndicator
= xhr
.percent
;
63 /* If we have amounts of work done/left that we can calculate with
64 (which, unless we're uploading dynamically resizing data, is always), calculate the percentage. */
65 if (evt
.lengthComputable
) {
66 let progressPercent
= Math
.floor((evt
.loaded
/ evt
.total
) * 100);
67 bar
.setAttribute('value', progressPercent
);
68 percentIndicator
.textContent
= progressPercent
+ '%';
73 * Complete the uploading process by checking the response status and, if the
74 * upload was successful, writing the URL(s) and creating the copy element(s)
77 * @param {ProgressEvent} evt
79 function handleUploadComplete(evt
)
84 let percentIndicator
= xhr
.percent
;
86 percentIndicator
.style
.visibility
= 'hidden';
87 bar
.style
.visibility
= 'hidden';
89 row
.removeChild(percentIndicator
);
90 let respStatus
= xhr
.status
;
92 let url
= document
.createElement('span');
93 url
.className
= 'file-url';
96 let link
= document
.createElement('a');
97 if (respStatus
=== 200) {
98 let response
= JSON
.parse(xhr
.responseText
);
99 if (response
.success
) {
100 link
.textContent
= response
.files
[0].url
.replace(/.*?:\/\//g, '');
101 link
.href
= response
.files
[0].url
;
102 url
.appendChild(link
);
103 const copy
= document
.createElement('button');
104 copy
.className
= 'upload-clipboard-btn';
105 const glyph
= document
.createElement('img');
106 glyph
.src
= 'img/glyphicons-512-copy.png';
107 copy
.appendChild(glyph
);
108 url
.appendChild(copy
);
109 copy
.addEventListener("click", function () {
110 /* Why create an element? The text needs to be on screen to be
111 selected and thus copied. The only text we have on-screen is the link
112 without the http[s]:// part. So, this creates an element with the
113 full link for a moment and then deletes it.
115 See the "Complex Example: Copy to clipboard without displaying
116 input" section at: https://stackoverflow.com/a/30810322 */
117 const element
= document
.createElement('a');
118 element
.textContent
= response
.files
[0].url
;
119 link
.appendChild(element
);
120 let range
= document
.createRange();
121 range
.selectNode(element
);
122 window
.getSelection().removeAllRanges();
123 window
.getSelection().addRange(range
);
124 document
.execCommand("copy");
125 link
.removeChild(element
);
128 bar
.innerHTML
= 'Error: ' + response
.description
;
130 } else if (respStatus
=== 413) {
131 link
.textContent
= 'File too big!';
132 url
.appendChild(link
);
134 let response
= JSON
.parse(xhr
.responseText
);
135 link
.textContent
= response
.description
;
136 url
.appendChild(link
);
141 * Updates the page while the file is being uploaded.
144 * @param {HTMLLIElement} row
146 function uploadFile(file
, row
)
148 let bar
= row
.querySelector('.file-progress');
149 let percentIndicator
= row
.querySelector('.progress-percent');
150 let xhr
= new XMLHttpRequest();
151 xhr
.open('POST', 'upload.php');
155 xhr
['percent'] = percentIndicator
;
156 xhr
.upload
['bar'] = bar
;
157 xhr
.upload
['percent'] = percentIndicator
;
159 xhr
.addEventListener('load', handleUploadComplete
, false);
160 xhr
.upload
.onprogress
= handleUploadProgress
;
162 let form
= new FormData();
163 form
.append('files[]', file
);
168 * Prevents the browser for allowing the normal actions associated with an event.
169 * This is used by event handlers to allow custom functionality without
170 * having to worry about the other consequences of that action.
174 function stopDefaultEvent(evt
)
176 evt
.stopPropagation();
177 evt
.preventDefault();
181 * Adds 1 to the state and changes the text.
183 * @param {Object} state
184 * @param {HTMLButtonElement} element
185 * @param {DragEvent} evt
187 function handleDrag(state
, element
, evt
)
189 stopDefaultEvent(evt
);
190 if (state
.dragCount
=== 1) {
191 element
.textContent
= 'Drop it here~';
193 state
.dragCount
+= 1;
197 * Subtracts 1 from the state and changes the text back.
199 * @param {Object} state
200 * @param {HTMLButtonElement} element
201 * @param {DragEvent} evt
203 function handleDragAway(state
, element
, evt
)
205 stopDefaultEvent(evt
);
206 state
.dragCount
-= 1;
207 if (state
.dragCount
=== 0) {
208 element
.textContent
= 'Select or drop file(s)';
213 * Prepares files for uploading after being added via drag-drop.
215 * @param {Object} state
216 * @param {HTMLButtonElement} element
217 * @param {DragEvent} evt
219 function handleDragDrop(state
, element
, evt
)
221 stopDefaultEvent(evt
);
222 handleDragAway(state
, element
, evt
);
223 let len
= evt
.dataTransfer
.files
.length
;
224 for (let i
= 0; i
< len
; i
++) {
225 let file
= evt
.dataTransfer
.files
[i
];
226 let row
= addRow(file
);
227 uploadFile(file
, row
);
232 * Prepares the files to be uploaded when they're added to the <input> element.
234 * @param {InputEvent} evt
236 function uploadFiles(evt
)
238 let len
= evt
.target
.files
.length
;
239 // For each file, make a row, and upload the file.
240 for (let i
= 0; i
< len
; i
++) {
241 let file
= evt
.target
.files
[i
];
242 let row
= addRow(file
);
243 uploadFile(file
, row
);
248 * Opens up a "Select files.." dialog window to allow users to select files to upload.
250 * @param {HTMLInputElement} target
251 * @param {InputEvent} evt
253 function selectFiles(target
, evt
)
255 stopDefaultEvent(evt
);
259 /* Handles the pasting function */
260 window
.addEventListener("paste", e
=> {
261 let len
= e
.clipboardData
.files
.length
;
262 for (let i
= 0; i
< len
; i
++) {
263 let file
= e
.clipboardData
.files
[i
];
264 let row
= addRow(file
);
265 uploadFile(file
, row
);
270 /* Set up the event handlers for the <button>, <input> and the window itself
271 and also set the "js" class on selector "#upload-form", presumably to
272 allow custom styles for clients running javascript. */
273 let state
= {dragCount: 0};
274 let uploadButton
= document
.getElementById('upload-btn');
275 window
.addEventListener('dragenter', handleDrag
.bind(this, state
, uploadButton
), false);
276 window
.addEventListener('dragleave', handleDragAway
.bind(this, state
, uploadButton
), false);
277 window
.addEventListener('drop', handleDragAway
.bind(this, state
, uploadButton
), false);
278 window
.addEventListener('dragover', stopDefaultEvent
, false);
281 let uploadInput
= document
.getElementById('upload-input');
282 uploadInput
.addEventListener('change', uploadFiles
);
283 uploadButton
.addEventListener('click', selectFiles
.bind(this, uploadInput
));
284 uploadButton
.addEventListener('drop', handleDragDrop
.bind(this, state
, uploadButton
), false);
285 document
.getElementById('upload-form').classList
.add('js');