2 commits - plugins/calendar plugins/libkolab

Thomas Brüderli bruederli at kolabsys.com
Tue Mar 24 11:55:39 CET 2015


 plugins/calendar/calendar.php                        |    5 
 plugins/calendar/calendar_ui.js                      |  164 ++-------------
 plugins/calendar/lib/calendar_ui.php                 |    1 
 plugins/calendar/localization/ca_ES.inc              |    4 
 plugins/calendar/localization/cs_CZ.inc              |    4 
 plugins/calendar/localization/da_DK.inc              |    4 
 plugins/calendar/localization/de_DE.inc              |    8 
 plugins/calendar/localization/en_US.inc              |    4 
 plugins/calendar/localization/es_AR.inc              |    4 
 plugins/calendar/localization/fi_FI.inc              |    7 
 plugins/calendar/localization/fr_FR.inc              |    4 
 plugins/calendar/localization/he.inc                 |    4 
 plugins/calendar/localization/hr.inc                 |    4 
 plugins/calendar/localization/it_IT.inc              |    4 
 plugins/calendar/localization/pl_PL.inc              |    4 
 plugins/calendar/localization/pt_PT.inc              |    4 
 plugins/calendar/localization/ru_RU.inc              |    4 
 plugins/calendar/localization/sl.inc                 |    4 
 plugins/calendar/localization/sv_SE.inc              |    4 
 plugins/calendar/localization/th.inc                 |    5 
 plugins/calendar/localization/uk.inc                 |    1 
 plugins/calendar/localization/vi.inc                 |    5 
 plugins/calendar/localization/vi_VN.inc              |    4 
 plugins/calendar/localization/zh_TW.inc              |    5 
 plugins/calendar/skins/larry/calendar.css            |   28 +-
 plugins/calendar/skins/larry/templates/calendar.html |    2 
 plugins/libkolab/js/audittrail.js                    |  203 +++++++++++++++++++
 27 files changed, 290 insertions(+), 204 deletions(-)

New commits:
commit 8a74c132d8469169d909e6fceaa185f3b7002de5
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Tue Mar 24 11:55:32 2015 +0100

    Move some audit trail functions to libkolab for shared use

diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php
index 3aa0bd6..53d3f20 100644
--- a/plugins/calendar/calendar.php
+++ b/plugins/calendar/calendar.php
@@ -1057,11 +1057,12 @@ class calendar extends rcube_plugin
         $data = $this->driver->get_event_changelog($event);
         if (is_array($data) && !empty($data)) {
           $lib = $this->lib;
-          array_walk($data, function(&$change) use ($lib) {
+          $dtformat = $this->rc->config->get('date_format') . ' ' . $this->rc->config->get('time_format');
+          array_walk($data, function(&$change) use ($lib, $dtformat) {
             if ($change['date']) {
               $dt = $lib->adjust_timezone($change['date']);
               if ($dt instanceof DateTime)
-                $change['date'] = $dt->format('c');
+                $change['date'] = $this->rc->format_date($dt, $dtformat, false);
             }
           });
           $this->rc->output->command('plugin.render_event_changelog', $data);
diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js
index 835873b..6c26e5a 100644
--- a/plugins/calendar/calendar_ui.js
+++ b/plugins/calendar/calendar_ui.js
@@ -1018,119 +1018,33 @@ function rcube_calendar_ui(settings)
     // show event changelog in a dialog
     var event_history_dialog = function(event)
     {
-      if (!event.id)
+      if (!event.id || !window.libkolab_audittrail)
         return false
 
       // render dialog
-      var $dialog = $('#eventhistory');
-
-      // close show dialog first
-      if ($dialog.is(':ui-dialog'))
-        $dialog.dialog('close');
-
-      var buttons = {};
-      buttons[rcmail.gettext('close', 'calendar')] = function() {
-        $dialog.dialog('close');
-      };
-
-      // hide and reset changelog table
-      $dialog.find('div.event-dialog-message').remove();
-      $('#event-changelog-table').show().children('tbody')
-        .html('<tr><td colspan="6"><span class="loading">'+ rcmail.gettext('loading') +'</span></td></tr>');
-
-      // open jquery UI dialog
-      $dialog.dialog({
-        modal: false,
-        resizable: true,
-        closeOnEscape: true,
+      var $dialog = libkolab_audittrail.object_history_dialog({
+        module: 'calendar',
+        container: '#eventhistory',
         title: rcmail.gettext('eventchangelog','calendar') + ' - ' + event.title + ', ' + me.event_date_text(event),
-        open: function() {
-          $dialog.attr('aria-hidden', 'false');
-          setTimeout(function(){
-            $dialog.parent().find('.ui-button:not(.ui-dialog-titlebar-close)').first().focus();
-          }, 5);
-        },
-        close: function() {
-          $dialog.dialog('destroy').attr('aria-hidden', 'true').hide();
+
+        // callback function for list actions
+        listfunc: function(action, rev) {
+          me.loading_lock = rcmail.set_busy(true, 'loading', me.loading_lock);
+          rcmail.http_post('event', { action:action, e:{ id:event.id, calendar:event.calendar, rev: rev } }, me.loading_lock);
         },
-        buttons: buttons,
-        minWidth: 450,
-        width: 650,
-        height: 350,
-        minHeight: 200,
-      })
-      .data('event', event)
-      .show().children('.compare-button').hide();
 
-      // set dialog size according to content
-      // me.dialog_resize($dialog.get(0), $dialog.height(), 650);
+        // callback function for comparing two object revisions
+        comparefunc: function(rev1, rev2) {
+          me.loading_lock = rcmail.set_busy(true, 'loading', me.loading_lock);
+          rcmail.http_post('event', { action:'diff', e:{ id:event.id, calendar:event.calendar, rev1: rev1, rev2: rev2 } }, me.loading_lock);
+        }
+      });
+
+      $dialog.data('event', event);
 
       // fetch changelog data
       me.loading_lock = rcmail.set_busy(true, 'loading', me.loading_lock);
       rcmail.http_post('event', { action:'changelog', e:{ id:event.id, calendar:event.calendar } }, me.loading_lock);
-
-      // initialize event handlers for history dialog UI elements
-      if (!$dialog.data('initialized')) {
-        // compare button
-        $dialog.find('.compare-button input').click(function(e) {
-          var rev1 = $('#event-changelog-table input.diff-rev1:checked').val(),
-            rev2 = $('#event-changelog-table input.diff-rev2:checked').val(),
-            event = $('#eventhistory').data('event');
-
-            if (rev1 && rev2 && rev1 != rev2) {
-              // swap revisions if the user got it wrong
-              if (rev1 > rev2) {
-                var tmp = rev2;
-                rev2 = rev1;
-                rev1 = tmp;
-              }
-
-              me.loading_lock = rcmail.set_busy(true, 'loading', me.loading_lock);
-              rcmail.http_post('event', { action:'diff', e:{ id:event.id, calendar:event.calendar, rev1: rev1, rev2: rev2 } }, me.loading_lock);
-            }
-            else {
-              alert('Invalid selection!')
-            }
-        });
-
-        // delegate handlers for list actions
-        $('#event-changelog-table tbody').on('click', 'td.actions a', function(e) {
-          var link = $(this),
-            action = link.hasClass('restore') ? 'restore' : 'show',
-            event = $('#eventhistory').data('event'),
-            rev = link.attr('data-rev');
-
-            // ignore clicks on first row (current revision)
-            if (link.closest('tr').hasClass('first')) {
-              return false;
-            }
-
-            // let the user confirm the restore action
-            if (action == 'restore' && !confirm(rcmail.gettext('eventrestoreconfirm','calendar').replace('$rev', rev))) {
-              return false;
-            }
-
-            me.loading_lock = rcmail.set_busy(true, 'loading', me.loading_lock);
-            rcmail.http_post('event', { action:action, e:{ id:event.id, calendar:event.calendar, rev: rev } }, me.loading_lock);
-            return false;
-        })
-        .on('click', 'input.diff-rev1', function(e) {
-          if (!this.checked) return true;
-
-          var rev1 = this.value, selection_valid = false;
-          $('#event-changelog-table input.diff-rev2').each(function(i, elem) {
-            $(elem).prop('disabled', elem.value <= rev1);
-            if (elem.checked && elem.value > rev1) {
-              selection_valid = true;
-            }
-          });
-          if (!selection_valid) {
-            $('#event-changelog-table input.diff-rev2:not([disabled])').last().prop('checked', true);
-          }
-        });
-
-        $dialog.data('initialized', true);
-      }
     };
 
     // callback from server with changelog data
@@ -1139,48 +1053,14 @@ function rcube_calendar_ui(settings)
       var $dialog = $('#eventhistory'),
         event = $dialog.data('event');
 
-      if (data === false || !data.length) {
+      if (data === false || !data.length || !event) {
         // display 'unavailable' message
-        $('<div class="event-dialog-message warning">'+ rcmail.gettext('eventchangelognotavailable','calendar') +'</div>')
-          .insertBefore($('#event-changelog-table').hide());
-        return
-      }
-
-      var i, change, accessible, op_append, first = data.length -1, last = 0,
-        op_labels = { APPEND: 'actionappend', MOVE: 'actionmove', DELETE: 'actiondelete' },
-        is_writeable = !!me.calendars[event.calendar].editable,
-        actions = '<a href="#show" class="iconbutton preview" title="'+ rcmail.gettext('showrevision','calendar') +'" data-rev="{rev}" /> ' +
-          (is_writeable ? '<a href="#restore" class="iconbutton restore" title="'+ rcmail.gettext('restore','calendar') + '" data-rev="{rev}" />' : ''),
-        tbody = $('#event-changelog-table tbody').html('');
-
-      for (i=first; i >= 0; i--) {
-        change = data[i];
-        accessible = change.date && change.user;
-
-        if (change.op == 'MOVE' && change.mailbox) {
-          op_append = ' ⇢ ' + change.mailbox;
-        }
-        else {
-          op_append = '';
-        }
-
-        $('<tr class="' + (i == first ? 'first' : (i == last ? 'last' : '')) + (accessible ? '' : 'undisclosed') + '">')
-          .append('<td class="diff">' + (accessible && change.op != 'DELETE' ? 
-            '<input type="radio" name="rev1" class="diff-rev1" value="' + change.rev + '" title="" '+ (i == last ? 'checked="checked"' : '') +' /> '+
-            '<input type="radio" name="rev2" class="diff-rev2" value="' + change.rev + '" title="" '+ (i == first ? 'checked="checked"' : '') +' /></td>'
-            : ''))
-          .append('<td class="revision">' + Q(i+1) + '</td>')
-          .append('<td class="date">' + Q(change.date ? format_datetime(parseISO8601(change.date)) : '') + '</td>')
-          .append('<td class="user">' + Q(change.user || 'undisclosed') + '</td>')
-          .append('<td class="operation" title="' + op_append + '">' + Q(rcmail.gettext(op_labels[change.op] || '', 'calendar') + (op_append ? ' ...' : '')) + '</td>')
-          .append('<td class="actions">' + (accessible && change.op != 'DELETE' ? actions.replace(/\{rev\}/g, change.rev) : '') + '</td>')
-          .appendTo(tbody);
+        $('<div class="notfound-message event-dialog-message warning">' + rcmail.gettext('objectchangelognotavailable','calendar') + '</div>')
+          .insertBefore($dialog.find('.changelog-table').hide());
+        return;
       }
 
-      if (first > 0) {
-        $('#eventhistory .compare-button').fadeIn(200);
-        $('#event-changelog-table tr.last input.diff-rev1').click();
-      }
+      libkolab_audittrail.render_changelog(data, event, me.calendars[event.calendar]);
 
       // set dialog size according to content
       me.dialog_resize($dialog.get(0), $dialog.height(), 600);
diff --git a/plugins/calendar/lib/calendar_ui.php b/plugins/calendar/lib/calendar_ui.php
index 9e31f78..5a1f41e 100644
--- a/plugins/calendar/lib/calendar_ui.php
+++ b/plugins/calendar/lib/calendar_ui.php
@@ -121,6 +121,7 @@ class calendar_ui
     // include kolab folderlist widget if available
     if (in_array('libkolab', $this->cal->api->loaded_plugins())) {
         $this->cal->api->include_script('libkolab/js/folderlist.js');
+        $this->cal->api->include_script('libkolab/js/audittrail.js');
     }
 
     jqueryui::miniColors();
diff --git a/plugins/calendar/localization/ca_ES.inc b/plugins/calendar/localization/ca_ES.inc
index 4318eba..d3c5ff9 100644
--- a/plugins/calendar/localization/ca_ES.inc
+++ b/plugins/calendar/localization/ca_ES.inc
@@ -250,9 +250,9 @@ $labels['compare'] = 'Compara';
 $labels['showrevision'] = 'Mostra aquesta versió';
 $labels['restore'] = 'Restaura aquesta versió';
 $labels['eventnotfound'] = 'No s\'han pogut carregar les dades d\'aquest esdeveniment';
-$labels['eventchangelognotavailable'] = 'No està disponible canviar l\'historial d\'aquest esdeveniment';
+$labels['objectchangelognotavailable'] = 'No està disponible canviar l\'historial d\'aquest esdeveniment';
 $labels['eventdiffnotavailable'] = 'No és possible comparar les revisions seleccionades';
-$labels['eventrestoreconfirm'] = 'Esteu segurs de voler restaurar la revisió $rev d\'aquest esdeveniment? Això substituirà l\'actual esdeveniment per una versió antiga.';
+$labels['revisionrestoreconfirm'] = 'Esteu segurs de voler restaurar la revisió $rev d\'aquest esdeveniment? Això substituirà l\'actual esdeveniment per una versió antiga.';
 $labels['arialabelminical'] = 'Selecció de la data del calendari';
 $labels['arialabelcalendarview'] = 'Vista del calendari';
 $labels['arialabelsearchform'] = 'Formulari per cercar esdeveniments';
diff --git a/plugins/calendar/localization/cs_CZ.inc b/plugins/calendar/localization/cs_CZ.inc
index 9b03cd9..1ed6cf3 100644
--- a/plugins/calendar/localization/cs_CZ.inc
+++ b/plugins/calendar/localization/cs_CZ.inc
@@ -257,9 +257,9 @@ $labels['compare'] = 'Porovnat';
 $labels['showrevision'] = 'Ukázat tuto verzi';
 $labels['restore'] = 'Obnovit tuto verzi';
 $labels['eventnotfound'] = 'Nepodařilo se nahrát data události';
-$labels['eventchangelognotavailable'] = 'Historie změn není pro tuto událost dostupná';
+$labels['objectchangelognotavailable'] = 'Historie změn není pro tuto událost dostupná';
 $labels['eventdiffnotavailable'] = 'Pro vybrané verze není žádné srovnání možné';
-$labels['eventrestoreconfirm'] = 'Opravdu chcete obnovit změnu $rev této události? Tímto dojde k nahrazení nynější události starou verzí.';
+$labels['revisionrestoreconfirm'] = 'Opravdu chcete obnovit změnu $rev této události? Tímto dojde k nahrazení nynější události starou verzí.';
 $labels['arialabelminical'] = 'Výběr data v kalendáři';
 $labels['arialabelcalendarview'] = 'Pohled na kalendář';
 $labels['arialabelsearchform'] = 'Hledání události';
diff --git a/plugins/calendar/localization/da_DK.inc b/plugins/calendar/localization/da_DK.inc
index fcfe5cc..05c9b71 100644
--- a/plugins/calendar/localization/da_DK.inc
+++ b/plugins/calendar/localization/da_DK.inc
@@ -258,9 +258,9 @@ $labels['compare'] = 'Sammenlign';
 $labels['showrevision'] = 'Vis denne version';
 $labels['restore'] = 'Genskab denne version';
 $labels['eventnotfound'] = 'Kunne ikke indlæse begivenhedsdata';
-$labels['eventchangelognotavailable'] = 'Ændringshistorikken er ikke tilgængelig for denne begivenhed';
+$labels['objectchangelognotavailable'] = 'Ændringshistorikken er ikke tilgængelig for denne begivenhed';
 $labels['eventdiffnotavailable'] = 'Det er ikke muligt at sammenligne de valgte revisioner';
-$labels['eventrestoreconfirm'] = 'Sikker på at du vil genskabe revision $rev af denne begivenhed? Dette vil erstatte den nuværende begivenhed med den tidligere version.';
+$labels['revisionrestoreconfirm'] = 'Sikker på at du vil genskabe revision $rev af denne begivenhed? Dette vil erstatte den nuværende begivenhed med den tidligere version.';
 $labels['arialabelminical'] = 'Valg af kalenderdato';
 $labels['arialabelcalendarview'] = 'Kalendervisning';
 $labels['arialabelsearchform'] = 'Søgeformular for begivenheder';
diff --git a/plugins/calendar/localization/de_DE.inc b/plugins/calendar/localization/de_DE.inc
index 15af6b7..ab5a5af 100644
--- a/plugins/calendar/localization/de_DE.inc
+++ b/plugins/calendar/localization/de_DE.inc
@@ -259,9 +259,9 @@ $labels['compare'] = 'Vergleichen';
 $labels['showrevision'] = 'Diese Version anzeigen';
 $labels['restore'] = 'Diese Version wiederherstellen';
 $labels['eventnotfound'] = 'Termindaten sind leider nicht vergübar';
-$labels['eventchangelognotavailable'] = 'Änderungshistorie ist nicht verfügbar für diesen Termin';
+$labels['objectchangelognotavailable'] = 'Änderungshistorie ist nicht verfügbar für diesen Termin';
 $labels['eventdiffnotavailable'] = 'Vergleich für die gewählten Versionen nicht möglich';
-$labels['eventrestoreconfirm'] = 'Wollen Sie wirklich die Version $rev dieses Termins wiederherstellen? Diese Aktion wird die aktuelle Kopie mit der älteren Version ersetzen.';
+$labels['revisionrestoreconfirm'] = 'Wollen Sie wirklich die Version $rev dieses Termins wiederherstellen? Diese Aktion wird die aktuelle Kopie mit der älteren Version ersetzen.';
 $labels['eventrestoresuccess'] = 'Revision $rev erfolgreich wiederhergestellt';
 $labels['eventrestoreerror'] = 'Fehler beim Wiederherstellen der alten Revision';
 $labels['arialabelminical'] = 'Kalender Datumswahl';
diff --git a/plugins/calendar/localization/en_US.inc b/plugins/calendar/localization/en_US.inc
index 046115b..3a15b6f 100644
--- a/plugins/calendar/localization/en_US.inc
+++ b/plugins/calendar/localization/en_US.inc
@@ -288,9 +288,9 @@ $labels['compare'] = 'Compare';
 $labels['showrevision'] = 'Show this version';
 $labels['restore'] = 'Restore this version';
 $labels['eventnotfound'] = 'Failed to load event data';
-$labels['eventchangelognotavailable'] = 'Change history is not available for this event';
+$labels['objectchangelognotavailable'] = 'Change history is not available for this event';
 $labels['eventdiffnotavailable'] = 'No comparison possible for the selected revisions';
-$labels['eventrestoreconfirm'] = 'Do you really want to restore revision $rev of this event? This will replace the current event with the old version.';
+$labels['revisionrestoreconfirm'] = 'Do you really want to restore revision $rev of this event? This will replace the current event with the old version.';
 $labels['eventrestoresuccess'] = 'Revision $rev successfully restored';
 $labels['eventrestoreerror'] = 'Failed to restore the old revision';
 
diff --git a/plugins/calendar/localization/es_AR.inc b/plugins/calendar/localization/es_AR.inc
index a22ea03..1bb9b51 100644
--- a/plugins/calendar/localization/es_AR.inc
+++ b/plugins/calendar/localization/es_AR.inc
@@ -253,9 +253,9 @@ $labels['compare'] = 'Comparar';
 $labels['showrevision'] = 'Mostrar esta versión';
 $labels['restore'] = 'Recuperar esta versión';
 $labels['eventnotfound'] = 'Fallo al cargar datos del evento';
-$labels['eventchangelognotavailable'] = 'Cambiar historial no esta disponible para este evento';
+$labels['objectchangelognotavailable'] = 'Cambiar historial no esta disponible para este evento';
 $labels['eventdiffnotavailable'] = 'No es posible comparar las revisiones seleccionadas';
-$labels['eventrestoreconfirm'] = 'Confirme que quiere recuperar la revisión $rev de este evento. Esta acción reemplazará el evento actual con la versión anterior.';
+$labels['revisionrestoreconfirm'] = 'Confirme que quiere recuperar la revisión $rev de este evento. Esta acción reemplazará el evento actual con la versión anterior.';
 $labels['arialabelminical'] = 'Selección de fecha del calendario';
 $labels['arialabelcalendarview'] = 'Vista del calendario';
 $labels['arialabelsearchform'] = 'Formulario de búsqueda de evento';
diff --git a/plugins/calendar/localization/fi_FI.inc b/plugins/calendar/localization/fi_FI.inc
index a3c0f9f..35d1065 100644
--- a/plugins/calendar/localization/fi_FI.inc
+++ b/plugins/calendar/localization/fi_FI.inc
@@ -255,9 +255,9 @@ $labels['compare'] = 'Vertaa';
 $labels['showrevision'] = 'Näytä tämä versio';
 $labels['restore'] = 'Palauta tämä versio';
 $labels['eventnotfound'] = 'Tapahtumadatan lataus epäonnistui';
-$labels['eventchangelognotavailable'] = 'Tapahtuman muutoshistoria ei ole saatavilla';
+$labels['objectchangelognotavailable'] = 'Tapahtuman muutoshistoria ei ole saatavilla';
 $labels['eventdiffnotavailable'] = 'Vertailu ei ole saatavilla valittujen versioiden välillä';
-$labels['eventrestoreconfirm'] = 'Haluatko varmasti palauttaa tämän tapahtuman version $rev? Nykyinen tapahtuma korvataan vanhalla versiolla.';
+$labels['revisionrestoreconfirm'] = 'Haluatko varmasti palauttaa tämän tapahtuman version $rev? Nykyinen tapahtuma korvataan vanhalla versiolla.';
 $labels['eventrestoresuccess'] = 'Versio $rev palautettiin onnistuneesti';
 $labels['eventrestoreerror'] = 'Vanhan version palauttaminen epäonnistui';
 $labels['arialabelminical'] = 'Kalenterin ajankohdan valinta';
diff --git a/plugins/calendar/localization/fr_FR.inc b/plugins/calendar/localization/fr_FR.inc
index 871a9ab..076a7d6 100644
--- a/plugins/calendar/localization/fr_FR.inc
+++ b/plugins/calendar/localization/fr_FR.inc
@@ -255,9 +255,9 @@ $labels['compare'] = 'Comparer';
 $labels['showrevision'] = 'Afficher cette version';
 $labels['restore'] = 'Restaurer cette version';
 $labels['eventnotfound'] = 'Impossible de charger les données de l’évènement';
-$labels['eventchangelognotavailable'] = 'Il n\'y a pas d\'historique des modifications pour cet évènement';
+$labels['objectchangelognotavailable'] = 'Il n\'y a pas d\'historique des modifications pour cet évènement';
 $labels['eventdiffnotavailable'] = 'La comparaison des versions sélectionnées est impossible';
-$labels['eventrestoreconfirm'] = 'Voulez-vous vraiment restaurer le version $rev de cet évènement ? Cette action va remplacer l\'évènement courent  par l\'ancienne version.';
+$labels['revisionrestoreconfirm'] = 'Voulez-vous vraiment restaurer le version $rev de cet évènement ? Cette action va remplacer l\'évènement courent  par l\'ancienne version.';
 $labels['arialabelminical'] = 'Sélection de la date du calendrier';
 $labels['arialabelcalendarview'] = 'Vue du calendrier';
 $labels['arialabelsearchform'] = 'Recherche d\'évènements depuis';
diff --git a/plugins/calendar/localization/he.inc b/plugins/calendar/localization/he.inc
index 6a5284a..ae0698b 100644
--- a/plugins/calendar/localization/he.inc
+++ b/plugins/calendar/localization/he.inc
@@ -255,9 +255,9 @@ $labels['compare'] = 'Compare';
 $labels['showrevision'] = 'Show this version';
 $labels['restore'] = 'Restore this version';
 $labels['eventnotfound'] = 'Failed to load event data';
-$labels['eventchangelognotavailable'] = 'Change history is not available for this event';
+$labels['objectchangelognotavailable'] = 'Change history is not available for this event';
 $labels['eventdiffnotavailable'] = 'No comparison possible for the selected revisions';
-$labels['eventrestoreconfirm'] = 'Do you really want to restore revision $rev of this event? This will replace the current event with the old version.';
+$labels['revisionrestoreconfirm'] = 'Do you really want to restore revision $rev of this event? This will replace the current event with the old version.';
 $labels['arialabelminical'] = 'Calendar date selection';
 $labels['arialabelcalendarview'] = 'Calendar view';
 $labels['arialabelsearchform'] = 'Event search form';
diff --git a/plugins/calendar/localization/hr.inc b/plugins/calendar/localization/hr.inc
index d622f75..309ef90 100644
--- a/plugins/calendar/localization/hr.inc
+++ b/plugins/calendar/localization/hr.inc
@@ -255,9 +255,9 @@ $labels['compare'] = 'Compare';
 $labels['showrevision'] = 'Show this version';
 $labels['restore'] = 'Restore this version';
 $labels['eventnotfound'] = 'Failed to load event data';
-$labels['eventchangelognotavailable'] = 'Change history is not available for this event';
+$labels['objectchangelognotavailable'] = 'Change history is not available for this event';
 $labels['eventdiffnotavailable'] = 'No comparison possible for the selected revisions';
-$labels['eventrestoreconfirm'] = 'Do you really want to restore revision $rev of this event? This will replace the current event with the old version.';
+$labels['revisionrestoreconfirm'] = 'Do you really want to restore revision $rev of this event? This will replace the current event with the old version.';
 $labels['arialabelminical'] = 'Calendar date selection';
 $labels['arialabelcalendarview'] = 'Calendar view';
 $labels['arialabelsearchform'] = 'Event search form';
diff --git a/plugins/calendar/localization/it_IT.inc b/plugins/calendar/localization/it_IT.inc
index 64a22cb..78b6a05 100644
--- a/plugins/calendar/localization/it_IT.inc
+++ b/plugins/calendar/localization/it_IT.inc
@@ -257,9 +257,9 @@ $labels['compare'] = 'Confronta';
 $labels['showrevision'] = 'Mostra questa versione';
 $labels['restore'] = 'Rirpistina questa versione';
 $labels['eventnotfound'] = 'Caricamento dati dell\'evento fallito';
-$labels['eventchangelognotavailable'] = 'Lo storico modifiche non è disponibile per questo evento';
+$labels['objectchangelognotavailable'] = 'Lo storico modifiche non è disponibile per questo evento';
 $labels['eventdiffnotavailable'] = 'Nessun confronto possibile tra le revisioni selezionate';
-$labels['eventrestoreconfirm'] = 'Vuoi veramente ripristinare la revisione $rev di questo evento? L\'evento corrente verrà sostituito dalla vecchia versione.';
+$labels['revisionrestoreconfirm'] = 'Vuoi veramente ripristinare la revisione $rev di questo evento? L\'evento corrente verrà sostituito dalla vecchia versione.';
 $labels['arialabelminical'] = 'Selezione della data del calendario';
 $labels['arialabelcalendarview'] = 'Vista calendario';
 $labels['arialabelsearchform'] = 'Modulo ricerca evento';
diff --git a/plugins/calendar/localization/pl_PL.inc b/plugins/calendar/localization/pl_PL.inc
index 8a0db8a..4495e2f 100644
--- a/plugins/calendar/localization/pl_PL.inc
+++ b/plugins/calendar/localization/pl_PL.inc
@@ -256,9 +256,9 @@ $labels['compare'] = 'Porównaj';
 $labels['showrevision'] = 'Pokaż tą wersję';
 $labels['restore'] = 'Przywróć tą wersję';
 $labels['eventnotfound'] = 'Nie udało się wczytać zdarzenia';
-$labels['eventchangelognotavailable'] = 'Historia zmian jest niedostępna dla tego zdarzenia';
+$labels['objectchangelognotavailable'] = 'Historia zmian jest niedostępna dla tego zdarzenia';
 $labels['eventdiffnotavailable'] = 'Nie można porównać wybranych wersji';
-$labels['eventrestoreconfirm'] = 'Czy na pewno chcesz przywrócić wersję $rev tego zdarzenia? Bierzące zdarzenie zostanie zastąpione starszą wersją.';
+$labels['revisionrestoreconfirm'] = 'Czy na pewno chcesz przywrócić wersję $rev tego zdarzenia? Bierzące zdarzenie zostanie zastąpione starszą wersją.';
 $labels['arialabelminical'] = 'Wybór daty kalendarza';
 $labels['arialabelcalendarview'] = 'PodglÄ…d kalendarza';
 $labels['arialabelsearchform'] = 'Formularz wyszukiwania zdarzeń';
diff --git a/plugins/calendar/localization/pt_PT.inc b/plugins/calendar/localization/pt_PT.inc
index 75ab307..9cd0006 100644
--- a/plugins/calendar/localization/pt_PT.inc
+++ b/plugins/calendar/localization/pt_PT.inc
@@ -258,9 +258,9 @@ $labels['compare'] = 'Comparar';
 $labels['showrevision'] = 'Mostrar esta versão';
 $labels['restore'] = 'Restaurar esta versão';
 $labels['eventnotfound'] = 'Falha ao ler os dados do evento';
-$labels['eventchangelognotavailable'] = 'Não é possível alterar o histórico deste evento';
+$labels['objectchangelognotavailable'] = 'Não é possível alterar o histórico deste evento';
 $labels['eventdiffnotavailable'] = 'Não é possível comparar as revisões selecionadas';
-$labels['eventrestoreconfirm'] = 'Confirma o restauro da revisão $rev deste evento? Os dados atuais serão substituídos pelos da versão anterior.';
+$labels['revisionrestoreconfirm'] = 'Confirma o restauro da revisão $rev deste evento? Os dados atuais serão substituídos pelos da versão anterior.';
 $labels['arialabelminical'] = 'Seleção da data do calendário';
 $labels['arialabelcalendarview'] = 'Vista do calendário';
 $labels['arialabelsearchform'] = 'Quadro de pesquisa de eventos';
diff --git a/plugins/calendar/localization/ru_RU.inc b/plugins/calendar/localization/ru_RU.inc
index 0ef726b..a7b0918 100644
--- a/plugins/calendar/localization/ru_RU.inc
+++ b/plugins/calendar/localization/ru_RU.inc
@@ -258,9 +258,9 @@ $labels['compare'] = 'Сравнить';
 $labels['showrevision'] = 'Показать эту версию';
 $labels['restore'] = 'Восстановить эту версию';
 $labels['eventnotfound'] = 'Не удалось загрузить информацию о мероприятиях';
-$labels['eventchangelognotavailable'] = 'История изменений для этого события недоступна';
+$labels['objectchangelognotavailable'] = 'История изменений для этого события недоступна';
 $labels['eventdiffnotavailable'] = 'Невозможно провести сравнение выбранных ревизий ';
-$labels['eventrestoreconfirm'] = 'Вы уверенны, что хотите восстановить это событие из ревизии $rev? Оно заменит текущее событие старой версией. ';
+$labels['revisionrestoreconfirm'] = 'Вы уверенны, что хотите восстановить это событие из ревизии $rev? Оно заменит текущее событие старой версией. ';
 $labels['arialabelminical'] = 'Выбор даты';
 $labels['arialabelcalendarview'] = 'Вид календаря';
 $labels['arialabelsearchform'] = 'Форма поиска событий';
diff --git a/plugins/calendar/localization/sl.inc b/plugins/calendar/localization/sl.inc
index 747dfe3..9ab874b 100644
--- a/plugins/calendar/localization/sl.inc
+++ b/plugins/calendar/localization/sl.inc
@@ -257,9 +257,9 @@ $labels['compare'] = 'Primerjaj';
 $labels['showrevision'] = 'Prikaži to verzijo';
 $labels['restore'] = 'Obnovi to verzijo';
 $labels['eventnotfound'] = 'Napaka pri nalaganju podatkov o dogodku';
-$labels['eventchangelognotavailable'] = 'Sprememba zgodovine za ta dogodek ni na voljo';
+$labels['objectchangelognotavailable'] = 'Sprememba zgodovine za ta dogodek ni na voljo';
 $labels['eventdiffnotavailable'] = 'Primerjava za izbrane verzije ni na voljo';
-$labels['eventrestoreconfirm'] = 'Ali želite obnoviti verzijo $rev tega dogodka? To bo nadomestilo trenutni dogodek s starejšo verzijo.';
+$labels['revisionrestoreconfirm'] = 'Ali želite obnoviti verzijo $rev tega dogodka? To bo nadomestilo trenutni dogodek s starejšo verzijo.';
 $labels['arialabelminical'] = 'Izbira datuma v koledarju';
 $labels['arialabelcalendarview'] = 'Prikaz koledarja';
 $labels['arialabelsearchform'] = 'Obrazec za iskanje dogodkov';
diff --git a/plugins/calendar/localization/sv_SE.inc b/plugins/calendar/localization/sv_SE.inc
index 1947944..94e7213 100644
--- a/plugins/calendar/localization/sv_SE.inc
+++ b/plugins/calendar/localization/sv_SE.inc
@@ -257,9 +257,9 @@ $labels['compare'] = 'Jämför';
 $labels['showrevision'] = 'Visa denna version';
 $labels['restore'] = 'Återställ denna verson';
 $labels['eventnotfound'] = 'Det gick inte att läsa in data för händelsen';
-$labels['eventchangelognotavailable'] = 'Ändringshistorik är inte tillgänglig för denna händelse';
+$labels['objectchangelognotavailable'] = 'Ändringshistorik är inte tillgänglig för denna händelse';
 $labels['eventdiffnotavailable'] = 'Ingen jämförelse möjlig för valda revisioner';
-$labels['eventrestoreconfirm'] = 'Vill du verkligen återställa revision $rev för denna händelse? Det kommer att ersätta den aktuella händelsen med den gamla versionen.';
+$labels['revisionrestoreconfirm'] = 'Vill du verkligen återställa revision $rev för denna händelse? Det kommer att ersätta den aktuella händelsen med den gamla versionen.';
 $labels['arialabelminical'] = 'Kalender datumurval';
 $labels['arialabelcalendarview'] = 'Kalender vy';
 $labels['arialabelsearchform'] = 'Händelse sökformulär';
diff --git a/plugins/calendar/localization/th.inc b/plugins/calendar/localization/th.inc
index 074cc81..f157543 100644
--- a/plugins/calendar/localization/th.inc
+++ b/plugins/calendar/localization/th.inc
@@ -244,9 +244,9 @@ $labels['compare'] = 'เปรียบเทียบ';
 $labels['showrevision'] = 'แสดงรุ่นการปรับปรุงนี้';
 $labels['restore'] = 'ย้อนกลับไปยังรุ่นการปรับปรุงนี้';
 $labels['eventnotfound'] = 'การโหลดข้อมูลของเหตุการณ์ล้มเหลว';
-$labels['eventchangelognotavailable'] = 'ไม่มีประวัติการปรับเปลี่ยนสำหรับเหตุการณ์นี้';
+$labels['objectchangelognotavailable'] = 'ไม่มีประวัติการปรับเปลี่ยนสำหรับเหตุการณ์นี้';
 $labels['eventdiffnotavailable'] = 'ไม่สามารถเปรียบเทียบรุ่นการปรับปรุงที่เลือกได้';
-$labels['eventrestoreconfirm'] = 'คุณต้องการกู้คืนรุ่นการปรับปรุง $rev ของเหตุการณ์นี้หรือ  นี่จะเป็นการเขียนทับข้อมูลปัจจุบันด้วยข้อมูลที่เก่ากว่า';
+$labels['revisionrestoreconfirm'] = 'คุณต้องการกู้คืนรุ่นการปรับปรุง $rev ของเหตุการณ์นี้หรือ  นี่จะเป็นการเขียนทับข้อมูลปัจจุบันด้วยข้อมูลที่เก่ากว่า';
 $labels['arialabelcalendarview'] = 'มุมมองปฎิทิน';
 $labels['arialabelquicksearchbox'] = 'ป้อนข้อมูลเพื่อค้นหาเหตุการณ์';
 $labels['arialabelcalsearchform'] = 'ฟอร์มค้นหาปฎิทิน';
diff --git a/plugins/calendar/localization/vi.inc b/plugins/calendar/localization/vi.inc
index 6a5284a..ae0698b 100644
--- a/plugins/calendar/localization/vi.inc
+++ b/plugins/calendar/localization/vi.inc
@@ -255,9 +255,9 @@ $labels['compare'] = 'Compare';
 $labels['showrevision'] = 'Show this version';
 $labels['restore'] = 'Restore this version';
 $labels['eventnotfound'] = 'Failed to load event data';
-$labels['eventchangelognotavailable'] = 'Change history is not available for this event';
+$labels['objectchangelognotavailable'] = 'Change history is not available for this event';
 $labels['eventdiffnotavailable'] = 'No comparison possible for the selected revisions';
-$labels['eventrestoreconfirm'] = 'Do you really want to restore revision $rev of this event? This will replace the current event with the old version.';
+$labels['revisionrestoreconfirm'] = 'Do you really want to restore revision $rev of this event? This will replace the current event with the old version.';
 $labels['arialabelminical'] = 'Calendar date selection';
 $labels['arialabelcalendarview'] = 'Calendar view';
 $labels['arialabelsearchform'] = 'Event search form';
diff --git a/plugins/calendar/localization/vi_VN.inc b/plugins/calendar/localization/vi_VN.inc
index 036f184..d55f7b3 100644
--- a/plugins/calendar/localization/vi_VN.inc
+++ b/plugins/calendar/localization/vi_VN.inc
@@ -256,9 +256,9 @@ $labels['compare'] = 'Compare';
 $labels['showrevision'] = 'Show this version';
 $labels['restore'] = 'Restore this version';
 $labels['eventnotfound'] = 'Failed to load event data';
-$labels['eventchangelognotavailable'] = 'Change history is not available for this event';
+$labels['objectchangelognotavailable'] = 'Change history is not available for this event';
 $labels['eventdiffnotavailable'] = 'No comparison possible for the selected revisions';
-$labels['eventrestoreconfirm'] = 'Do you really want to restore revision $rev of this event? This will replace the current event with the old version.';
+$labels['revisionrestoreconfirm'] = 'Do you really want to restore revision $rev of this event? This will replace the current event with the old version.';
 $labels['arialabelminical'] = 'Calendar date selection';
 $labels['arialabelcalendarview'] = 'Calendar view';
 $labels['arialabelsearchform'] = 'Event search form';
diff --git a/plugins/calendar/localization/zh_TW.inc b/plugins/calendar/localization/zh_TW.inc
index 6a5284a..ae0698b 100644
--- a/plugins/calendar/localization/zh_TW.inc
+++ b/plugins/calendar/localization/zh_TW.inc
@@ -255,9 +255,9 @@ $labels['compare'] = 'Compare';
 $labels['showrevision'] = 'Show this version';
 $labels['restore'] = 'Restore this version';
 $labels['eventnotfound'] = 'Failed to load event data';
-$labels['eventchangelognotavailable'] = 'Change history is not available for this event';
+$labels['objectchangelognotavailable'] = 'Change history is not available for this event';
 $labels['eventdiffnotavailable'] = 'No comparison possible for the selected revisions';
-$labels['eventrestoreconfirm'] = 'Do you really want to restore revision $rev of this event? This will replace the current event with the old version.';
+$labels['revisionrestoreconfirm'] = 'Do you really want to restore revision $rev of this event? This will replace the current event with the old version.';
 $labels['arialabelminical'] = 'Calendar date selection';
 $labels['arialabelcalendarview'] = 'Calendar view';
 $labels['arialabelsearchform'] = 'Event search form';
diff --git a/plugins/calendar/skins/larry/calendar.css b/plugins/calendar/skins/larry/calendar.css
index c137fb8..b0a8660 100644
--- a/plugins/calendar/skins/larry/calendar.css
+++ b/plugins/calendar/skins/larry/calendar.css
@@ -848,61 +848,61 @@ a.miniColors-trigger {
 	margin: 4px 0;
 }
 
-#event-changelog-table tbody td {
+.changelog-table tbody td {
 	padding: 4px 7px;
 	vertical-align: middle;
 }
 
-#event-changelog-table tbody tr:last-child td {
+.changelog-table tbody tr:last-child td {
 	border-bottom: 0;
 }
 
-#event-changelog-table tbody tr.undisclosed td.date,
-#event-changelog-table tbody tr.undisclosed td.user {
+.changelog-table tbody tr.undisclosed td.date,
+.changelog-table tbody tr.undisclosed td.user {
 	font-style: italic;
 }
 
-#event-changelog-table .diff {
+.changelog-table .diff {
 	width: 4em;
 	padding: 2px;
 }
 
-#event-changelog-table .revision {
+.changelog-table .revision {
 	width: 6em;
 }
 
-#event-changelog-table .date {
+.changelog-table .date {
 	width: 11em;
 }
 
-#event-changelog-table .user {
+.changelog-table .user {
 	width: auto;
 }
 
-#event-changelog-table .operation {
+.changelog-table .operation {
 	width: 15%;
 }
 
-#event-changelog-table .actions {
+.changelog-table .actions {
 	width: 50px;
 	text-align: right;
 	padding: 4px;
 }
 
-#event-changelog-table td a.iconbutton.restore,
-#event-changelog-table td a.iconbutton.preview {
+.changelog-table td a.iconbutton.restore,
+.changelog-table td a.iconbutton.preview {
 	width: 16px;
 	margin-right: 2px;
 	background-image: url(images/calendars.png);
 	background-position: -1px -147px;
 }
 
-#event-changelog-table td a.iconbutton.restore {
+.changelog-table td a.iconbutton.restore {
 	background-image: url(images/calendars.png);
 	background-position: -1px -167px;
 }
 
-#event-changelog-table tr.first td a.iconbutton {
+.changelog-table tr.first td a.iconbutton {
 	opacity: 0.3;
 	cursor: default;
 }
diff --git a/plugins/calendar/skins/larry/templates/calendar.html b/plugins/calendar/skins/larry/templates/calendar.html
index eecb24e..b9ea905 100644
--- a/plugins/calendar/skins/larry/templates/calendar.html
+++ b/plugins/calendar/skins/larry/templates/calendar.html
@@ -335,7 +335,7 @@
 </div>
 
 <div id="eventhistory" class="uidialog" aria-hidden="true">
-    <roundcube:object name="plugin.event_changelog_table" id="event-changelog-table" class="records-table" />
+    <roundcube:object name="plugin.event_changelog_table" id="event-changelog-table" class="records-table changelog-table" />
     <div class="compare-button"><input type="button" class="button" value="↳ <roundcube:label name='calendar.compare' />" /></div>
 </div>
 
diff --git a/plugins/libkolab/js/audittrail.js b/plugins/libkolab/js/audittrail.js
new file mode 100644
index 0000000..5c9eec0
--- /dev/null
+++ b/plugins/libkolab/js/audittrail.js
@@ -0,0 +1,203 @@
+/**
+ * Kolab groupware audit trail utilities
+ *
+ * @author Thomas Bruederli <bruederli at kolabsys.com>
+ *
+ * @licstart  The following is the entire license notice for the
+ * JavaScript code in this file.
+ *
+ * Copyright (C) 2015, Kolab Systems AG <contact at kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @licend  The above is the entire license notice
+ * for the JavaScript code in this file.
+ */
+
+var libkolab_audittrail = {}
+
+libkolab_audittrail.quote_html = function(str)
+{
+    return String(str).replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
+};
+
+
+// show object changelog in a dialog
+libkolab_audittrail.object_history_dialog = function(p)
+{
+    // render dialog
+    var $dialog = $(p.container);
+
+    // close show dialog first
+    if ($dialog.is(':ui-dialog'))
+        $dialog.dialog('close');
+
+    var buttons = {};
+    buttons[rcmail.gettext('close', 'calendar')] = function() {
+        $dialog.dialog('close');
+    };
+
+    // hide and reset changelog table
+    $dialog.find('div.notfound-message').remove();
+    $dialog.find('.changelog-table').show().children('tbody')
+        .html('<tr><td colspan="6"><span class="loading">' + rcmail.gettext('loading') + '</span></td></tr>');
+
+    // open jquery UI dialog
+    $dialog.dialog({
+        modal: false,
+        resizable: true,
+        closeOnEscape: true,
+        title: p.title,
+        open: function() {
+          $dialog.attr('aria-hidden', 'false');
+          setTimeout(function(){
+            $dialog.parent().find('.ui-button:not(.ui-dialog-titlebar-close)').first().focus();
+          }, 5);
+        },
+        close: function() {
+          $dialog.dialog('destroy').attr('aria-hidden', 'true').hide();
+        },
+        buttons: buttons,
+        minWidth: 450,
+        width: 650,
+        height: 350,
+        minHeight: 200,
+    })
+    .show().children('.compare-button').hide();
+
+    // initialize event handlers for history dialog UI elements
+    if (!$dialog.data('initialized')) {
+      // compare button
+      $dialog.find('.compare-button input').click(function(e) {
+        var rev1 = $dialog.find('.changelog-table input.diff-rev1:checked').val(),
+          rev2 = $dialog.find('.changelog-table input.diff-rev2:checked').val();
+
+          if (rev1 && rev2 && rev1 != rev2) {
+            // swap revisions if the user got it wrong
+            if (rev1 > rev2) {
+              var tmp = rev2;
+              rev2 = rev1;
+              rev1 = tmp;
+            }
+
+            if (p.comparefunc) {
+                p.comparefunc(rev1, rev2);
+            }
+          }
+          else {
+              alert('Invalid selection!')
+          }
+
+          if (!rcube_event.is_keyboard(e) && this.blur) {
+              this.blur();
+          }
+          return false;
+      });
+
+      // delegate handlers for list actions
+      $dialog.find('.changelog-table tbody').on('click', 'td.actions a', function(e) {
+          var link = $(this),
+            action = link.hasClass('restore') ? 'restore' : 'show',
+            event = $('#eventhistory').data('event'),
+            rev = link.attr('data-rev');
+
+            // ignore clicks on first row (current revision)
+            if (link.closest('tr').hasClass('first')) {
+                return false;
+            }
+
+            // let the user confirm the restore action
+            if (action == 'restore' && !confirm(rcmail.gettext('revisionrestoreconfirm', p.module).replace('$rev', rev))) {
+                return false;
+            }
+
+            if (p.listfunc) {
+                p.listfunc(action, rev);
+            }
+
+            if (!rcube_event.is_keyboard(e) && this.blur) {
+                this.blur();
+            }
+            return false;
+      })
+      .on('click', 'input.diff-rev1', function(e) {
+          if (!this.checked) return true;
+
+          var rev1 = this.value, selection_valid = false;
+          $dialog.find('.changelog-table input.diff-rev2').each(function(i, elem) {
+              $(elem).prop('disabled', elem.value <= rev1);
+              if (elem.checked && elem.value > rev1) {
+                  selection_valid = true;
+              }
+          });
+          if (!selection_valid) {
+              $dialog.find('.changelog-table input.diff-rev2:not([disabled])').last().prop('checked', true);
+          }
+      });
+
+      $dialog.addClass('changelog-dialog').data('initialized', true);
+    }
+
+    return $dialog;
+};
+
+// callback from server with changelog data
+libkolab_audittrail.render_changelog = function(data, object, folder)
+{
+    var Q = libkolab_audittrail.quote_html;
+
+    var $dialog = $('.changelog-dialog')
+    if (data === false || !data.length) {
+        return false;
+    }
+
+    var i, change, accessible, op_append,
+      first = data.length - 1, last = 0,
+      is_writeable = !!folder.editable,
+      op_labels = { APPEND: 'actionappend', MOVE: 'actionmove', DELETE: 'actiondelete' },
+      actions = '<a href="#show" class="iconbutton preview" title="'+ rcmail.gettext('showrevision',data.module) +'" data-rev="{rev}" /> ' +
+          (is_writeable ? '<a href="#restore" class="iconbutton restore" title="'+ rcmail.gettext('restore',data.module) + '" data-rev="{rev}" />' : ''),
+      tbody = $dialog.find('.changelog-table tbody').html('');
+
+    for (i=first; i >= 0; i--) {
+        change = data[i];
+        accessible = change.date && change.user;
+
+        if (change.op == 'MOVE' && change.mailbox) {
+            op_append = ' ⇢ ' + change.mailbox;
+        }
+        else {
+            op_append = '';
+        }
+
+        $('<tr class="' + (i == first ? 'first' : (i == last ? 'last' : '')) + (accessible ? '' : 'undisclosed') + '">')
+            .append('<td class="diff">' + (accessible && change.op != 'DELETE' ? 
+                '<input type="radio" name="rev1" class="diff-rev1" value="' + change.rev + '" title="" '+ (i == last ? 'checked="checked"' : '') +' /> '+
+                '<input type="radio" name="rev2" class="diff-rev2" value="' + change.rev + '" title="" '+ (i == first ? 'checked="checked"' : '') +' /></td>'
+                : ''))
+            .append('<td class="revision">' + Q(i+1) + '</td>')
+            .append('<td class="date">' + Q(change.date || '') + '</td>')
+            .append('<td class="user">' + Q(change.user || 'undisclosed') + '</td>')
+            .append('<td class="operation" title="' + op_append + '">' + Q(rcmail.gettext(op_labels[change.op] || '', 'calendar') + (op_append ? ' ...' : '')) + '</td>')
+            .append('<td class="actions">' + (accessible && change.op != 'DELETE' ? actions.replace(/\{rev\}/g, change.rev) : '') + '</td>')
+            .appendTo(tbody);
+    }
+
+    if (first > 0) {
+        $dialog.find('.compare-button').fadeIn(200);
+        $dialog.find('.changelog-table tr.last input.diff-rev1').click();
+    }
+
+    return $dialog;
+};
\ No newline at end of file


commit b74cb629c056ecd7568cbb9ce618bffc172c5446
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Tue Mar 24 11:52:33 2015 +0100

    Updated localizations from Transifex

diff --git a/plugins/calendar/localization/de_DE.inc b/plugins/calendar/localization/de_DE.inc
index 1a11052..15af6b7 100644
--- a/plugins/calendar/localization/de_DE.inc
+++ b/plugins/calendar/localization/de_DE.inc
@@ -248,7 +248,7 @@ $labels['birthdayscalendarsources'] = 'Für diese Adressbücher';
 $labels['birthdayeventtitle'] = '$names Geburtstag';
 $labels['birthdayage'] = 'Alter $age';
 $labels['eventchangelog'] = 'Änderungshistorie';
-$labels['eventdiff'] = 'Änderungen zwischen $rev1 und $rev2';
+$labels['eventdiff'] = 'Änderungen aus $rev1 nach $rev2';
 $labels['revision'] = 'Version';
 $labels['user'] = 'Benutzer';
 $labels['operation'] = 'Aktion';
@@ -262,6 +262,8 @@ $labels['eventnotfound'] = 'Termindaten sind leider nicht vergübar';
 $labels['eventchangelognotavailable'] = 'Änderungshistorie ist nicht verfügbar für diesen Termin';
 $labels['eventdiffnotavailable'] = 'Vergleich für die gewählten Versionen nicht möglich';
 $labels['eventrestoreconfirm'] = 'Wollen Sie wirklich die Version $rev dieses Termins wiederherstellen? Diese Aktion wird die aktuelle Kopie mit der älteren Version ersetzen.';
+$labels['eventrestoresuccess'] = 'Revision $rev erfolgreich wiederhergestellt';
+$labels['eventrestoreerror'] = 'Fehler beim Wiederherstellen der alten Revision';
 $labels['arialabelminical'] = 'Kalender Datumswahl';
 $labels['arialabelcalendarview'] = 'Kalender Ansicht';
 $labels['arialabelsearchform'] = 'Suchformular für Termine';
diff --git a/plugins/calendar/localization/fi_FI.inc b/plugins/calendar/localization/fi_FI.inc
index 2543934..a3c0f9f 100644
--- a/plugins/calendar/localization/fi_FI.inc
+++ b/plugins/calendar/localization/fi_FI.inc
@@ -244,6 +244,7 @@ $labels['birthdayscalendarsources'] = 'Näistä osoitekirjoista';
 $labels['birthdayeventtitle'] = 'Syntymäpäivä: $name';
 $labels['birthdayage'] = 'Ikä $age';
 $labels['eventchangelog'] = 'Muuta historiaa';
+$labels['eventdiff'] = 'Muutokset versiosta $rev1 versioon $rev2';
 $labels['revision'] = 'Versio';
 $labels['user'] = 'Käyttäjä';
 $labels['operation'] = 'Toiminto';
@@ -257,6 +258,8 @@ $labels['eventnotfound'] = 'Tapahtumadatan lataus epäonnistui';
 $labels['eventchangelognotavailable'] = 'Tapahtuman muutoshistoria ei ole saatavilla';
 $labels['eventdiffnotavailable'] = 'Vertailu ei ole saatavilla valittujen versioiden välillä';
 $labels['eventrestoreconfirm'] = 'Haluatko varmasti palauttaa tämän tapahtuman version $rev? Nykyinen tapahtuma korvataan vanhalla versiolla.';
+$labels['eventrestoresuccess'] = 'Versio $rev palautettiin onnistuneesti';
+$labels['eventrestoreerror'] = 'Vanhan version palauttaminen epäonnistui';
 $labels['arialabelminical'] = 'Kalenterin ajankohdan valinta';
 $labels['arialabelcalendarview'] = 'Kalenterinäkymä';
 $labels['arialabelsearchform'] = 'Tapahtumahaun lomake';
diff --git a/plugins/calendar/localization/th.inc b/plugins/calendar/localization/th.inc
index e59e242..074cc81 100644
--- a/plugins/calendar/localization/th.inc
+++ b/plugins/calendar/localization/th.inc
@@ -234,7 +234,6 @@ $labels['birthdayscalendarsources'] = 'จากสมุดที่อยู
 $labels['birthdayeventtitle'] = 'วันเกิดของ $name';
 $labels['birthdayage'] = 'อายุ $age ปี';
 $labels['eventchangelog'] = 'ประวัติการปรับเปลี่ยน';
-$labels['eventdiff'] = 'สิ่งที่เปลี่ยนจาก รุ่นการปรับปรุง $rev';
 $labels['revision'] = 'รุ่นการปรับปรุง';
 $labels['user'] = 'ผู้ใช้';
 $labels['operation'] = 'การกระทำ';
diff --git a/plugins/calendar/localization/uk.inc b/plugins/calendar/localization/uk.inc
index 5005eea..aac583a 100644
--- a/plugins/calendar/localization/uk.inc
+++ b/plugins/calendar/localization/uk.inc
@@ -206,7 +206,6 @@ $labels['birthdayscalendarsources'] = 'З даних адресних книг';
 $labels['birthdayeventtitle'] = 'День Народження $name';
 $labels['birthdayage'] = 'Вік $age';
 $labels['eventchangelog'] = 'Історія змін';
-$labels['eventdiff'] = 'Зміни з ревізії $rev';
 $labels['revision'] = 'Ревізія';
 $labels['user'] = 'Користувач';
 $labels['operation'] = 'Дія';
diff --git a/plugins/calendar/localization/vi.inc b/plugins/calendar/localization/vi.inc
index 036f184..6a5284a 100644
--- a/plugins/calendar/localization/vi.inc
+++ b/plugins/calendar/localization/vi.inc
@@ -245,7 +245,6 @@ $labels['birthdayscalendarsources'] = 'From these address books';
 $labels['birthdayeventtitle'] = '$name\'s Birthday';
 $labels['birthdayage'] = 'Age $age';
 $labels['eventchangelog'] = 'Change History';
-$labels['eventdiff'] = 'Changes from revisions $rev';
 $labels['revision'] = 'Revision';
 $labels['user'] = 'User';
 $labels['operation'] = 'Action';
diff --git a/plugins/calendar/localization/zh_TW.inc b/plugins/calendar/localization/zh_TW.inc
index 036f184..6a5284a 100644
--- a/plugins/calendar/localization/zh_TW.inc
+++ b/plugins/calendar/localization/zh_TW.inc
@@ -245,7 +245,6 @@ $labels['birthdayscalendarsources'] = 'From these address books';
 $labels['birthdayeventtitle'] = '$name\'s Birthday';
 $labels['birthdayage'] = 'Age $age';
 $labels['eventchangelog'] = 'Change History';
-$labels['eventdiff'] = 'Changes from revisions $rev';
 $labels['revision'] = 'Revision';
 $labels['user'] = 'User';
 $labels['operation'] = 'Action';




More information about the commits mailing list