]> git.p6c8.net - jirafeau_project.git/blobdiff - lib/functions.js.php
[BUGFIX] admin.php password input box display not correctly
[jirafeau_project.git] / lib / functions.js.php
index 24be13fe429bfd06e74cf29d2bcbb4a508b41642..fe0b55b0f6ebe7053d032120bc7c2dd8549f1f7f 100644 (file)
  *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
  *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-define ('JIRAFEAU_ROOT', dirname (__FILE__) . '/../');
-require (JIRAFEAU_ROOT . 'lib/config.original.php');
-require (JIRAFEAU_ROOT . 'lib/settings.php');
-require (JIRAFEAU_ROOT . 'lib/functions.php');
-require (JIRAFEAU_ROOT . 'lib/lang.php');
+header('Content-Type: text/javascript');
+define('JIRAFEAU_ROOT', dirname(__FILE__) . '/../');
+
+require(JIRAFEAU_ROOT . 'lib/settings.php');
+require(JIRAFEAU_ROOT . 'lib/functions.php');
+require(JIRAFEAU_ROOT . 'lib/lang.php');
 ?>
 ?>
+// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt GPL-v3-or-Later
+var web_root = "<?php echo $cfg['web_root']; ?>";
 
 
-function translate (expr)
-{
-    var lang_array = <?php echo json_lang_generator () ?>;
-    if (lang_array.hasOwnProperty(expr))
-        return lang_array[expr];
-    return expr;
+var lang_array = <?php echo json_lang_generator(null); ?>;
+var lang_array_fallback = <?php echo json_lang_generator("en"); ?>;
+
+function translate (expr) {
+    if (lang_array.hasOwnProperty(expr)) {
+        var e = lang_array[expr];
+        if (!isEmpty(e))
+            return e;
+    }
+    if (lang_array_fallback.hasOwnProperty(expr)) {
+        var e = lang_array_fallback[expr];
+        if (!isEmpty(e))
+            return e;
+    }
+    return "FIXME: " + expr;
+}
+
+function isEmpty(str) {
+    return (!str || 0 === str.length);
+}
+
+// Extend date object with format method
+Date.prototype.format = function(format) {
+    format = format || 'YYYY-MM-DD hh:mm';
+
+    var zeropad = function(number, length) {
+        number = number.toString();
+        length = length || 2;
+        while(number.length < length)
+            number = '0' + number;
+        return number;
+    },
+    formats = {
+        YYYY: this.getFullYear(),
+        MM: zeropad(this.getMonth() + 1),
+        DD: zeropad(this.getDate()),
+        hh: zeropad(this.getHours()),
+        mm: zeropad(this.getMinutes()),
+        O: (function() {
+            localDate = new Date;
+            sign = (localDate.getTimezoneOffset() > 0) ? '-' : '+';
+            offset = Math.abs(localDate.getTimezoneOffset());
+            hours = zeropad(Math.floor(offset / 60));
+            minutes = zeropad(offset % 60);
+            return sign + hours + ":" + minutes;
+        })()
+    },
+    pattern = '(' + Object.keys(formats).join(')|(') + ')';
+
+    return format.replace(new RegExp(pattern, 'g'), function(match) {
+        return formats[match];
+    });
+};
+
+function dateFromUtcString(datestring) {
+    // matches »YYYY-MM-DD hh:mm«
+    var m = datestring.match(/(\d+)-(\d+)-(\d+)\s+(\d+):(\d+)/);
+    return new Date(Date.UTC(+m[1], +m[2] - 1, +m[3], +m[4], +m[5], 0));
+}
+
+function dateFromUtcTimestamp(datetimestamp) {
+    return new Date(parseInt(datetimestamp) * 1000)
 }
 
 }
 
