]>
jfr.im git - uguu.git/blob - static/js/app.js
2 * Copyright (c) 2016 Luminarys <postmaster@gensok.io>
4 * Copyright (c) 2021 Eric Johansson (Nekunekus) <neku@pomf.se>
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 document
.addEventListener('DOMContentLoaded', function() {
27 * Sets up the elements inside file upload rows.
30 * @return {HTMLLIElement} row
32 function addRow(file
) {
33 var row
= document
.createElement('li');
35 var name
= document
.createElement('span');
36 name
.textContent
= file
.name
;
37 name
.className
= 'file-name';
39 var progressIndicator
= document
.createElement('span');
40 progressIndicator
.className
= 'progress-percent';
41 progressIndicator
.textContent
= '0%';
43 var progressBar
= document
.createElement('progress');
44 progressBar
.className
= 'file-progress';
45 progressBar
.setAttribute('max', '100');
46 progressBar
.setAttribute('value', '0');
48 row
.appendChild(name
);
49 row
.appendChild(progressBar
);
50 row
.appendChild(progressIndicator
);
52 document
.getElementById('upload-filelist').appendChild(row
);
57 * Updates the page while the file is being uploaded.
59 * @param {ProgressEvent} evt
61 function handleUploadProgress(evt
) {
64 var percentIndicator
= xhr
.percent
;
66 /* If we have amounts of work done/left that we can calculate with
67 (which, unless we're uploading dynamically resizing data, is always), calculate the percentage. */
68 if (evt
.lengthComputable
) {
69 var progressPercent
= Math
.floor((evt
.loaded
/ evt
.total
) * 100);
70 bar
.setAttribute('value', progressPercent
);
71 percentIndicator
.textContent
= progressPercent
+ '%';
76 * Complete the uploading process by checking the response status and, if the
77 * upload was successful, writing the URL(s) and creating the copy element(s)
80 * @param {ProgressEvent} evt
82 function handleUploadComplete(evt
) {
86 var percentIndicator
= xhr
.percent
;
88 percentIndicator
.style
.visibility
= 'hidden';
89 bar
.style
.visibility
= 'hidden';
91 row
.removeChild(percentIndicator
);
92 var respStatus
= xhr
.status
;
94 var url
= document
.createElement('span');
95 url
.className
= 'file-url';
98 var link
= document
.createElement('a');
99 if (respStatus
=== 200) {
100 var response
= JSON
.parse(xhr
.responseText
);
101 if (response
.success
) {
102 link
.textContent
= response
.files
[0].url
.replace(/.*?:\/\//g, '');
103 link
.href
= response
.files
[0].url
;
104 url
.appendChild(link
);
105 var copy
= document
.createElement('button');
106 copy
.className
= 'upload-clipboard-btn';
107 var glyph
= document
.createElement('img');
108 glyph
.src
= 'img/glyphicons-512-copy.png';
109 copy
.appendChild(glyph
);
110 url
.appendChild(copy
);
111 copy
.addEventListener("click", function(event
) {
112 /* Why create an element? The text needs to be on screen to be
113 selected and thus copied. The only text we have on-screen is the link
114 without the http[s]:// part. So, this creates an element with the
115 full link for a moment and then deletes it.
117 See the "Complex Example: Copy to clipboard without displaying
118 input" section at: https://stackoverflow.com/a/30810322 */
119 var element
= document
.createElement('a');
120 element
.textContent
= response
.files
[0].url
;
121 link
.appendChild(element
);
122 var range
= document
.createRange();
123 range
.selectNode(element
);
124 window
.getSelection().removeAllRanges();
125 window
.getSelection().addRange(range
);
126 document
.execCommand("copy");
127 link
.removeChild(element
);
130 bar
.innerHTML
= 'Error: ' + response
.description
;
132 } else if (respStatus
=== 413) {
133 link
.textContent
= 'File too big!';
134 url
.appendChild(link
);
135 } else if (respStatus
=== 415) {
136 link
.textContent
= 'Filetype not allowed!';
137 url
.appendChild(link
);
139 link
.textContent
= 'Server error!';
140 url
.appendChild(link
);
145 * Updates the page while the file is being uploaded.
148 * @param {HTMLLIElement} row
150 function uploadFile(file
, row
) {
151 var bar
= row
.querySelector('.file-progress');
152 var percentIndicator
= row
.querySelector('.progress-percent');
153 var xhr
= new XMLHttpRequest();
154 xhr
.open('POST', 'upload.php');
158 xhr
['percent'] = percentIndicator
;
159 xhr
.upload
['bar'] = bar
;
160 xhr
.upload
['percent'] = percentIndicator
;
162 xhr
.addEventListener('load', handleUploadComplete
, false);
163 xhr
.upload
.onprogress
= handleUploadProgress
;
165 var form
= new FormData();
166 form
.append('files[]', file
);
171 * Prevents the browser for allowing the normal actions associated with an event.
172 * This is used by event handlers to allow custom functionality without
173 * having to worry about the other consequences of that action.
177 function stopDefaultEvent(evt
) {
178 evt
.stopPropagation();
179 evt
.preventDefault();
183 * Adds 1 to the state and changes the text.
185 * @param {Object} state
186 * @param {HTMLButtonElement} element
187 * @param {DragEvent} evt
189 function handleDrag(state
, element
, evt
) {
190 stopDefaultEvent(evt
);
191 if (state
.dragCount
== 1) {
192 element
.textContent
= 'Drop it here~';
194 state
.dragCount
+= 1;
198 * Subtracts 1 from the state and changes the text back.
200 * @param {Object} state
201 * @param {HTMLButtonElement} element
202 * @param {DragEvent} evt
204 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
) {
220 stopDefaultEvent(evt
);
221 handleDragAway(state
, element
, evt
);
222 var len
= evt
.dataTransfer
.files
.length
;
223 for (var i
= 0; i
< len
; i
++) {
224 var file
= evt
.dataTransfer
.files
[i
];
225 var row
= addRow(file
);
226 uploadFile(file
, row
);
231 * Prepares the files to be uploaded when they're added to the <input> element.
233 * @param {InputEvent} evt
235 function uploadFiles(evt
) {
236 var len
= evt
.target
.files
.length
;
237 // For each file, make a row, and upload the file.
238 for (var i
= 0; i
< len
; i
++) {
239 var file
= evt
.target
.files
[i
];
240 var row
= addRow(file
);
241 uploadFile(file
, row
);
246 * Opens up a "Select files.." dialog window to allow users to select files to upload.
248 * @param {HTMLInputElement} target
249 * @param {InputEvent} evt
251 function selectFiles(target
, evt
) {
252 stopDefaultEvent(evt
);
256 /* Handles the pasting function */
257 window
.addEventListener("paste", e
=>{
258 var len
= e
.clipboardData
.files
.length
;
259 for (var i
= 0; i
< len
; i
++) {
260 var file
= e
.clipboardData
.files
[i
];
261 var row
= addRow(file
);
262 uploadFile(file
, row
);
267 /* Set-up the event handlers for the <button>, <input> and the window itself
268 and also set the "js" class on selector "#upload-form", presumably to
269 allow custom styles for clients running javascript. */
270 var state
= { dragCount: 0 };
271 var uploadButton
= document
.getElementById('upload-btn');
272 window
.addEventListener('dragenter', handleDrag
.bind(this, state
, uploadButton
), false);
273 window
.addEventListener('dragleave', handleDragAway
.bind(this, state
, uploadButton
), false);
274 window
.addEventListener('drop', handleDragAway
.bind(this, state
, uploadButton
), false);
275 window
.addEventListener('dragover', stopDefaultEvent
, false);
278 var uploadInput
= document
.getElementById('upload-input');
279 uploadInput
.addEventListener('change', uploadFiles
);
280 uploadButton
.addEventListener('click', selectFiles
.bind(this, uploadInput
));
281 uploadButton
.addEventListener('drop', handleDragDrop
.bind(this, state
, uploadButton
), false);
282 document
.getElementById('upload-form').classList
.add('js');