]>
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
);
134 link
.textContent
= 'Server error!';
135 url
.appendChild(link
);
140 * Updates the page while the file is being uploaded.
143 * @param {HTMLLIElement} row
145 function uploadFile(file
, row
) {
146 var bar
= row
.querySelector('.file-progress');
147 var percentIndicator
= row
.querySelector('.progress-percent');
148 var xhr
= new XMLHttpRequest();
149 xhr
.open('POST', 'upload.php');
153 xhr
['percent'] = percentIndicator
;
154 xhr
.upload
['bar'] = bar
;
155 xhr
.upload
['percent'] = percentIndicator
;
157 xhr
.addEventListener('load', handleUploadComplete
, false);
158 xhr
.upload
.onprogress
= handleUploadProgress
;
160 var form
= new FormData();
161 form
.append('files[]', file
);
166 * Prevents the browser for allowing the normal actions associated with an event.
167 * This is used by event handlers to allow custom functionality without
168 * having to worry about the other consequences of that action.
172 function stopDefaultEvent(evt
) {
173 evt
.stopPropagation();
174 evt
.preventDefault();
178 * Adds 1 to the state and changes the text.
180 * @param {Object} state
181 * @param {HTMLButtonElement} element
182 * @param {DragEvent} evt
184 function handleDrag(state
, element
, evt
) {
185 stopDefaultEvent(evt
);
186 if (state
.dragCount
== 1) {
187 element
.textContent
= 'Drop it here~';
189 state
.dragCount
+= 1;
193 * Subtracts 1 from the state and changes the text back.
195 * @param {Object} state
196 * @param {HTMLButtonElement} element
197 * @param {DragEvent} evt
199 function handleDragAway(state
, element
, evt
) {
200 stopDefaultEvent(evt
);
201 state
.dragCount
-= 1;
202 if (state
.dragCount
== 0) {
203 element
.textContent
= 'Select or drop file(s)';
208 * Prepares files for uploading after being added via drag-drop.
210 * @param {Object} state
211 * @param {HTMLButtonElement} element
212 * @param {DragEvent} evt
214 function handleDragDrop(state
, element
, evt
) {
215 stopDefaultEvent(evt
);
216 handleDragAway(state
, element
, evt
);
217 var len
= evt
.dataTransfer
.files
.length
;
218 for (var i
= 0; i
< len
; i
++) {
219 var file
= evt
.dataTransfer
.files
[i
];
220 var row
= addRow(file
);
221 uploadFile(file
, row
);
226 * Prepares the files to be uploaded when they're added to the <input> element.
228 * @param {InputEvent} evt
230 function uploadFiles(evt
) {
231 var len
= evt
.target
.files
.length
;
232 // For each file, make a row, and upload the file.
233 for (var i
= 0; i
< len
; i
++) {
234 var file
= evt
.target
.files
[i
];
235 var row
= addRow(file
);
236 uploadFile(file
, row
);
241 * Opens up a "Select files.." dialog window to allow users to select files to upload.
243 * @param {HTMLInputElement} target
244 * @param {InputEvent} evt
246 function selectFiles(target
, evt
) {
247 stopDefaultEvent(evt
);
251 /* Set-up the event handlers for the <button>, <input> and the window itself
252 and also set the "js" class on selector "#upload-form", presumably to
253 allow custom styles for clients running javascript. */
254 var state
= { dragCount: 0 };
255 var uploadButton
= document
.getElementById('upload-btn');
256 window
.addEventListener('dragenter', handleDrag
.bind(this, state
, uploadButton
), false);
257 window
.addEventListener('dragleave', handleDragAway
.bind(this, state
, uploadButton
), false);
258 window
.addEventListener('drop', handleDragAway
.bind(this, state
, uploadButton
), false);
259 window
.addEventListener('dragover', stopDefaultEvent
, false);
261 var uploadInput
= document
.getElementById('upload-input');
262 uploadInput
.addEventListener('change', uploadFiles
);
263 uploadButton
.addEventListener('click', selectFiles
.bind(this, uploadInput
));
264 uploadButton
.addEventListener('drop', handleDragDrop
.bind(this, state
, uploadButton
), false);
265 document
.getElementById('upload-form').classList
.add('js');