-function show_link (url, reference, delete_code, crypt_key, date)
+function dateToUtcString(datelocal) {
+    return new Date(
+        datelocal.getUTCFullYear(),
+        datelocal.getUTCMonth(),
+        datelocal.getUTCDate(),
+        datelocal.getUTCHours(),
+        datelocal.getUTCMinutes(),
+        datelocal.getUTCSeconds()
+    ).format();
+}
+
+function dateToUtcTimestamp(datelocal) {
+    return (Date.UTC(
+        datelocal.getUTCFullYear(),
+        datelocal.getUTCMonth(),
+        datelocal.getUTCDate(),
+        datelocal.getUTCHours(),
+        datelocal.getUTCMinutes(),
+        datelocal.getUTCSeconds()
+    ) / 1000);
+}
+
+function convertAllDatetimeFields() {
+    datefields = document.getElementsByClassName('datetime')
+    for(var i=0; i<datefields.length; i++) {
+        dateUTC = datefields[i].getAttribute('data-datetime');
+        datefields[i].setAttribute('title', dateUTC + ' (GMT)');
+        datefields[i].innerHTML = dateFromUtcString(dateUTC).format('YYYY-MM-DD hh:mm (GMT O)');
+    }
+}
+
+function show_link (reference, delete_code, crypt_key, date)
 {
     // Upload finished
     document.getElementById('uploading').style.display = 'none';
     document.getElementById('upload').style.display = 'none';
     document.getElementById('upload_finished').style.display = '';
 {
     // Upload finished
     document.getElementById('uploading').style.display = 'none';
     document.getElementById('upload').style.display = 'none';
     document.getElementById('upload_finished').style.display = '';
-    document.title = 'Jirafeau - 100%';
+    document.title = "100% - <?php echo empty($cfg['title']) ? 'Jirafeau' : $cfg['title']; ?>";
 
     // Download page
 
     // Download page
-    var download_link = url + 'f.php?h=' + reference;
-    var download_link_href = url + 'f.php?h=' + reference;
+    var download_link_href = 'f.php?h=' + reference;
     if (crypt_key.length > 0)
     {
     if (crypt_key.length > 0)
     {
-        download_link += '&amp;k=' + crypt_key;
         download_link_href += '&k=' + crypt_key;
     }
     if (!!document.getElementById('upload_finished_download_page'))
     {
         download_link_href += '&k=' + crypt_key;
     }
     if (!!document.getElementById('upload_finished_download_page'))
     {
-        document.getElementById('upload_link').innerHTML = download_link;
         document.getElementById('upload_link').href = download_link_href;
         document.getElementById('upload_link').href = download_link_href;
+        document.getElementById('upload_link_text').innerHTML = web_root + download_link_href;
     }
 
     // Email link
     var filename = document.getElementById('file_select').files[0].name;
     }
 
     // Email link
     var filename = document.getElementById('file_select').files[0].name;
-    var b = encodeURIComponent("Download file \"" + filename + "\":") + "%0D";
-    b += encodeURIComponent(download_link_href) + "%0D";
-    if (date)
-        b += "%0D" + encodeURIComponent("This file will be available until " + date) + "%0D";
-    document.getElementById('upload_link_email').href = "mailto:?body=" + b + "&subject=" + encodeURIComponent(filename);
+    var b = encodeURIComponent("<?php echo t("DL"); ?> \"" + filename + "\":") + "%0D";
+    b += encodeURIComponent(web_root + download_link_href) + "%0D";
+    if (false == isEmpty(date))
+    {
+        b += "%0D" + encodeURIComponent("<?php echo t("VALID_UNTIL"); ?>: " + date.format('YYYY-MM-DD hh:mm (GMT O)')) + "%0D";
+        document.getElementById('upload_link_email').href = "mailto:?body=" + b + "&subject=" + encodeURIComponent(filename);
+    }
 
     // Delete link
 
     // Delete link
-    var delete_link = url + 'f.php?h=' + reference + '&amp;d=' + delete_code;
-    var delete_link_href = url + 'f.php?h=' + reference + '&d=' + delete_code;
-    document.getElementById('delete_link').innerHTML = delete_link;
+    var delete_link_href = 'f.php?h=' + reference + '&d=' + delete_code;
     document.getElementById('delete_link').href = delete_link_href;
     document.getElementById('delete_link').href = delete_link_href;
+    document.getElementById('delete_link_text').innerHTML = web_root + delete_link_href;
 
     // Validity date
 
     // Validity date
-    if (date)
+    if (isEmpty(date))
     {
     {
-        document.getElementById('date').innerHTML = date;
-        document.getElementById('validity').style.display = '';
+        document.getElementById('date').style.display = 'none';
+    }
+    else {
+        document.getElementById('date').innerHTML = '<span class="datetime" title="'
+            + dateToUtcString(date) + ' (GMT)">'
+            + date.format('YYYY-MM-DD hh:mm (GMT O)')
+            + '</span>';
+        document.getElementById('date').style.display = '';
     }
     }
-    else
-        document.getElementById('validity').style.display = 'none';
 
     // Preview link (if allowed)
     if (!!document.getElementById('preview_link'))
     {
         document.getElementById('upload_finished_preview').style.display = 'none';
 
     // Preview link (if allowed)
     if (!!document.getElementById('preview_link'))
     {
         document.getElementById('upload_finished_preview').style.display = 'none';
-        var preview_link = url + 'f.php?h=' + reference + '&amp;p=1';
-        var preview_link_href = url + 'f.php?h=' + reference + '&p=1';
+        var preview_link_href = 'f.php?h=' + reference + '&p=1';
         if (crypt_key.length > 0)
         {
         if (crypt_key.length > 0)
         {
-            preview_link += '&amp;k=' + crypt_key;
             preview_link_href += '&k=' + crypt_key;
         }
 
             preview_link_href += '&k=' + crypt_key;
         }
 
@@ -97,23 +188,20 @@ function show_link (url, reference, delete_code, crypt_key, date)
              type.indexOf("text") > -1 ||
              type.indexOf("video") > -1)
          {
              type.indexOf("text") > -1 ||
              type.indexOf("video") > -1)
          {
-            document.getElementById('preview_link').innerHTML = preview_link;
             document.getElementById('preview_link').href = preview_link_href;
             document.getElementById('preview_link').href = preview_link_href;
+            document.getElementById('preview_link_text').innerHTML = web_root + preview_link_href;
             document.getElementById('upload_finished_preview').style.display = '';
          }
     }
 
     // Direct download link
             document.getElementById('upload_finished_preview').style.display = '';
          }
     }
 
     // Direct download link
