]> git.p6c8.net - jirafeau.git/blob - lib/functions.js.php
79d7c952dfe549420495c006b4f0a1cdf1520c86
[jirafeau.git] / lib / functions.js.php
1 <?php
2 /*
3 * Jirafeau, your web file repository
4 * Copyright (C) 2015 Jerome Jutteau <j.jutteau@gmail.com>
5 * Copyright (C) 2015 Nicola Spanti (RyDroid) <dev@nicola-spanti.info>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21 header('Content-Type: text/javascript');
22
23 define('JIRAFEAU_ROOT', dirname(__FILE__) . '/../');
24
25 require(JIRAFEAU_ROOT . 'lib/settings.php');
26 require(JIRAFEAU_ROOT . 'lib/functions.php');
27 require(JIRAFEAU_ROOT . 'lib/lang.php');
28 ?>
29 var web_root = "<?php echo $cfg['web_root']; ?>";
30
31 function translate (expr)
32 {
33 var lang_array = <?php echo json_lang_generator() ?>;
34 if (lang_array.hasOwnProperty(expr))
35 return lang_array[expr];
36 return expr;
37 }
38
39 function isEmpty(str) {
40 return (!str || 0 === str.length);
41 }
42
43 // Extend date object with format method
44 Date.prototype.format = function(format) {
45 format = format || 'YYYY-MM-DD hh:mm';
46
47 var zeropad = function(number, length) {
48 number = number.toString();
49 length = length || 2;
50 while(number.length < length)
51 number = '0' + number;
52 return number;
53 },
54 formats = {
55 YYYY: this.getFullYear(),
56 MM: zeropad(this.getMonth() + 1),
57 DD: zeropad(this.getDate()),
58 hh: zeropad(this.getHours()),
59 mm: zeropad(this.getMinutes()),
60 O: (function() {
61 localDate = new Date;
62 sign = (localDate.getTimezoneOffset() > 0) ? '-' : '+';
63 offset = Math.abs(localDate.getTimezoneOffset());
64 hours = zeropad(Math.floor(offset / 60));
65 minutes = zeropad(offset % 60);
66 return sign + hours + ":" + minutes;
67 })()
68 },
69 pattern = '(' + Object.keys(formats).join(')|(') + ')';
70
71 return format.replace(new RegExp(pattern, 'g'), function(match) {
72 return formats[match];
73 });
74 };
75
76 function dateFromUtcString(datestring) {
77 // matches »YYYY-MM-DD hh:mm«
78 var m = datestring.match(/(\d+)-(\d+)-(\d+)\s+(\d+):(\d+)/);
79 return new Date(Date.UTC(+m[1], +m[2] - 1, +m[3], +m[4], +m[5], 0));
80 }
81
82 function dateFromUtcTimestamp(datetimestamp) {
83 return new Date(parseInt(datetimestamp) * 1000)
84 }
85
86 function dateToUtcString(datelocal) {
87 return new Date(
88 datelocal.getUTCFullYear(),
89 datelocal.getUTCMonth(),
90 datelocal.getUTCDate(),
91 datelocal.getUTCHours(),
92 datelocal.getUTCMinutes(),
93 datelocal.getUTCSeconds()
94 ).format();
95 }
96
97 function dateToUtcTimestamp(datelocal) {
98 return (Date.UTC(
99 datelocal.getUTCFullYear(),
100 datelocal.getUTCMonth(),
101 datelocal.getUTCDate(),
102 datelocal.getUTCHours(),
103 datelocal.getUTCMinutes(),
104 datelocal.getUTCSeconds()
105 ) / 1000);
106 }
107
108 function convertAllDatetimeFields() {
109 datefields = document.getElementsByClassName('datetime')
110 for(var i=0; i<datefields.length; i++) {
111 dateUTC = datefields[i].getAttribute('data-datetime');
112 datefields[i].setAttribute('title', dateUTC + ' (GMT)');
113 datefields[i].innerHTML = dateFromUtcString(dateUTC).format('YYYY-MM-DD hh:mm (GMT O)');
114 }
115 }
116
117 function show_link (reference, delete_code, crypt_key, date)
118 {
119 // Upload finished
120 document.getElementById('uploading').style.display = 'none';
121 document.getElementById('upload').style.display = 'none';
122 document.getElementById('upload_finished').style.display = '';
123 document.title = "100% - <?php echo empty($cfg['title']) ? 'Jirafeau' : $cfg['title']; ?>";
124
125 // Download page
126 var download_link_href = 'f.php?h=' + reference;
127 if (crypt_key.length > 0)
128 {
129 download_link_href += '&k=' + crypt_key;
130 }
131 if (!!document.getElementById('upload_finished_download_page'))
132 {
133 document.getElementById('upload_link').href = download_link_href;
134 document.getElementById('upload_link_text').innerHTML = web_root + download_link_href;
135 }
136
137 // Email link
138 var filename = document.getElementById('file_select').files[0].name;
139 var b = encodeURIComponent("Download file \"" + filename + "\":") + "%0D";
140 b += encodeURIComponent(web_root + download_link_href) + "%0D";
141 if (false == isEmpty(date))
142 {
143 b += "%0D" + encodeURIComponent("This file will be available until " + date.format('YYYY-MM-DD hh:mm (GMT O)')) + "%0D";
144 document.getElementById('upload_link_email').href = "mailto:?body=" + b + "&subject=" + encodeURIComponent(filename);
145 }
146
147 // Delete link
148 var delete_link_href = 'f.php?h=' + reference + '&d=' + delete_code;
149 document.getElementById('delete_link').href = delete_link_href;
150 document.getElementById('delete_link_text').innerHTML = web_root + delete_link_href;
151
152 // Validity date
153 if (isEmpty(date))
154 {
155 document.getElementById('date').style.display = 'none';
156 }
157 else {
158 document.getElementById('date').innerHTML = '<span class="datetime" title="'
159 + dateToUtcString(date) + ' (GMT)">'
160 + date.format('YYYY-MM-DD hh:mm (GMT O)')
161 + '</span>';
162 document.getElementById('date').style.display = '';
163 }
164
165 // Preview link (if allowed)
166 if (!!document.getElementById('preview_link'))
167 {
168 document.getElementById('upload_finished_preview').style.display = 'none';
169 var preview_link_href = 'f.php?h=' + reference + '&p=1';
170 if (crypt_key.length > 0)
171 {
172 preview_link_href += '&k=' + crypt_key;
173 }
174
175 // Test if content can be previewed
176 type = document.getElementById('file_select').files[0].type;
177 if (type.indexOf("image") > -1 ||
178 type.indexOf("audio") > -1 ||
179 type.indexOf("text") > -1 ||
180 type.indexOf("video") > -1)
181 {
182 document.getElementById('preview_link').href = preview_link_href;
183 document.getElementById('preview_link_text').innerHTML = web_root + preview_link_href;
184 document.getElementById('upload_finished_preview').style.display = '';
185 }
186 }
187
188 // Direct download link
189 var direct_download_link_href = 'f.php?h=' + reference + '&d=1';
190 if (crypt_key.length > 0)
191 {
192 direct_download_link_href += '&k=' + crypt_key;
193 }
194 document.getElementById('direct_link').href = direct_download_link_href;
195 document.getElementById('direct_link_text').innerHTML = web_root + direct_download_link_href;
196
197 // Hide preview and direct download link if password is set
198 if (document.getElementById('input_key').value.length > 0)
199 {
200 if (!!document.getElementById('preview_link'))
201 document.getElementById('upload_finished_preview').style.display = 'none';
202 document.getElementById('upload_direct_download').style.display = 'none';
203 }
204 }
205
206 function show_upload_progression (percentage, speed, time_left)
207 {
208 document.getElementById('uploaded_percentage').innerHTML = percentage;
209 document.getElementById('uploaded_speed').innerHTML = speed;
210 document.getElementById('uploaded_time').innerHTML = time_left;
211 document.title = percentage + " - <?php echo empty($cfg['title']) ? 'Jirafeau' : $cfg['title']; ?>";
212 }
213
214 function hide_upload_progression ()
215 {
216 document.getElementById('uploaded_percentage').style.display = 'none';
217 document.getElementById('uploaded_speed').style.display = 'none';
218 document.getElementById('uploaded_time').style.display = 'none';
219 document.title = "<?php echo empty($cfg['title']) ? 'Jirafeau' : $cfg['title']; ?>";
220 }
221
222 function upload_progress (e)
223 {
224 if (e == undefined || e == null || !e.lengthComputable)
225 return;
226
227 // Init time estimation if needed
228 if (upload_time_estimation_total_size == 0)
229 upload_time_estimation_total_size = e.total;
230
231 // Compute percentage
232 var p = Math.round (e.loaded * 100 / e.total);
233 var p_str = ' ';
234 if (p != 100)
235 p_str = p.toString() + '%';
236 // Update estimation speed
237 upload_time_estimation_add(e.loaded);
238 // Get speed string
239 var speed_str = upload_time_estimation_speed_string();
240 speed_str = upload_speed_refresh_limiter(speed_str);
241 // Get time string
242 var time_str = chrono_update(upload_time_estimation_time());
243
244 show_upload_progression (p_str, speed_str, time_str);
245 }
246
247 function control_selected_file_size(max_size, error_str)
248 {
249 f_size = document.getElementById('file_select').files[0].size;
250 if (max_size > 0 && f_size > max_size * 1024 * 1024)
251 {
252 pop_failure(error_str);
253 document.getElementById('send').style.display = 'none';
254 }
255 else
256 {
257 // add class to restyle upload form in next step
258 document.getElementById('upload').setAttribute('class', 'file-selected');
259 // display options
260 document.getElementById('options').style.display = 'block';
261 document.getElementById('send').style.display = 'block';
262 document.getElementById('error_pop').style.display = 'none';
263 document.getElementById('send').focus();
264 }
265 }
266
267 function pop_failure (e)
268 {
269 var text = "An error occured";
270 if (typeof e !== 'undefined')
271 text = e;
272 text = "<p>" + text + "</p>";
273 document.getElementById('error_pop').innerHTML = e;
274
275 document.getElementById('uploading').style.display = 'none';
276 document.getElementById('error_pop').style.display = '';
277 document.getElementById('upload').style.display = '';
278 document.getElementById('send').style.display = '';
279 }
280
281 function add_time_string_to_date(d, time)
282 {
283 if(typeof(d) != 'object' || !(d instanceof Date))
284 {
285 return false;
286 }
287
288 if (time == 'minute')
289 {
290 d.setSeconds (d.getSeconds() + 60);
291 return true;
292 }
293 if (time == 'hour')
294 {
295 d.setSeconds (d.getSeconds() + 3600);
296 return true;
297 }
298 if (time == 'day')
299 {
300 d.setSeconds (d.getSeconds() + 86400);
301 return true;
302 }
303 if (time == 'week')
304 {
305 d.setSeconds (d.getSeconds() + 604800);
306 return true;
307 }
308 if (time == 'month')
309 {
310 d.setSeconds (d.getSeconds() + 2419200);
311 return true;
312 }
313 if (time == 'quarter')
314 {
315 d.setSeconds (d.getSeconds() + 7257600);
316 return true;
317 }
318 if (time == 'year')
319 {
320 d.setSeconds (d.getSeconds() + 29030400);
321 return true;
322 }
323 return false;
324 }
325
326 function classic_upload (file, time, password, one_time, upload_password)
327 {
328 // Delay time estimation init as we can't have file size
329 upload_time_estimation_init(0);
330
331 var req = new XMLHttpRequest ();
332 req.upload.addEventListener ("progress", upload_progress, false);
333 req.addEventListener ("error", pop_failure, false);
334 req.addEventListener ("abort", pop_failure, false);
335 req.onreadystatechange = function ()
336 {
337 if (req.readyState == 4 && req.status == 200)
338 {
339 var res = req.responseText;
340
341 // if response starts with "Error" then show a failure
342 if (/^Error/.test(res))
343 {
344 pop_failure (res);
345 return;
346 }
347
348 res = res.split ("\n");
349 var expiryDate = '';
350 if (time != 'none')
351 {
352 // convert time (local time + selected expiry date)
353 var localDatetime = new Date();
354 if(!add_time_string_to_date(localDatetime, time))
355 {
356 pop_failure ('Error: Date can not be parsed');
357 return;
358 }
359 expiryDate = localDatetime;
360 }
361
362 show_link (res[0], res[1], res[2], expiryDate);
363 }
364 }
365 req.open ("POST", 'script.php' , true);
366
367 var form = new FormData();
368 form.append ("file", file);
369 if (time)
370 form.append ("time", time);
371 if (password)
372 form.append ("key", password);
373 if (one_time)
374 form.append ("one_time_download", '1');
375 if (upload_password.length > 0)
376 form.append ("upload_password", upload_password);
377
378 req.send (form);
379 }
380
381 function check_html5_file_api ()
382 {
383 return window.File && window.FileReader && window.FileList && window.Blob;
384 }
385
386 var async_global_transfered = 0;
387 var async_global_file;
388 var async_global_ref = '';
389 var async_global_max_size = 0;
390 var async_global_time;
391 var async_global_transfering = 0;
392
393 function async_upload_start (max_size, file, time, password, one_time, upload_password)
394 {
395 async_global_transfered = 0;
396 async_global_file = file;
397 async_global_max_size = max_size;
398 async_global_time = time;
399
400 var req = new XMLHttpRequest ();
401 req.addEventListener ("error", pop_failure, false);
402 req.addEventListener ("abort", pop_failure, false);
403 req.onreadystatechange = function ()
404 {
405 if (req.readyState == 4 && req.status == 200)
406 {
407 var res = req.responseText;
408
409 if (/^Error/.test(res))
410 {
411 pop_failure (res);
412 return;
413 }
414
415 res = res.split ("\n");
416 async_global_ref = res[0];
417 var code = res[1];
418 async_upload_push (code);
419 }
420 }
421 req.open ("POST", 'script.php?init_async' , true);
422
423 var form = new FormData();
424 form.append ("filename", async_global_file.name);
425 form.append ("type", async_global_file.type);
426 if (time)
427 form.append ("time", time);
428 if (password)
429 form.append ("key", password);
430 if (one_time)
431 form.append ("one_time_download", '1');
432 if (upload_password.length > 0)
433 form.append ("upload_password", upload_password);
434
435 // Start time estimation
436 upload_time_estimation_init(async_global_file.size);
437
438 req.send (form);
439 }
440
441 function async_upload_progress (e)
442 {
443 if (e == undefined || e == null || !e.lengthComputable && async_global_file.size != 0)
444 return;
445
446 // Compute percentage
447 var p = Math.round ((e.loaded + async_global_transfered) * 100 / (async_global_file.size));
448 var p_str = ' ';
449 if (p != 100)
450 p_str = p.toString() + '%';
451 // Update estimation speed
452 upload_time_estimation_add(e.loaded + async_global_transfered);
453 // Get speed string
454 var speed_str = upload_time_estimation_speed_string();
455 speed_str = upload_speed_refresh_limiter(speed_str);
456 // Get time string
457 var time_str = chrono_update(upload_time_estimation_time());
458
459 show_upload_progression (p_str, speed_str, time_str);
460 }
461
462 function async_upload_push (code)
463 {
464 if (async_global_transfered == async_global_file.size)
465 {
466 hide_upload_progression ();
467 async_upload_end (code);
468 return;
469 }
470 var req = new XMLHttpRequest ();
471 req.upload.addEventListener ("progress", async_upload_progress, false);
472 req.addEventListener ("error", pop_failure, false);
473 req.addEventListener ("abort", pop_failure, false);
474 req.onreadystatechange = function ()
475 {
476 if (req.readyState == 4 && req.status == 200)
477 {
478 var res = req.responseText;
479
480 if (/^Error/.test(res))
481 {
482 pop_failure (res);
483 return;
484 }
485
486 res = res.split ("\n");
487 var code = res[0]
488 async_global_transfered = async_global_transfering;
489 async_upload_push (code);
490 }
491 }
492 req.open ("POST", 'script.php?push_async' , true);
493
494 var chunk_size = parseInt (async_global_max_size * 0.50);
495 var start = async_global_transfered;
496 var end = start + chunk_size;
497 if (end >= async_global_file.size)
498 end = async_global_file.size;
499 var blob = async_global_file.slice (start, end);
500 async_global_transfering = end;
501
502 var form = new FormData();
503 form.append ("ref", async_global_ref);
504 form.append ("data", blob);
505 form.append ("code", code);
506 req.send (form);
507 }
508
509 function async_upload_end (code)
510 {
511 var req = new XMLHttpRequest ();
512 req.addEventListener ("error", pop_failure, false);
513 req.addEventListener ("abort", pop_failure, false);
514 req.onreadystatechange = function ()
515 {
516 if (req.readyState == 4 && req.status == 200)
517 {
518 var res = req.responseText;
519
520 if (/^Error/.test(res))
521 {
522 pop_failure (res);
523 return;
524 }
525
526 res = res.split ("\n");
527 var expiryDate = '';
528 if (async_global_time != 'none')
529 {
530 // convert time (local time + selected expiry date)
531 var localDatetime = new Date();
532 if(!add_time_string_to_date(localDatetime, async_global_time)) {
533 pop_failure ('Error: Date can not be parsed');
534 return;
535 }
536 expiryDate = localDatetime;
537 }
538
539 show_link (res[0], res[1], res[2], expiryDate);
540 }
541 }
542 req.open ("POST", 'script.php?end_async' , true);
543
544 var form = new FormData();
545 form.append ("ref", async_global_ref);
546 form.append ("code", code);
547 req.send (form);
548 }
549
550 function upload (max_size)
551 {
552 if (check_html5_file_api ()
553 && document.getElementById('file_select').files[0].size >= max_size)
554 {
555 async_upload_start (
556 max_size,
557 document.getElementById('file_select').files[0],
558 document.getElementById('select_time').value,
559 document.getElementById('input_key').value,
560 document.getElementById('one_time_download').checked,
561 document.getElementById('upload_password').value
562 );
563 }
564 else
565 {
566 classic_upload (
567 document.getElementById('file_select').files[0],
568 document.getElementById('select_time').value,
569 document.getElementById('input_key').value,
570 document.getElementById('one_time_download').checked,
571 document.getElementById('upload_password').value
572 );
573 }
574 }
575
576 var upload_time_estimation_total_size = 42;
577 var upload_time_estimation_transfered_size = 42;
578 var upload_time_estimation_transfered_date = 42;
579 var upload_time_estimation_moving_average_speed = 42;
580
581 function upload_time_estimation_init(total_size)
582 {
583 upload_time_estimation_total_size = total_size;
584 upload_time_estimation_transfered_size = 0;
585 upload_time_estimation_moving_average_speed = 0;
586 var d = new Date();
587 upload_time_estimation_transfered_date = d.getTime();
588 }
589
590 function upload_time_estimation_add(total_transfered_size)
591 {
592 // Let's compute the current speed
593 var d = new Date();
594 var speed = upload_time_estimation_moving_average_speed;
595 if (d.getTime() - upload_time_estimation_transfered_date != 0)
596 speed = (total_transfered_size - upload_time_estimation_transfered_size)
597 / (d.getTime() - upload_time_estimation_transfered_date);
598 // Let's compute moving average speed on 30 values
599 var m = (upload_time_estimation_moving_average_speed * 29 + speed) / 30;
600 // Update global values
601 upload_time_estimation_transfered_size = total_transfered_size;
602 upload_time_estimation_transfered_date = d.getTime();
603 upload_time_estimation_moving_average_speed = m;
604 }
605
606 function upload_time_estimation_speed_string()
607 {
608 // speed ms -> s
609 var s = upload_time_estimation_moving_average_speed * 1000;
610 var res = 0;
611 var scale = '';
612 if (s <= 1000)
613 {
614 res = s.toString();
615 scale = "Bit/s";
616 }
617 else if (s < 1000000)
618 {
619 res = Math.floor(s/100) / 10;
620 scale = "KBit/s";
621 }
622 else
623 {
624 res = Math.floor(s/100000) / 10;
625 scale = "Mbit/s";
626 }
627 if (res == 0)
628 return '';
629 return res.toString() + ' ' + scale;
630 }
631
632 function milliseconds_to_time_string (milliseconds)
633 {
634 function numberEnding (number) {
635 var currentLanguage = '<?php echo $cfg['lang']; ?>';
636
637 if(currentLanguage == 'de') {
638 return (number > 1) ? 'n' : '';
639 }
640 else {
641 return (number > 1) ? 's' : '';
642 }
643 }
644
645 var temp = Math.floor(milliseconds / 1000);
646 var years = Math.floor(temp / 31536000);
647 if (years) {
648 return years + ' ' + translate ('year') + numberEnding(years);
649 }
650 var days = Math.floor((temp %= 31536000) / 86400);
651 if (days) {
652 return days + ' ' + translate ('day') + numberEnding(days);
653 }
654 var hours = Math.floor((temp %= 86400) / 3600);
655 if (hours) {
656 return hours + ' ' + translate ('hour') + numberEnding(hours);
657 }
658 var minutes = Math.floor((temp %= 3600) / 60);
659 if (minutes) {
660 return minutes + ' ' + translate ('minute') + numberEnding(minutes);
661 }
662 var seconds = temp % 60;
663 if (seconds) {
664 return seconds + ' ' + translate ('second') + numberEnding(seconds);
665 }
666 return translate ('less than a second');
667 }
668
669 function upload_time_estimation_time()
670 {
671 // Estimate remaining time
672 if (upload_time_estimation_moving_average_speed == 0)
673 return 0;
674 return (upload_time_estimation_total_size - upload_time_estimation_transfered_size)
675 / upload_time_estimation_moving_average_speed;
676 }
677
678 var chrono_last_update = 0;
679 var chrono_time_ms = 0;
680 var chrono_time_ms_last_update = 0;
681 function chrono_update(time_ms)
682 {
683 var d = new Date();
684 var chrono = 0;
685 // Don't update too often
686 if (d.getTime() - chrono_last_update < 3000 &&
687 chrono_time_ms_last_update > 0)
688 chrono = chrono_time_ms;
689 else
690 {
691 chrono_last_update = d.getTime();
692 chrono_time_ms = time_ms;
693 chrono = time_ms;
694 chrono_time_ms_last_update = d.getTime();
695 }
696
697 // Adjust chrono for smooth estimation
698 chrono = chrono - (d.getTime() - chrono_time_ms_last_update);
699
700 // Let's update chronometer
701 var time_str = '';
702 if (chrono > 0)
703 time_str = milliseconds_to_time_string (chrono);
704 return time_str;
705 }
706
707 var upload_speed_refresh_limiter_last_update = 0;
708 var upload_speed_refresh_limiter_last_value = '';
709 function upload_speed_refresh_limiter(speed_str)
710 {
711 var d = new Date();
712 if (d.getTime() - upload_speed_refresh_limiter_last_update > 1500)
713 {
714 upload_speed_refresh_limiter_last_value = speed_str;
715 upload_speed_refresh_limiter_last_update = d.getTime();
716 }
717 return upload_speed_refresh_limiter_last_value;
718 }
719
720 // document.ready()
721 document.addEventListener('DOMContentLoaded', function(event) {
722 // Search for all datetime fields and convert the time to local timezone
723 convertAllDatetimeFields();
724 });
725
726 // Add copy event listeners
727 function copyLinkToClipboard(link_id) {
728 var focus = document.activeElement;
729 var e = document.getElementById(link_id);
730
731 var tmp = document.createElement("textarea");
732 document.body.appendChild(tmp);
733 tmp.textContent = e.href;
734 tmp.focus();
735 tmp.setSelectionRange(0, tmp.value.length);
736 document.execCommand("copy");
737 document.body.removeChild(tmp);
738
739 focus.focus();
740 }
741
742 function addCopyListener(button_id, link_id) {
743 document.getElementById(button_id)
744 .addEventListener("click", function() {
745 copyLinkToClipboard(link_id);});
746 }

patrick-canterino.de