]> jfr.im git - uguu.git/blame - static/js/app.js
unused code
[uguu.git] / static / js / app.js
CommitLineData
d8c46ff7
GJ
1/**
2 * Copyright (c) 2016 Luminarys <postmaster@gensok.io>
c036012e
GJ
3 *
4 * Copyright (c) 2021 Eric Johansson (Nekunekus) <neku@pomf.se>
d8c46ff7
GJ
5 *
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:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
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
22 * SOFTWARE.
23 */
24
c036012e 25 document.addEventListener('DOMContentLoaded', function() {
d8c46ff7
GJ
26 /**
27 * Sets up the elements inside file upload rows.
28 *
29 * @param {File} file
30 * @return {HTMLLIElement} row
31 */
32 function addRow(file) {
33 var row = document.createElement('li');
34
35 var name = document.createElement('span');
36 name.textContent = file.name;
37 name.className = 'file-name';
38
39 var progressIndicator = document.createElement('span');
40 progressIndicator.className = 'progress-percent';
41 progressIndicator.textContent = '0%';
42
43 var progressBar = document.createElement('progress');
44 progressBar.className = 'file-progress';
45 progressBar.setAttribute('max', '100');
46 progressBar.setAttribute('value', '0');
47
48 row.appendChild(name);
49 row.appendChild(progressBar);
50 row.appendChild(progressIndicator);
51
52 document.getElementById('upload-filelist').appendChild(row);
53 return row;
54 }
55
56 /**
57 * Updates the page while the file is being uploaded.
58 *
59 * @param {ProgressEvent} evt
60 */
61 function handleUploadProgress(evt) {
62 var xhr = evt.target;
63 var bar = xhr.bar;
64 var percentIndicator = xhr.percent;
65
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 + '%';
72 }
73 }
74
75 /**
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)
78 * for the files.
79 *
80 * @param {ProgressEvent} evt
81 */
82 function handleUploadComplete(evt) {
83 var xhr = evt.target;
84 var bar = xhr.bar;
85 var row = xhr.row;
86 var percentIndicator = xhr.percent;
87
88 percentIndicator.style.visibility = 'hidden';
89 bar.style.visibility = 'hidden';
90 row.removeChild(bar);
91 row.removeChild(percentIndicator);
92 var respStatus = xhr.status;
93
94 var url = document.createElement('span');
95 url.className = 'file-url';
96 row.appendChild(url);
97
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.
116
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);
128 });
129 } else {
130 bar.innerHTML = 'Error: ' + response.description;
131 }
132 } else if (respStatus === 413) {
133 link.textContent = 'File too big!';
134 url.appendChild(link);
4b7727f7 135 } else if (respStatus === 415) {
95b5e1a7 136 link.textContent = 'Filetype not allowed!';
4b7727f7 137 url.appendChild(link);
d8c46ff7 138 } else {
95b5e1a7 139 link.textContent = 'Server error!';
d8c46ff7
GJ
140 url.appendChild(link);
141 }
142 }
143
144 /**
145 * Updates the page while the file is being uploaded.
146 *
147 * @param {File} file
148 * @param {HTMLLIElement} row
149 */
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');
155
156 xhr['row'] = row;
157 xhr['bar'] = bar;
158 xhr['percent'] = percentIndicator;
159 xhr.upload['bar'] = bar;
160 xhr.upload['percent'] = percentIndicator;
161
162 xhr.addEventListener('load', handleUploadComplete, false);
163 xhr.upload.onprogress = handleUploadProgress;
164
165 var form = new FormData();
166 form.append('files[]', file);
167 xhr.send(form);
168 }
169
170 /**
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.
174 *
175 * @param {Event} evt
176 */
177 function stopDefaultEvent(evt) {
178 evt.stopPropagation();
179 evt.preventDefault();
180 }
181
182 /**
183 * Adds 1 to the state and changes the text.
184 *
185 * @param {Object} state
186 * @param {HTMLButtonElement} element
187 * @param {DragEvent} evt
188 */
189 function handleDrag(state, element, evt) {
190 stopDefaultEvent(evt);
191 if (state.dragCount == 1) {
192 element.textContent = 'Drop it here~';
193 }
194 state.dragCount += 1;
195 }
196
197 /**
198 * Subtracts 1 from the state and changes the text back.
199 *
200 * @param {Object} state
201 * @param {HTMLButtonElement} element
202 * @param {DragEvent} evt
203 */
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)';
209 }
210 }
211
212 /**
213 * Prepares files for uploading after being added via drag-drop.
214 *
215 * @param {Object} state
216 * @param {HTMLButtonElement} element
217 * @param {DragEvent} evt
218 */
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);
227 }
228 }
229
230 /**
231 * Prepares the files to be uploaded when they're added to the <input> element.
232 *
233 * @param {InputEvent} evt
234 */
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);
242 }
243 }
244
245 /**
246 * Opens up a "Select files.." dialog window to allow users to select files to upload.
247 *
248 * @param {HTMLInputElement} target
249 * @param {InputEvent} evt
250 */
251 function selectFiles(target, evt) {
252 stopDefaultEvent(evt);
253 target.click();
254 }
255
c036012e
GJ
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);
263 }
264 });
265
266
d8c46ff7
GJ
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);
276
c036012e 277
d8c46ff7
GJ
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');
283});