-    var direct_download_link = url + 'f.php?h=' + reference + '&amp;d=1';
-    var direct_download_link_href = url + 'f.php?h=' + reference + '&d=1';
+    var direct_download_link_href = 'f.php?h=' + reference + '&d=1';
     if (crypt_key.length > 0)
     {
     if (crypt_key.length > 0)
     {
-        direct_download_link += '&amp;k=' + crypt_key;
         direct_download_link_href += '&k=' + crypt_key;
     }
         direct_download_link_href += '&k=' + crypt_key;
     }
-    document.getElementById('direct_link').innerHTML = direct_download_link;
     document.getElementById('direct_link').href = direct_download_link_href;
     document.getElementById('direct_link').href = direct_download_link_href;
-
+    document.getElementById('direct_link_text').innerHTML = web_root + direct_download_link_href;
 
     // Hide preview and direct download link if password is set
     if (document.getElementById('input_key').value.length > 0)
 
     // Hide preview and direct download link if password is set
     if (document.getElementById('input_key').value.length > 0)
@@ -129,7 +217,7 @@ function show_upload_progression (percentage, speed, time_left)
     document.getElementById('uploaded_percentage').innerHTML = percentage;
     document.getElementById('uploaded_speed').innerHTML = speed;
     document.getElementById('uploaded_time').innerHTML = time_left;
     document.getElementById('uploaded_percentage').innerHTML = percentage;
     document.getElementById('uploaded_speed').innerHTML = speed;
     document.getElementById('uploaded_time').innerHTML = time_left;
-    document.title = 'Jirafeau - ' + percentage;
+    document.title = percentage + " - <?php echo empty($cfg['title']) ? 'Jirafeau' : $cfg['title']; ?>";
 }
 
 function hide_upload_progression ()
 }
 
 function hide_upload_progression ()
@@ -137,7 +225,7 @@ function hide_upload_progression ()
     document.getElementById('uploaded_percentage').style.display = 'none';
     document.getElementById('uploaded_speed').style.display = 'none';
     document.getElementById('uploaded_time').style.display = 'none';
     document.getElementById('uploaded_percentage').style.display = 'none';
     document.getElementById('uploaded_speed').style.display = 'none';
     document.getElementById('uploaded_time').style.display = 'none';
-    document.title = 'Jirafeau';
+    document.title = "<?php echo empty($cfg['title']) ? 'Jirafeau' : $cfg['title']; ?>";
 }
 
 function upload_progress (e)
 }
 
 function upload_progress (e)
