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>
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.
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.
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/>.
21 header('Content-Type: text/javascript');
23 define('JIRAFEAU_ROOT', dirname(__FILE__
) . '/../');
25 require(JIRAFEAU_ROOT
. 'lib/settings.php');
26 require(JIRAFEAU_ROOT
. 'lib/functions.php');
27 require(JIRAFEAU_ROOT
. 'lib/lang.php');
29 var web_root
= "<?php echo $cfg['web_root']; ?>";
31 function translate (expr
)
33 var lang_array
= <?php
echo json_lang_generator() ?
>;
34 if (lang_array
.hasOwnProperty(expr
))
35 return lang_array
[expr
];
39 function isEmpty(str
) {
40 return (!str ||
0 === str
.length
);
43 // Extend date object with format method
44 Date
.prototype
.format
= function(format
) {
45 format
= format ||
'YYYY-MM-DD hh:mm';
47 var zeropad
= function(number
, length
) {
48 number
= number
.toString();
50 while(number
.length
< length
)
51 number
= '0' + number
;
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()),
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
;
69 pattern
= '(' +
Object.keys(formats
).join(')|(') +
')';
71 return format
.replace(new RegExp(pattern
, 'g'), function(match
) {
72 return formats
[match
];
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));
82 function dateFromUtcTimestamp(datetimestamp
) {
83 return new Date(parseInt(datetimestamp
) * 1000)
86 function dateToUtcString(datelocal
) {
88 datelocal
.getUTCFullYear(),
89 datelocal
.getUTCMonth(),
90 datelocal
.getUTCDate(),
91 datelocal
.getUTCHours(),
92 datelocal
.getUTCMinutes(),
93 datelocal
.getUTCSeconds()
97 function dateToUtcTimestamp(datelocal
) {
99 datelocal
.getUTCFullYear(),
100 datelocal
.getUTCMonth(),
101 datelocal
.getUTCDate(),
102 datelocal
.getUTCHours(),
103 datelocal
.getUTCMinutes(),
104 datelocal
.getUTCSeconds()
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)');
117 function show_link (reference
, delete_code
, crypt_key
, date
)
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']; ?>";
126 var download_link_href
= 'f.php?h=' + reference
;
127 if (crypt_key
.length
> 0)
129 download_link_href +
= '&k=' + crypt_key
;
131 if (!!document
.getElementById('upload_finished_download_page'))
133 document
.getElementById('upload_link').href
= download_link_href
;
134 document
.getElementById('upload_link_text').innerHTML
= web_root + download_link_href
;
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
))
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
);
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
;
155 document
.getElementById('date').style
.display
= 'none';
158 document
.getElementById('date').innerHTML
= '<span class="datetime" title="'
159 +
dateToUtcString(date
) +
' (GMT)">'
160 + date
.format('YYYY-MM-DD hh:mm (GMT O)')
162 document
.getElementById('date').style
.display
= '';
165 // Preview link (if allowed)
166 if (!!document
.getElementById('preview_link'))
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)
172 preview_link_href +
= '&k=' + crypt_key
;
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)
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
= '';
188 // Direct download link
189 var direct_download_link_href
= 'f.php?h=' + reference +
'&d=1';
190 if (crypt_key
.length
> 0)
192 direct_download_link_href +
= '&k=' + crypt_key
;
194 document
.getElementById('direct_link').href
= direct_download_link_href
;
195 document
.getElementById('direct_link_text').innerHTML
= web_root + direct_download_link_href
;
197 // Hide preview and direct download link if password is set
198 if (document
.getElementById('input_key').value
.length
> 0)
200 if (!!document
.getElementById('preview_link'))
201 document
.getElementById('upload_finished_preview').style
.display
= 'none';
202 document
.getElementById('upload_direct_download').style
.display
= 'none';
206 function show_upload_progression (percentage
, speed
, time_left
)
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']; ?>";
214 function hide_upload_progression ()
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']; ?>";
222 function upload_progress (e
)
224 if (e
== undefined || e
== null ||
!e
.lengthComputable
)
227 // Init time estimation if needed
228 if (upload_time_estimation_total_size
== 0)
229 upload_time_estimation_total_size
= e
.total
;
231 // Compute percentage
232 var p
= Math
.round (e
.loaded
* 100 / e
.total
);
235 p_str
= p
.toString() +
'%';
236 // Update estimation speed
237 upload_time_estimation_add(e
.loaded
);
239 var speed_str
= upload_time_estimation_speed_string();
240 speed_str
= upload_speed_refresh_limiter(speed_str
);
242 var time_str
= chrono_update(upload_time_estimation_time());
244 show_upload_progression (p_str
, speed_str
, time_str
);
247 function control_selected_file_size(max_size
, error_str
)
249 f_size
= document
.getElementById('file_select').files
[0].size
;
250 if (max_size
> 0 && f_size
> max_size
* 1024 * 1024)
252 pop_failure(error_str
);
253 document
.getElementById('send').style
.display
= 'none';
257 // add class to restyle upload form in next step
258 document
.getElementById('upload').setAttribute('class', 'file-selected');
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();
267 function pop_failure (e
)
269 var text
= "An error occured";
270 if (typeof e
!== 'undefined')
272 text
= "<p>" + text +
"</p>";
273 document
.getElementById('error_pop').innerHTML
= e
;
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
= '';
281 function add_time_string_to_date(d
, time
)
283 if(typeof(d
) != 'object' ||
!(d
instanceof Date
))
288 if (time
== 'minute')
290 d
.setSeconds (d
.getSeconds() +
60);
295 d
.setSeconds (d
.getSeconds() +
3600);
300 d
.setSeconds (d
.getSeconds() +
86400);
305 d
.setSeconds (d
.getSeconds() +
604800);
310 d
.setSeconds (d
.getSeconds() +
2419200);
313 if (time
== 'quarter')
315 d
.setSeconds (d
.getSeconds() +
7257600);
320 d
.setSeconds (d
.getSeconds() +
29030400);
326 function classic_upload (file
, time
, password
, one_time
, upload_password
)
328 // Delay time estimation init as we can't have file size
329 upload_time_estimation_init(0);
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 ()
337 if (req
.readyState
== 4 && req
.status
== 200)
339 var res
= req
.responseText
;
341 // if response starts with "Error" then show a failure
342 if (/^Error
/.test(res
))
348 res
= res
.split ("\n");
352 // convert time (local time + selected expiry date)
353 var localDatetime
= new Date();
354 if(!add_time_string_to_date(localDatetime
, time
))
356 pop_failure ('Error: Date can not be parsed');
359 expiryDate
= localDatetime
;
362 show_link (res
[0], res
[1], res
[2], expiryDate
);
365 req
.open ("POST", 'script.php' , true);
367 var form
= new FormData();
368 form
.append ("file", file
);
370 form
.append ("time", time
);
372 form
.append ("key", password
);
374 form
.append ("one_time_download", '1');
375 if (upload_password
.length
> 0)
376 form
.append ("upload_password", upload_password
);
381 function check_html5_file_api ()
383 return window
.File
&& window
.FileReader
&& window
.FileList
&& window
.Blob
;
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;
393 function async_upload_start (max_size
, file
, time
, password
, one_time
, upload_password
)
395 async_global_transfered
= 0;
396 async_global_file
= file
;
397 async_global_max_size
= max_size
;
398 async_global_time
= time
;
400 var req
= new XMLHttpRequest ();
401 req
.addEventListener ("error", pop_failure
, false);
402 req
.addEventListener ("abort", pop_failure
, false);
403 req
.onreadystatechange
= function ()
405 if (req
.readyState
== 4 && req
.status
== 200)
407 var res
= req
.responseText
;
409 if (/^Error
/.test(res
))
415 res
= res
.split ("\n");
416 async_global_ref
= res
[0];
418 async_upload_push (code
);
421 req
.open ("POST", 'script.php?init_async' , true);
423 var form
= new FormData();
424 form
.append ("filename", async_global_file
.name
);
425 form
.append ("type", async_global_file
.type
);
427 form
.append ("time", time
);
429 form
.append ("key", password
);
431 form
.append ("one_time_download", '1');
432 if (upload_password
.length
> 0)
433 form
.append ("upload_password", upload_password
);
435 // Start time estimation
436 upload_time_estimation_init(async_global_file
.size
);
441 function async_upload_progress (e
)
443 if (e
== undefined || e
== null ||
!e
.lengthComputable
&& async_global_file
.size
!= 0)
446 // Compute percentage
447 var p
= Math
.round ((e
.loaded + async_global_transfered
) * 100 / (async_global_file
.size
));
450 p_str
= p
.toString() +
'%';
451 // Update estimation speed
452 upload_time_estimation_add(e
.loaded + async_global_transfered
);
454 var speed_str
= upload_time_estimation_speed_string();
455 speed_str
= upload_speed_refresh_limiter(speed_str
);
457 var time_str
= chrono_update(upload_time_estimation_time());
459 show_upload_progression (p_str
, speed_str
, time_str
);
462 function async_upload_push (code
)
464 if (async_global_transfered
== async_global_file
.size
)
466 hide_upload_progression ();
467 async_upload_end (code
);
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 ()
476 if (req
.readyState
== 4 && req
.status
== 200)
478 var res
= req
.responseText
;
480 if (/^Error
/.test(res
))
486 res
= res
.split ("\n");
488 async_global_transfered
= async_global_transfering
;
489 async_upload_push (code
);
492 req
.open ("POST", 'script.php?push_async' , true);
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
;
502 var form
= new FormData();
503 form
.append ("ref", async_global_ref
);
504 form
.append ("data", blob
);
505 form
.append ("code", code
);
509 function async_upload_end (code
)
511 var req
= new XMLHttpRequest ();
512 req
.addEventListener ("error", pop_failure
, false);
513 req
.addEventListener ("abort", pop_failure
, false);
514 req
.onreadystatechange
= function ()
516 if (req
.readyState
== 4 && req
.status
== 200)
518 var res
= req
.responseText
;
520 if (/^Error
/.test(res
))
526 res
= res
.split ("\n");
528 if (async_global_time
!= 'none')
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');
536 expiryDate
= localDatetime
;
539 show_link (res
[0], res
[1], res
[2], expiryDate
);
542 req
.open ("POST", 'script.php?end_async' , true);
544 var form
= new FormData();
545 form
.append ("ref", async_global_ref
);
546 form
.append ("code", code
);
550 function upload (max_size
)
552 if (check_html5_file_api ()
553 && document
.getElementById('file_select').files
[0].size
>= 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
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
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;
581 function upload_time_estimation_init(total_size
)
583 upload_time_estimation_total_size
= total_size
;
584 upload_time_estimation_transfered_size
= 0;
585 upload_time_estimation_moving_average_speed
= 0;
587 upload_time_estimation_transfered_date
= d
.getTime();
590 function upload_time_estimation_add(total_transfered_size
)
592 // Let's compute the current speed
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
;
606 function upload_time_estimation_speed_string()
609 var s
= upload_time_estimation_moving_average_speed
* 1000;
617 else if (s
< 1000000)
619 res
= Math
.floor(s
/100) / 10;
624 res
= Math
.floor(s
/100000) / 10;
629 return res
.toString() +
' ' + scale
;
632 function milliseconds_to_time_string (milliseconds
)
634 function numberEnding (number
) {
635 var currentLanguage
= '<?php echo $cfg['lang
']; ?>';
637 if(currentLanguage
== 'de') {
638 return (number
> 1) ?
'n' : '';
641 return (number
> 1) ?
's' : '';
645 var temp
= Math
.floor(milliseconds
/ 1000);
646 var years
= Math
.floor(temp
/ 31536000);
648 return years +
' ' +
translate ('year') +
numberEnding(years
);
650 var days
= Math
.floor((temp %
= 31536000) / 86400);
652 return days +
' ' +
translate ('day') +
numberEnding(days
);
654 var hours
= Math
.floor((temp %
= 86400) / 3600);
656 return hours +
' ' +
translate ('hour') +
numberEnding(hours
);
658 var minutes
= Math
.floor((temp %
= 3600) / 60);
660 return minutes +
' ' +
translate ('minute') +
numberEnding(minutes
);
662 var seconds
= temp %
60;
664 return seconds +
' ' +
translate ('second') +
numberEnding(seconds
);
666 return translate ('less than a second');
669 function upload_time_estimation_time()
671 // Estimate remaining time
672 if (upload_time_estimation_moving_average_speed
== 0)
674 return (upload_time_estimation_total_size
- upload_time_estimation_transfered_size
)
675 / upload_time_estimation_moving_average_speed
;
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
)
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
;
691 chrono_last_update
= d
.getTime();
692 chrono_time_ms
= time_ms
;
694 chrono_time_ms_last_update
= d
.getTime();
697 // Adjust chrono for smooth estimation
698 chrono
= chrono
- (d
.getTime() - chrono_time_ms_last_update
);
700 // Let's update chronometer
703 time_str
= milliseconds_to_time_string (chrono
);
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
)
712 if (d
.getTime() - upload_speed_refresh_limiter_last_update
> 1500)
714 upload_speed_refresh_limiter_last_value
= speed_str
;
715 upload_speed_refresh_limiter_last_update
= d
.getTime();
717 return upload_speed_refresh_limiter_last_value
;
721 document
.addEventListener('DOMContentLoaded', function(event
) {
722 // Search for all datetime fields and convert the time to local timezone
723 convertAllDatetimeFields();
726 // Add copy event listeners
727 function copyLinkToClipboard(link_id
) {
728 var focus
= document
.activeElement
;
729 var e
= document
.getElementById(link_id
);
731 var tmp
= document
.createElement("textarea");
732 document
.body
.appendChild(tmp
);
733 tmp
.textContent
= e
.href
;
735 tmp
.setSelectionRange(0, tmp
.value
.length
);
736 document
.execCommand("copy");
737 document
.body
.removeChild(tmp
);
742 function addCopyListener(button_id
, link_id
) {
743 document
.getElementById(button_id
)
744 .addEventListener("click", function() {
745 copyLinkToClipboard(link_id
);});