3 * Jirafeau, your web file repository
4 * Copyright (C) 2008 Julien "axolotl" BERNARD <axolotl@magieeternelle.org>
5 * Copyright (C) 2015 Jerome Jutteau <jerome@jutteau.fr>
6 * Copyright (C) 2024 Jirafeau project <https://gitlab.com/jirafeau> (see AUTHORS.md)
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as
10 * published by the Free Software Foundation, either version 3 of the
11 * License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Affero General Public License for more details.
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 function template_js_preview_link() {
24 if (!!document
.getElementById('preview_link'))
26 document
.getElementById('upload_finished_preview').style
.display
= 'none';
27 var preview_link_href
= 'f.php?h=' + reference +
'&p=1';
28 if (crypt_key
.length
> 0)
30 preview_link_href +
= '&k=' + crypt_key
;
33 // Test if content can be previewed
34 type
= document
.getElementById('file_select').files
[0].type
;
35 if ((type
.startsWith('image/')
36 || type
.startsWith('audio')
37 || type
.startsWith('text/plain')
38 || type
.startsWith('video/'))
39 && !type
.includes('image/svg+xml'))
41 document
.getElementById('preview_link').href
= preview_link_href
;
42 document
.getElementById('preview_link_text').innerHTML
= web_root + preview_link_href
;
43 document
.getElementById('upload_finished_preview').style
.display
= '';
48 function template_js_download_page() {
51 var download_link_href
= 'f.php?h=' + reference
;
52 if (crypt_key
.length
> 0)
54 download_link_href +
= '&k=' + crypt_key
;
56 if (!!document
.getElementById('upload_finished_download_page'))
58 document
.getElementById('upload_link').href
= download_link_href
;
59 document
.getElementById('upload_link_text').innerHTML
= web_root + download_link_href
;
63 function template_js_email_link() {
66 var b
= encodeURIComponent("<?php echo t("DL
"); ?> \"" + filename +
"\":") +
"%0D" +
"%0A";
67 b +
= encodeURIComponent(web_root + download_link_href
) +
"%0D" +
"%0A";
68 if (false == isEmpty(date
))
70 b +
= "%0D" +
"%0A" +
encodeURIComponent("<?php echo t("VALID_UNTIL
"); ?>: " + date
.format('YYYY-MM-DD hh:mm (GMT O)')) +
"%0D" +
"%0A";
71 document
.getElementById('upload_link_email').href
= "mailto:?body=" + b +
"&subject=" +
encodeURIComponent(filename
);
75 function template_js_delete_link() {
78 var delete_link_href
= 'f.php?h=' + reference +
'&d=' + delete_code
;
79 document
.getElementById('delete_link').href
= delete_link_href
;
80 document
.getElementById('delete_link_text').innerHTML
= web_root + delete_link_href
;
83 function template_js_direct_download() {
85 // Direct download link
86 var direct_download_link_href
= 'f.php?h=' + reference +
'&d=1';
87 if (crypt_key
.length
> 0)
89 direct_download_link_href +
= '&k=' + crypt_key
;
91 document
.getElementById('direct_link').href
= direct_download_link_href
;
92 document
.getElementById('direct_link_text').innerHTML
= web_root + direct_download_link_href
;
95 function template_js_date_function() {
100 document
.getElementById('date').style
.display
= 'none';
103 document
.getElementById('date').innerHTML
=
104 '<span class="datetime"'
106 +
dateToUtcString(date
) +
' (GMT"'
108 +
dateToUtcString(date
) +
' (GMT)">'
109 + date
.format('YYYY-MM-DD hh:mm (GMT O)')
111 document
.getElementById('date').style
.display
= '';
119 header('Content-Type: text/javascript');
120 define('JIRAFEAU_ROOT', dirname(__FILE__
) . '/../');
122 require(JIRAFEAU_ROOT
. 'lib/settings.php');
123 require(JIRAFEAU_ROOT
. 'lib/functions.php');
124 require(JIRAFEAU_ROOT
. 'lib/lang.php');
127 // @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
128 var web_root
= "<?php echo $cfg['web_root']; ?>";
130 var lang_array
= <?php
echo json_lang_generator(null); ?
>;
131 var lang_array_fallback
= <?php
echo json_lang_generator("en"); ?
>;
133 function translate (expr
) {
134 if (lang_array
.hasOwnProperty(expr
)) {
135 var e
= lang_array
[expr
];
139 if (lang_array_fallback
.hasOwnProperty(expr
)) {
140 var e
= lang_array_fallback
[expr
];
144 return "FIXME: " + expr
;
147 function isEmpty(str
) {
148 return (!str ||
0 === str
.length
);
151 // Extend date object with format method
152 Date
.prototype
.format
= function(format
) {
153 format
= format ||
'YYYY-MM-DD hh:mm';
155 var zeropad
= function(number
, length
) {
156 number
= number
.toString();
157 length
= length ||
2;
158 while(number
.length
< length
)
159 number
= '0' + number
;
163 YYYY
: this
.getFullYear(),
164 MM
: zeropad(this
.getMonth() +
1),
165 DD
: zeropad(this
.getDate()),
166 hh
: zeropad(this
.getHours()),
167 mm
: zeropad(this
.getMinutes()),
169 localDate
= new Date
;
170 sign
= (localDate
.getTimezoneOffset() > 0) ?
'-' : '+';
171 offset
= Math
.abs(localDate
.getTimezoneOffset());
172 hours
= zeropad(Math
.floor(offset
/ 60));
173 minutes
= zeropad(offset %
60);
174 return sign + hours +
":" + minutes
;
177 pattern
= '(' +
Object.keys(formats
).join(')|(') +
')';
179 return format
.replace(new RegExp(pattern
, 'g'), function(match
) {
180 return formats
[match
];
184 function dateFromUtcString(datestring
) {
185 // matches »YYYY-MM-DD hh:mm«
186 var m
= datestring
.match(/(\d+
)-(\d+
)-(\d+
)\s+
(\d+
):(\d+
)/);
187 return new Date(Date
.UTC(+m
[1], +m
[2] - 1, +m
[3], +m
[4], +m
[5], 0));
190 function dateFromUtcTimestamp(datetimestamp
) {
191 return new Date(parseInt(datetimestamp
) * 1000)
194 function dateToUtcString(datelocal
) {
196 datelocal
.getUTCFullYear(),
197 datelocal
.getUTCMonth(),
198 datelocal
.getUTCDate(),
199 datelocal
.getUTCHours(),
200 datelocal
.getUTCMinutes(),
201 datelocal
.getUTCSeconds()
205 function dateToUtcTimestamp(datelocal
) {
207 datelocal
.getUTCFullYear(),
208 datelocal
.getUTCMonth(),
209 datelocal
.getUTCDate(),
210 datelocal
.getUTCHours(),
211 datelocal
.getUTCMinutes(),
212 datelocal
.getUTCSeconds()
216 function convertAllDatetimeFields() {
217 datefields
= document
.getElementsByClassName('datetime')
218 for(var i
=0; i
<datefields
.length
; i++
) {
219 dateUTC
= datefields
[i
].getAttribute('data-datetime');
220 datefields
[i
].setAttribute('title', dateUTC +
' (GMT)');
221 datefields
[i
].innerHTML
= dateFromUtcString(dateUTC
).format('YYYY-MM-DD hh:mm (GMT O)');
225 // evil copy and paste from show_link - TODO refactor show link
226 function show_link_from_php (file_name
,file_type
, reference
, delete_code
, crypt_key
, date
)
228 <?php
template_js_download_page(); ?
>
231 var filename
= file_name
;
232 <?php
template_js_email_link(); ?
>
233 <?php
template_js_delete_link(); ?
>
234 <?php
template_js_date_function(); ?
>
235 var type
= file_type
;
236 <?php
template_js_direct_download();?
>
241 function show_link (reference
, delete_code
, crypt_key
, date
)
244 document
.getElementById('uploading').style
.display
= 'none';
245 document
.getElementById('upload').style
.display
= 'none';
246 document
.getElementById('upload_finished').style
.display
= '';
247 document
.title
= "100% - <?php echo empty($cfg['title']) ? 'Jirafeau' : $cfg['title']; ?>";
249 <?php
template_js_download_page(); ?
>
251 var filename
= document
.getElementById('file_select').files
[0].name
;
253 <?php
template_js_email_link(); ?
>
255 <?php
template_js_delete_link(); ?
>
256 <?php
template_js_date_function(); ?
>
259 // Preview link (if allowed)
261 var type
= document
.getElementById('file_select').files
[0].type
;
262 <?php
template_js_preview_link(); ?
>
264 <?php
template_js_direct_download();?
>
267 // Hide preview and direct download link if password is set
268 if (document
.getElementById('input_key').value
.length
> 0)
270 if (!!document
.getElementById('preview_link'))
271 document
.getElementById('upload_finished_preview').style
.display
= 'none';
272 document
.getElementById('upload_direct_download').style
.display
= 'none';
276 function show_upload_progression (percentage
, speed
, time_left
)
278 document
.getElementById('uploaded_percentage').innerHTML
= percentage
;
279 document
.getElementById('uploaded_speed').innerHTML
= speed
;
280 document
.getElementById('uploaded_time').innerHTML
= time_left
;
281 document
.title
= percentage +
" - <?php echo empty($cfg['title']) ? 'Jirafeau' : $cfg['title']; ?>";
284 function hide_upload_progression ()
286 document
.getElementById('uploaded_percentage').style
.display
= 'none';
287 document
.getElementById('uploaded_speed').style
.display
= 'none';
288 document
.getElementById('uploaded_time').style
.display
= 'none';
289 document
.title
= "<?php echo empty($cfg['title']) ? 'Jirafeau' : $cfg['title']; ?>";
292 function upload_progress (e
)
294 if (e
== undefined || e
== null ||
!e
.lengthComputable
)
297 // Init time estimation if needed
298 if (upload_time_estimation_total_size
== 0)
299 upload_time_estimation_total_size
= e
.total
;
301 // Compute percentage
302 var p
= Math
.round (e
.loaded
* 100 / e
.total
);
305 p_str
= p
.toString() +
'%';
306 // Update estimation speed
307 upload_time_estimation_add(e
.loaded
);
309 var speed_str
= upload_time_estimation_speed_string();
310 speed_str
= upload_speed_refresh_limiter(speed_str
);
312 var time_str
= chrono_update(upload_time_estimation_time());
314 show_upload_progression (p_str
, speed_str
, time_str
);
317 function control_selected_file_size(max_size
, error_str
)
319 f_size
= document
.getElementById('file_select').files
[0].size
;
320 if (max_size
> 0 && f_size
> max_size
* 1024 * 1024)
322 pop_failure(error_str
);
323 document
.getElementById('send').style
.display
= 'none';
327 // add class to restyle upload form in next step
328 document
.getElementById('upload').setAttribute('class', 'file-selected');
330 document
.getElementById('options').style
.display
= 'block';
331 document
.getElementById('send').style
.display
= 'block';
332 document
.getElementById('error_pop').style
.display
= 'none';
333 document
.getElementById('send').focus();
337 function XHRErrorHandler(e
)
339 var text
= "${e.type}: ${e.loaded} bytes transferred"
343 function pop_failure (e
)
345 var text
= "<p>An error occured";
346 if (typeof e
!== 'undefined')
349 document
.getElementById('error_pop').innerHTML
= e
;
351 document
.getElementById('uploading').style
.display
= 'none';
352 document
.getElementById('error_pop').style
.display
= '';
353 document
.getElementById('upload').style
.display
= '';
354 document
.getElementById('send').style
.display
= '';
357 function add_time_string_to_date(d
, time
)
359 if(typeof(d
) != 'object' ||
!(d
instanceof Date
))
364 if (time
== 'minute')
366 d
.setSeconds (d
.getSeconds() +
60);
371 d
.setSeconds (d
.getSeconds() +
3600);
376 d
.setSeconds (d
.getSeconds() +
86400);
381 d
.setSeconds (d
.getSeconds() +
604800);
384 if (time
== 'fortnight')
386 d
.setSeconds (d
.getSeconds() +
1209600);
391 d
.setSeconds (d
.getSeconds() +
2592000);
394 if (time
== 'quarter')
396 d
.setSeconds (d
.getSeconds() +
7776000);
401 d
.setSeconds (d
.getSeconds() +
31536000);
407 function classic_upload (file
, time
, password
, one_time
)
409 // Delay time estimation init as we can't have file size
410 upload_time_estimation_init(0);
412 var req
= new XMLHttpRequest ();
413 req
.upload
.addEventListener ("progress", upload_progress
, false);
414 req
.addEventListener ("error", XHRErrorHandler
, false);
415 req
.addEventListener ("abort", XHRErrorHandler
, false);
416 req
.onreadystatechange
= function ()
418 if (req
.readyState
== 4 && req
.status
== 200)
420 var res
= req
.responseText
;
422 // if response starts with "Error" then show a failure
423 if (/^Error
/.test(res
))
429 res
= res
.split ("\n");
433 // convert time (local time + selected expiry date)
434 var localDatetime
= new Date();
435 if(!add_time_string_to_date(localDatetime
, time
))
437 pop_failure ('Error: Date can not be parsed');
440 expiryDate
= localDatetime
;
443 show_link (res
[0], res
[1], res
[2], expiryDate
);
447 pop_failure ("<?php echo t("ERR_OCC
"); ?>");
450 req
.open ("POST", 'script.php' , true);
452 var form
= new FormData();
453 form
.append ("file", file
);
455 form
.append ("time", time
);
457 form
.append ("key", password
);
459 form
.append ("one_time_download", '1');
463 function check_html5_file_api ()
465 return window
.File
&& window
.FileReader
&& window
.FileList
&& window
.Blob
;
468 var async_global_transfered
= 0;
469 var async_global_file
;
470 var async_global_ref
= '';
471 var async_global_max_size
= 0;
472 var async_global_time
;
473 var async_global_transfering
= 0;
474 var async_global_last_code
;
476 function async_upload_start (max_size
, file
, time
, password
, one_time
)
478 async_global_transfered
= 0;
479 async_global_file
= file
;
480 async_global_max_size
= max_size
;
481 async_global_time
= time
;
483 var req
= new XMLHttpRequest ();
484 req
.addEventListener ("error", XHRErrorHandler
, false);
485 req
.addEventListener ("abort", XHRErrorHandler
, false);
486 req
.onreadystatechange
= function ()
488 if (req
.readyState
== 4 && req
.status
== 200)
490 var res
= req
.responseText
;
492 if (/^Error
/.test(res
))
498 res
= res
.split ("\n");
499 async_global_ref
= res
[0];
501 async_upload_push (code
);
504 req
.open ("POST", 'script.php?init_async' , true);
506 var form
= new FormData();
507 form
.append ("filename", async_global_file
.name
);
508 form
.append ("type", async_global_file
.type
);
510 form
.append ("time", time
);
512 form
.append ("key", password
);
514 form
.append ("one_time_download", '1');
516 // Start time estimation
517 upload_time_estimation_init(async_global_file
.size
);
522 function async_upload_progress (e
)
524 if (e
== undefined || e
== null ||
!e
.lengthComputable
&& async_global_file
.size
!= 0)
527 // Compute percentage
528 var p
= Math
.round ((e
.loaded + async_global_transfered
) * 100 / (async_global_file
.size
));
531 p_str
= p
.toString() +
'%';
532 // Update estimation speed
533 upload_time_estimation_add(e
.loaded + async_global_transfered
);
535 var speed_str
= upload_time_estimation_speed_string();
536 speed_str
= upload_speed_refresh_limiter(speed_str
);
538 var time_str
= chrono_update(upload_time_estimation_time());
540 show_upload_progression (p_str
, speed_str
, time_str
);
543 function async_upload_push (code
)
545 async_global_last_code
= code
;
546 if (async_global_transfered
== async_global_file
.size
)
548 hide_upload_progression ();
549 async_upload_end (code
);
552 var req
= new XMLHttpRequest ();
553 req
.upload
.addEventListener ("progress", async_upload_progress
, false);
554 req
.addEventListener ("error", XHRErrorHandler
, false);
555 req
.addEventListener ("abort", XHRErrorHandler
, false);
556 req
.onreadystatechange
= function ()
558 if (req
.readyState
== 4)
560 if (req
.status
== 200)
562 var res
= req
.responseText
;
564 // This error may be triggered when Jirafeau does not receive any file in POST.
565 // This may be due to bad php configuration where post_max_size is too low
566 // comparing to upload_max_filesize. Let's retry with lower file size.
567 if (res
=== "Error 23")
569 async_global_max_size
= Math
.max(1, async_global_max_size
- 500);
570 async_upload_push (async_global_last_code
);
573 else if (/^Error
/.test(res
))
579 res
= res
.split ("\n");
581 async_global_transfered
= async_global_transfering
;
582 async_upload_push (code
);
587 // lower async_global_max_size and retry
588 // This can occurs in several cases:
589 // - Request Entity Too Large (413) due to server bad configuration relative to PHP configuration
590 // - Server Error (500) which can happen when PHP's `max_execution_time` is too low comparared to sent size
591 async_global_max_size
= Math
.max(1, parseInt (async_global_max_size
* 0.5));
592 async_upload_push (async_global_last_code
);
597 req
.open ("POST", 'script.php?push_async' , true);
599 var start
= async_global_transfered
;
600 var end
= start + async_global_max_size
;
601 if (end
>= async_global_file
.size
)
602 end
= async_global_file
.size
;
603 var blob
= async_global_file
.slice (start
, end
);
604 async_global_transfering
= end
;
606 var form
= new FormData();
607 form
.append ("ref", async_global_ref
);
608 form
.append ("data", blob
);
609 form
.append ("code", code
);
613 function async_upload_end (code
)
615 var req
= new XMLHttpRequest ();
616 req
.addEventListener ("error", XHRErrorHandler
, false);
617 req
.addEventListener ("abort", XHRErrorHandler
, false);
618 req
.onreadystatechange
= function ()
620 if (req
.readyState
== 4 && req
.status
== 200)
622 var res
= req
.responseText
;
624 if (/^Error
/.test(res
))
630 res
= res
.split ("\n");
632 if (async_global_time
!= 'none')
634 // convert time (local time + selected expiry date)
635 var localDatetime
= new Date();
636 if(!add_time_string_to_date(localDatetime
, async_global_time
)) {
637 pop_failure ('Error: Date can not be parsed');
640 expiryDate
= localDatetime
;
643 show_link (res
[0], res
[1], res
[2], expiryDate
);
646 req
.open ("POST", 'script.php?end_async' , true);
648 var form
= new FormData();
649 form
.append ("ref", async_global_ref
);
650 form
.append ("code", code
);
654 function upload (max_chunk_size
)
656 var one_time_checkbox
= document
.getElementById('one_time_download');
657 var one_time
= one_time_checkbox
!== null ? one_time_checkbox
.checked
: false;
658 if (check_html5_file_api ())
662 document
.getElementById('file_select').files
[0],
663 document
.getElementById('select_time').value
,
664 document
.getElementById('input_key').value
,
671 document
.getElementById('file_select').files
[0],
672 document
.getElementById('select_time').value
,
673 document
.getElementById('input_key').value
,
679 var upload_time_estimation_total_size
= 42;
680 var upload_time_estimation_transfered_size
= 42;
681 var upload_time_estimation_transfered_date
= 42;
682 var upload_time_estimation_moving_average_speed
= 42;
684 function upload_time_estimation_init(total_size
)
686 upload_time_estimation_total_size
= total_size
;
687 upload_time_estimation_transfered_size
= 0;
688 upload_time_estimation_moving_average_speed
= 0;
690 upload_time_estimation_transfered_date
= d
.getTime();
693 function upload_time_estimation_add(total_transfered_size
)
695 // Let's compute the current speed
697 var speed
= upload_time_estimation_moving_average_speed
;
698 if (d
.getTime() - upload_time_estimation_transfered_date
!= 0) {
699 speed
= (total_transfered_size
- upload_time_estimation_transfered_size
)
700 / (d
.getTime() - upload_time_estimation_transfered_date
);
701 speed
= Math
.max(0, speed
);
703 // Let's compute moving average speed on 30 values
704 var m
= (upload_time_estimation_moving_average_speed
* 29 + speed
) / 30;
705 // Update global values
706 upload_time_estimation_transfered_size
= total_transfered_size
;
707 upload_time_estimation_transfered_date
= d
.getTime();
708 upload_time_estimation_moving_average_speed
= m
;
711 function upload_time_estimation_speed_string()
714 var s
= upload_time_estimation_moving_average_speed
* 1000;
722 else if (s
< 1000000)
724 res
= Math
.floor(s
/100) / 10;
729 res
= Math
.floor(s
/100000) / 10;
734 return res
.toString() +
' ' + scale
;
737 function milliseconds_to_time_string (milliseconds
)
739 function numberEnding (number
) {
740 return (number
> 1) ?
translate ('PLURAL_ENDING') : '';
743 var temp
= Math
.floor(milliseconds
/ 1000);
744 var years
= Math
.floor(temp
/ 31536000);
746 return years +
' ' +
translate ('YEAR') +
numberEnding(years
);
748 var days
= Math
.floor((temp %
= 31536000) / 86400);
750 return days +
' ' +
translate ('DAY') +
numberEnding(days
);
752 var hours
= Math
.floor((temp %
= 86400) / 3600);
754 return hours +
' ' +
translate ('HOUR') +
numberEnding(hours
);
756 var minutes
= Math
.floor((temp %
= 3600) / 60);
758 return minutes +
' ' +
translate ('MINUTE') +
numberEnding(minutes
);
760 var seconds
= temp %
60;
762 return seconds +
' ' +
translate ('SECOND') +
numberEnding(seconds
);
764 return translate ('LESS_1_SEC');
767 function upload_time_estimation_time()
769 // Estimate remaining time
770 if (upload_time_estimation_moving_average_speed
<= 0)
772 return (upload_time_estimation_total_size
- upload_time_estimation_transfered_size
)
773 / upload_time_estimation_moving_average_speed
;
776 var chrono_last_update
= 0;
777 var chrono_time_ms
= 0;
778 var chrono_time_ms_last_update
= 0;
779 function chrono_update(time_ms
)
783 // Don't update too often
784 if (d
.getTime() - chrono_last_update
< 3000 &&
785 chrono_time_ms_last_update
> 0)
786 chrono
= chrono_time_ms
;
789 chrono_last_update
= d
.getTime();
790 chrono_time_ms
= time_ms
;
792 chrono_time_ms_last_update
= d
.getTime();
795 // Adjust chrono for smooth estimation
796 chrono
= chrono
- (d
.getTime() - chrono_time_ms_last_update
);
798 // Let's update chronometer
801 time_str
= milliseconds_to_time_string (chrono
);
805 var upload_speed_refresh_limiter_last_update
= 0;
806 var upload_speed_refresh_limiter_last_value
= '';
807 function upload_speed_refresh_limiter(speed_str
)
810 if (d
.getTime() - upload_speed_refresh_limiter_last_update
> 1500)
812 upload_speed_refresh_limiter_last_value
= speed_str
;
813 upload_speed_refresh_limiter_last_update
= d
.getTime();
815 return upload_speed_refresh_limiter_last_value
;
819 document
.addEventListener('DOMContentLoaded', function(event
) {
820 // Search for all datetime fields and convert the time to local timezone
821 convertAllDatetimeFields();
824 // Add copy event listeners
825 function copyLinkToClipboard(link_id
) {
826 var focus
= document
.activeElement
;
827 var e
= document
.getElementById(link_id
);
829 var tmp
= document
.createElement("textarea");
830 document
.body
.appendChild(tmp
);
831 tmp
.textContent
= e
.href
;
833 tmp
.setSelectionRange(0, tmp
.value
.length
);
834 document
.execCommand("copy");
835 document
.body
.removeChild(tmp
);
840 function addCopyListener(button_id
, link_id
) {
841 if(document
.getElementById(button_id
)){
842 document
.getElementById(button_id
)
843 .addEventListener("click", function() {
844 copyLinkToClipboard(link_id
);});
848 function copyTextToClipboard(text_id
){
849 var copyText
= document
.getElementById(text_id
);
851 copyText
.setSelectionRange(0, 99999);
852 navigator
.clipboard
.writeText(copyText
.value
);
855 function addTextCopyListener(button_id
, text_id
) {
856 if(document
.getElementById(button_id
)){
857 document
.getElementById(button_id
)
858 .addEventListener("click", function() {
859 copyTextToClipboard(text_id
);});
863 function set_dark_mode() {
864 let steel_sheet
= "<?php echo 'media/' . $cfg['dark_style'] . '/style.css.php'; ?>";
865 let shortcut_icon
= "<?php echo 'media/' . $cfg['dark_style'] . '/favicon.ico'; ?>";
866 document
.getElementById('stylesheet').href
= steel_sheet
;
867 document
.getElementById('shortcut_icon').href
= shortcut_icon
;
870 function set_light_mode() {
871 let steel_sheet
= "<?php echo 'media/' . $cfg['style'] . '/style.css.php'; ?>";
872 let shortcut_icon
= "<?php echo 'media/' . $cfg['style'] . '/favicon.ico'; ?>";
873 document
.getElementById('stylesheet').href
= steel_sheet
;
874 document
.getElementById('shortcut_icon').href
= shortcut_icon
;
877 function color_scheme_preferences() {
879 let dark_mode_steel_sheet
= "<?php echo 'media/' . $cfg['dark_style'] . '/style.css.php'; ?>"
880 if (window
.matchMedia
&& window
.matchMedia('(prefers-color-scheme: dark)').matches
) {
886 // When user change its preference
887 window
.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', lightMode
=> {
888 lightMode
.matches ?
set_dark_mode() : set_light_mode();