@@ -175,12 +263,13 @@ function control_selected_file_size(max_size, error_str)
     }
     else
     {
     }
     else
     {
-        document.getElementById('options').style.display = '';
-        document.getElementById('send').style.display = '';
+        // add class to restyle upload form in next step
+        document.getElementById('upload').setAttribute('class', 'file-selected');
+        // display options
+        document.getElementById('options').style.display = 'block';
+        document.getElementById('send').style.display = 'block';
         document.getElementById('error_pop').style.display = 'none';
         document.getElementById('error_pop').style.display = 'none';
-        document.getElementById('file_select').style.left = 'inherit';
-        document.getElementById('file_select').style.height = 'inherit';
-        document.getElementById('file_select').style.opacity = '1';
+        document.getElementById('send').focus();
     }
 }
 
     }
 }
 
@@ -204,7 +293,7 @@ function add_time_string_to_date(d, time)
     {
         return false;
     }
     {
         return false;
     }
-    
+
     if (time == 'minute')
     {
         d.setSeconds (d.getSeconds() + 60);
     if (time == 'minute')
     {
         d.setSeconds (d.getSeconds() + 60);
@@ -230,6 +319,11 @@ function add_time_string_to_date(d, time)
         d.setSeconds (d.getSeconds() + 2419200);
         return true;
     }
         d.setSeconds (d.getSeconds() + 2419200);
         return true;
     }
+    if (time == 'quarter')
+    {
+        d.setSeconds (d.getSeconds() + 7257600);
+        return true;
+    }
     if (time == 'year')
     {
         d.setSeconds (d.getSeconds() + 29030400);
     if (time == 'year')
     {
         d.setSeconds (d.getSeconds() + 29030400);
@@ -238,7 +332,7 @@ function add_time_string_to_date(d, time)
     return false;
 }
 
     return false;
 }
 
-function classic_upload (url, file, time, password, one_time, upload_password)
+function classic_upload (file, time, password, one_time, upload_password)
 {
     // Delay time estimation init as we can't have file size
     upload_time_estimation_init(0);
 {
     // Delay time estimation init as we can't have file size
     upload_time_estimation_init(0);
@@ -252,24 +346,32 @@ function classic_upload (url, file, time, password, one_time, upload_password)
         if (req.readyState == 4 && req.status == 200)
         {
             var res = req.responseText;
         if (req.readyState == 4 && req.status == 200)
         {
             var res = req.responseText;
-            if (res == "Error")
+
+            // if response starts with "Error" then show a failure
+            if (/^Error/.test(res))
             {
             {
-                pop_failure ();
+                pop_failure (res);
                 return;
             }
                 return;
             }
+
             res = res.split ("\n");
             res = res.split ("\n");
+            var expiryDate = '';
             if (time != 'none')
             {
             if (time != 'none')
             {
-                var d = new Date();
-                if(!add_time_string_to_date(d, time))
+                // convert time (local time + selected expiry date)
+                var localDatetime = new Date();
+                if(!add_time_string_to_date(localDatetime, time))
+                {
+                    pop_failure ('Error: Date can not be parsed');
                     return;
                     return;
-                show_link (url, res[0], res[1], res[2], d.toString());
+                }
+                expiryDate = localDatetime;
             }
             }
-            else
-                show_link (url, res[0], res[1], res[2]);
+
+            show_link (res[0], res[1], res[2], expiryDate);
         }
     }
         }
     }
-    req.open ("POST", url + 'script.php' , true);
+    req.open ("POST", 'script.php' , true);
 
     var form = new FormData();
     form.append ("file", file);
 
     var form = new FormData();
     form.append ("file", file);
@@ -291,17 +393,15 @@ function check_html5_file_api ()
 }
 
 var async_global_transfered = 0;
 }
 
 var async_global_transfered = 0;
-var async_global_url = '';
 var async_global_file;
 var async_global_ref = '';
 var async_global_max_size = 0;
 var async_global_time;
 var async_global_transfering = 0;
 
 var async_global_file;
 var async_global_ref = '';
 var async_global_max_size = 0;
 var async_global_time;
 var async_global_transfering = 0;
 
