]>
jfr.im git - uguu.git/blob - static/js/app.js
2 * Copyright (c) 2016 Luminarys <postmaster@gensok.io>
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 document
.addEventListener('DOMContentLoaded', function() {
25 * Sets up the elements inside file upload rows.
28 * @return {HTMLLIElement} row
30 function addRow(file
) {
31 var row
= document
.createElement('li');
33 var name
= document
.createElement('span');
34 name
.textContent
= file
.name
;
35 name
.className
= 'file-name';
37 var progressIndicator
= document
.createElement('span');
38 progressIndicator
.className
= 'progress-percent';
39 progressIndicator
.textContent
= '0%';
41 var progressBar
= document
.createElement('progress');
42 progressBar
.className
= 'file-progress';
43 progressBar
.setAttribute('max', '100');
44 progressBar
.setAttribute('value', '0');
46 row
.appendChild(name
);
47 row
.appendChild(progressBar
);
48 row
.appendChild(progressIndicator
);
50 document
.getElementById('upload-filelist').appendChild(row
);
55 * Updates the page while the file is being uploaded.
57 * @param {ProgressEvent} evt
59 function handleUploadProgress(evt
) {
62 var percentIndicator
= xhr
.percent
;
64 /* If we have amounts of work done/left that we can calculate with
65 (which, unless we're uploading dynamically resizing data, is always), calculate the percentage. */
66 if (evt
.lengthComputable
) {
67 var progressPercent
= Math
.floor((evt
.loaded
/ evt
.total
) * 100);
68 bar
.setAttribute('value', progressPercent
);
69 percentIndicator
.textContent
= progressPercent
+ '%';
74 * Complete the uploading process by checking the response status and, if the
75 * upload was successful, writing the URL(s) and creating the copy element(s)
78 * @param {ProgressEvent} evt
80 function handleUploadComplete(evt
) {
84 var percentIndicator
= xhr
.percent
;
86 percentIndicator
.style
.visibility
= 'hidden';
87 bar
.style
.visibility
= 'hidden';
89 row
.removeChild(percentIndicator
);
90 var respStatus
= xhr
.status
;
92 var url
= document
.createElement('span');
93 url
.className
= 'file-url';
96 var link
= document
.createElement('a');
97 if (respStatus
=== 200) {
98 var 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 var copy
= document
.createElement('button');
104 copy
.className
= 'upload-clipboard-btn';
105 var 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(event
) {
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 var element
= document
.createElement('a');
118 element
.textContent
= response
.files
[0].url
;
119 link
.appendChild(element
);
120 var 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
);
133 } else if (respStatus
=== 415) {
134 link
.textContent
= 'Filetype not allowed!';
135 url
.appendChild(link
);
137 link
.textContent
= 'Server error!';
138 url
.appendChild(link
);
143 * Updates the page while the file is being uploaded.
146 * @param {HTMLLIElement} row
148 function uploadFile(file
, row
) {
149 var bar
= row
.querySelector('.file-progress');
150 var percentIndicator
= row
.querySelector('.progress-percent');
151 var xhr
= new XMLHttpRequest();
152 xhr
.open('POST', 'upload.php');
156 xhr
['percent'] = percentIndicator
;
157 xhr
.upload
['bar'] = bar
;
158 xhr
.upload
['percent'] = percentIndicator
;
160 xhr
.addEventListener('load', handleUploadComplete
, false);
161 xhr
.upload
.onprogress
= handleUploadProgress
;
163 var form
= new FormData();
164 form
.append('files[]', file
);
169 * Prevents the browser for allowing the normal actions associated with an event.
170 * This is used by event handlers to allow custom functionality without
171 * having to worry about the other consequences of that action.
175 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
) {
188 stopDefaultEvent(evt
);
189 if (state
.dragCount
== 1) {
190 element
.textContent
= 'Drop it here~';
192 state
.dragCount
+= 1;
196 * Subtracts 1 from the state and changes the text back.
198 * @param {Object} state
199 * @param {HTMLButtonElement} element
200 * @param {DragEvent} evt
202 function handleDragAway(state
, element
, evt
) {
203 stopDefaultEvent(evt
);
204 state
.dragCount
-= 1;
205 if (state
.dragCount
== 0) {
206 element
.textContent
= 'Select or drop file(s)';
211 * Prepares files for uploading after being added via drag-drop.
213 * @param {Object} state
214 * @param {HTMLButtonElement} element
215 * @param {DragEvent} evt
217 function handleDragDrop(state
, element
, evt
) {
218 stopDefaultEvent(evt
);
219 handleDragAway(state
, element
, evt
);
220 var len
= evt
.dataTransfer
.files
.length
;
221 for (var i
= 0; i
< len
; i
++) {
222 var file
= evt
.dataTransfer
.files
[i
];
223 var row
= addRow(file
);
224 uploadFile(file
, row
);
229 * Prepares the files to be uploaded when they're added to the <input> element.
231 * @param {InputEvent} evt
233 function uploadFiles(evt
) {
234 var len
= evt
.target
.files
.length
;
235 // For each file, make a row, and upload the file.
236 for (var i
= 0; i
< len
; i
++) {
237 var file
= evt
.target
.files
[i
];
238 var row
= addRow(file
);
239 uploadFile(file
, row
);
244 * Opens up a "Select files.." dialog window to allow users to select files to upload.
246 * @param {HTMLInputElement} target
247 * @param {InputEvent} evt
249 function selectFiles(target
, evt
) {
250 stopDefaultEvent(evt
);
254 /* Set-up the event handlers for the <button>, <input> and the window itself
255 and also set the "js" class on selector "#upload-form", presumably to
256 allow custom styles for clients running javascript. */
257 var state
= { dragCount: 0 };
258 var uploadButton
= document
.getElementById('upload-btn');
259 window
.addEventListener('dragenter', handleDrag
.bind(this, state
, uploadButton
), false);
260 window
.addEventListener('dragleave', handleDragAway
.bind(this, state
, uploadButton
), false);
261 window
.addEventListener('drop', handleDragAway
.bind(this, state
, uploadButton
), false);
262 window
.addEventListener('dragover', stopDefaultEvent
, false);
264 var uploadInput
= document
.getElementById('upload-input');
265 uploadInput
.addEventListener('change', uploadFiles
);
266 uploadButton
.addEventListener('click', selectFiles
.bind(this, uploadInput
));
267 uploadButton
.addEventListener('drop', handleDragDrop
.bind(this, state
, uploadButton
), false);
268 document
.getElementById('upload-form').classList
.add('js');