-function async_upload_start (url, max_size, file, time, password, one_time, upload_password)
+function async_upload_start (max_size, file, time, password, one_time, upload_password)
 {
     async_global_transfered = 0;
 {
     async_global_transfered = 0;
-    async_global_url = url;
     async_global_file = file;
     async_global_max_size = max_size;
     async_global_time = time;
     async_global_file = file;
     async_global_max_size = max_size;
     async_global_time = time;
@@ -314,18 +414,20 @@ function async_upload_start (url, max_size, file, time, password, one_time, uplo
         if (req.readyState == 4 && req.status == 200)
         {
             var res = req.responseText;
         if (req.readyState == 4 && req.status == 200)
         {
             var res = req.responseText;
-            if (res == "Error")
+
+            if (/^Error/.test(res))
             {
             {
-                pop_failure ();
+                pop_failure (res);
                 return;
             }
                 return;
             }
+
             res = res.split ("\n");
             async_global_ref = res[0];
             var code = res[1];
             async_upload_push (code);
         }
     }
             res = res.split ("\n");
             async_global_ref = res[0];
             var code = res[1];
             async_upload_push (code);
         }
     }
-    req.open ("POST", async_global_url + 'script.php?init_async' , true);
+    req.open ("POST", 'script.php?init_async' , true);
 
     var form = new FormData();
     form.append ("filename", async_global_file.name);
 
     var form = new FormData();
     form.append ("filename", async_global_file.name);
@@ -383,18 +485,20 @@ function async_upload_push (code)
         if (req.readyState == 4 && req.status == 200)
         {
             var res = req.responseText;
         if (req.readyState == 4 && req.status == 200)
         {
             var res = req.responseText;
-            if (res == "Error")
+
+            if (/^Error/.test(res))
             {
             {
-                pop_failure ();
+                pop_failure (res);
                 return;
             }
                 return;
             }
+
             res = res.split ("\n");
             var code = res[0]
             async_global_transfered = async_global_transfering;
             async_upload_push (code);
         }
     }
             res = res.split ("\n");
             var code = res[0]
             async_global_transfered = async_global_transfering;
             async_upload_push (code);
         }
     }
-    req.open ("POST", async_global_url + 'script.php?push_async' , true);
+    req.open ("POST", 'script.php?push_async' , true);
 
     var chunk_size = parseInt (async_global_max_size * 0.50);
     var start = async_global_transfered;
 
     var chunk_size = parseInt (async_global_max_size * 0.50);
     var start = async_global_transfered;
@@ -421,24 +525,30 @@ function async_upload_end (code)
         if (req.readyState == 4 && req.status == 200)
         {
             var res = req.responseText;
         if (req.readyState == 4 && req.status == 200)
         {
             var res = req.responseText;
-            if (res == "Error")
+
+            if (/^Error/.test(res))
             {
             {
-                pop_failure ();
+                pop_failure (res);
                 return;
             }
                 return;
             }
+
             res = res.split ("\n");
             res = res.split ("\n");
+            var expiryDate = '';
             if (async_global_time != 'none')
             {
             if (async_global_time != 'none')
             {
-                var d = new Date();
-                if(!add_time_string_to_date(d, async_global_time))
-                    return;
-                show_link (async_global_url, res[0], res[1], res[2], d.toString());
+              // convert time (local time + selected expiry date)
+              var localDatetime = new Date();
+              if(!add_time_string_to_date(localDatetime, async_global_time)) {
+                pop_failure ('Error: Date can not be parsed');
+                return;
+              }
+              expiryDate = localDatetime;
             }
             }
-            else
-                show_link (async_global_url, res[0], res[1], res[2]);
+
+            show_link (res[0], res[1], res[2], expiryDate);
         }
     }
         }
     }
-    req.open ("POST", async_global_url + 'script.php?end_async' , true);
+    req.open ("POST", 'script.php?end_async' , true);
 
     var form = new FormData();
     form.append ("ref", async_global_ref);
 
     var form = new FormData();
     form.append ("ref", async_global_ref);
@@ -446,12 +556,12 @@ function async_upload_end (code)
     req.send (form);
 }
 
     req.send (form);
 }
 
-function upload (url, max_size)
+function upload (max_size)
 {
     if (check_html5_file_api ()
         && document.getElementById('file_select').files[0].size >= max_size)
     {
 {
     if (check_html5_file_api ()
         && document.getElementById('file_select').files[0].size >= max_size)
     {
-        async_upload_start (url,
+        async_upload_start (
             max_size,
             document.getElementById('file_select').files[0],
             document.getElementById('select_time').value,
             max_size,
             document.getElementById('file_select').files[0],
             document.getElementById('select_time').value,
@@ -462,7 +572,7 @@ function upload (url, max_size)
     }
     else
     {
     }
     else
     {
-        classic_upload (url,
+        classic_upload (
             document.getElementById('file_select').files[0],
             document.getElementById('select_time').value,
             document.getElementById('input_key').value,
             document.getElementById('file_select').files[0],
             document.getElementById('select_time').value,
             document.getElementById('input_key').value,
@@ -511,17 +621,17 @@ function upload_time_estimation_speed_string()
     if (s <= 1000)
     {
         res = s.toString();
     if (s <= 1000)
     {
         res = s.toString();
-        scale = "o/s";
+        scale = "Bit/s";
     }
     else if (s < 1000000)
     {
         res = Math.floor(s/100) / 10;
     }
     else if (s < 1000000)
     {
         res = Math.floor(s/100) / 10;
-        scale = "Ko/s";
+        scale = "KBit/s";
     }
     else
     {
         res = Math.floor(s/100000) / 10;
     }
     else
     {
         res = Math.floor(s/100000) / 10;
-        scale = "Mo/s";
+        scale = "Mbit/s";
     }
     if (res == 0)
         return '';
     }
     if (res == 0)
         return '';
@@ -531,31 +641,31 @@ function upload_time_estimation_speed_string()
 function milliseconds_to_time_string (milliseconds)
 {
     function numberEnding (number) {
 function milliseconds_to_time_string (milliseconds)
 {
     function numberEnding (number) {
-        return (number > 1) ? 's' : '';
+        return (number > 1) ? translate ('PLURAL_ENDING') : '';
     }
 
     var temp = Math.floor(milliseconds / 1000);
     var years = Math.floor(temp / 31536000);
     if (years) {
     }
 
     var temp = Math.floor(milliseconds / 1000);
     var years = Math.floor(temp / 31536000);
     if (years) {
-        return years + ' ' + translate ('year') + numberEnding(years);
+        return years + ' ' + translate ('YEAR') + numberEnding(years);
     }
     var days = Math.floor((temp %= 31536000) / 86400);
     if (days) {
     }
     var days = Math.floor((temp %= 31536000) / 86400);
     if (days) {
-        return days + ' ' + translate ('day') + numberEnding(days);
+        return days + ' ' + translate ('DAY') + numberEnding(days);
     }
     var hours = Math.floor((temp %= 86400) / 3600);
     if (hours) {
     }
     var hours = Math.floor((temp %= 86400) / 3600);
     if (hours) {
-        return hours + ' ' + translate ('hour') + numberEnding(hours);
+        return hours + ' ' + translate ('HOUR') + numberEnding(hours);
     }
     var minutes = Math.floor((temp %= 3600) / 60);
     if (minutes) {
     }
     var minutes = Math.floor((temp %= 3600) / 60);
     if (minutes) {
-        return minutes + ' ' + translate ('minute') + numberEnding(minutes);
+        return minutes + ' ' + translate ('MINUTE') + numberEnding(minutes);
     }
     var seconds = temp % 60;
     if (seconds) {
     }
     var seconds = temp % 60;
     if (seconds) {
-        return seconds + ' ' + translate ('second') + numberEnding(seconds);
+        return seconds + ' ' + translate ('SECOND') + numberEnding(seconds);
     }
     }
-    return translate ('less than a second');
+    return translate ('LESS_1_SEC');
 }
 
 function upload_time_estimation_time()
 }
 
 function upload_time_estimation_time()
@@ -608,3 +718,32 @@ function upload_speed_refresh_limiter(speed_str)
     }
     return upload_speed_refresh_limiter_last_value;
 }
     }
     return upload_speed_refresh_limiter_last_value;
 }
+
+// document.ready()
+document.addEventListener('DOMContentLoaded', function(event) {
+    // Search for all datetime fields and convert the time to local timezone
+    convertAllDatetimeFields();
+});
+
+// Add copy event listeners
+function copyLinkToClipboard(link_id) {
+    var focus = document.activeElement;
+    var e = document.getElementById(link_id);
+
+    var tmp = document.createElement("textarea");
+    document.body.appendChild(tmp);
+    tmp.textContent = e.href;
+    tmp.focus();
+    tmp.setSelectionRange(0, tmp.value.length);
+    document.execCommand("copy");
+    document.body.removeChild(tmp);
+
+    focus.focus();
+}
+
+function addCopyListener(button_id, link_id) {
+    document.getElementById(button_id)
+            .addEventListener("click", function() {
+                copyLinkToClipboard(link_id);});
+}
+// @license-end

patrick-canterino.de