plugins/calendar plugins/libcalendaring

Thomas Brüderli bruederli at kolabsys.com
Thu Sep 11 17:55:10 CEST 2014


 plugins/calendar/calendar.php                      |   58 ++++++++++++++++++++-
 plugins/calendar/localization/en_US.inc            |    2 
 plugins/calendar/skins/classic/calendar.css        |   36 +++++++++++++
 plugins/calendar/skins/larry/calendar.css          |   38 +++++++++++++
 plugins/libcalendaring/lib/libcalendaring_itip.php |    3 +
 plugins/libcalendaring/libcalendaring.js           |   14 +++++
 6 files changed, 150 insertions(+), 1 deletion(-)

New commits:
commit 086e2b2e1fa86cdd37a298fdaadd3472518d53b7
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Thu Sep 11 17:55:01 2014 +0200

    Render preview agenda for iTip requests below RSVP buttons (#3161)

diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php
index 9c0a892..5616b28 100644
--- a/plugins/calendar/calendar.php
+++ b/plugins/calendar/calendar.php
@@ -2237,6 +2237,37 @@ class calendar extends rcube_plugin
       $response['select'] = html::tag('input', array('type' => 'hidden', 'name' => 'calendar', 'id' => 'itip-saveto', 'value' => ''));
     }
 
+    // render small agenda view for the respective day
+    if ($data['method'] == 'REQUEST' && !empty($data['date']) && $response['action'] == 'rsvp') {
+      $event_start = rcube_utils::anytodatetime($data['date']);
+      $day_start = new Datetime(gmdate('Y-m-d 00:00', $data['date']), $this->lib->timezone);
+      $day_end = new Datetime(gmdate('Y-m-d 23:59', $data['date']), $this->lib->timezone);
+
+      // get events on that day from the user's personal calendars
+      $calendars = $this->driver->list_calendars(false, true);
+      $events = $this->driver->load_events($day_start->format('U'), $day_end->format('U'), null, array_keys($calendars));
+      usort($events, function($a, $b) { return $a['start'] > $b['start'] ? 1 : -1; });
+
+      $before = $after = array();
+      foreach ($events as $event) {
+        // TODO: skip events with free_busy == 'free' ?
+        if ($event['uid'] == $data['uid'] || $event['end'] < $day_start || $event['start'] > $day_end)
+          continue;
+        else if ($event['start'] < $event_start)
+          $before[] = $this->mail_agenda_event_row($event);
+        else
+          $after[] = $this->mail_agenda_event_row($event);
+      }
+
+      $response['append'] = array(
+        'selector' => '.calendar-agenda-preview',
+        'replacements' => array(
+          '%before%' => !empty($before) ? join("\n", array_slice($before,  -3)) : html::div('event-row no-event', $this->gettext('noearlierevents')),
+          '%after%'  => !empty($after)  ? join("\n", array_slice($after, 0, 3)) : html::div('event-row no-event', $this->gettext('nolaterevents')),
+        ),
+      );
+    }
+
     $this->rc->output->command('plugin.update_itip_object_status', $response);
   }
 
@@ -2338,6 +2369,21 @@ class calendar extends rcube_plugin
     $hidden = new html_hiddenfield(array('name' => "_t", 'value' => $this->token));
     return html::tag('form', array('action' => $this->rc->url(array('task' => 'calendar', 'action' => 'attend')), 'method' => 'post', 'noclose' => true) + $attrib) . $hidden->show();
   }
+
+  /**
+   * 
+   */
+  private function mail_agenda_event_row($event, $class = '')
+  {
+    $time = $event['all-day'] ? $this->gettext('allday') :
+      $this->rc->format_date($event['start'], $this->rc->config->get('time_format')) . ' - ' .
+        $this->rc->format_date($event['end'], $this->rc->config->get('time_format'));
+
+    return html::div(rtrim('event-row ' . $class),
+      html::span('event-date', $time) .
+      html::span('event-title', Q($event['title']))
+    );
+  }
   
   /**
    * 
@@ -2391,6 +2437,16 @@ class calendar extends rcube_plugin
 
       // get prepared inline UI for this event object
       if ($ical_objects->method) {
+        $append = '';
+
+        // prepare a small agenda preview to be filled with actual event data on async request
+        if ($ical_objects->method == 'REQUEST') {
+          $append = html::div('calendar-agenda-preview',
+            html::tag('h3', 'preview-title', $this->gettext('agenda') . ' ' .
+              html::span('date', $this->rc->format_date($event['start'], $this->rc->config->get('date_format')))
+            ) . '%before%' . $this->mail_agenda_event_row($event, 'current') . '%after%');
+        }
+
         $html .= html::div('calendar-invitebox',
           $this->itip->mail_itip_inline_ui(
             $event,
@@ -2399,7 +2455,7 @@ class calendar extends rcube_plugin
             'calendar',
             rcube_utils::anytodatetime($ical_objects->message_date),
             $this->rc->url(array('task' => 'calendar')) . '&view=agendaDay&date=' . $event['start']->format('U')
-          )
+          ) . $append
         );
       }
 
diff --git a/plugins/calendar/localization/en_US.inc b/plugins/calendar/localization/en_US.inc
index 76fbcee..7755aa7 100644
--- a/plugins/calendar/localization/en_US.inc
+++ b/plugins/calendar/localization/en_US.inc
@@ -202,6 +202,8 @@ $labels['saveincalendar'] = 'save in';
 $labels['updatemycopy'] = 'Update in my calendar';
 $labels['savetocalendar'] = 'Save to calendar';
 $labels['openpreview'] = 'Check Calendar';
+$labels['noearlierevents'] = 'No earlier events';
+$labels['nolaterevents'] = 'No later events';
 
 // resources
 $labels['resource'] = 'Resource';
diff --git a/plugins/calendar/skins/classic/calendar.css b/plugins/calendar/skins/classic/calendar.css
index f7e0c1c..f8a4fa3 100644
--- a/plugins/calendar/skins/classic/calendar.css
+++ b/plugins/calendar/skins/classic/calendar.css
@@ -1688,6 +1688,42 @@ div.calendar-invitebox .rsvp-status.delegated {
 	background-position: 2px -180px;
 }
 
+div.calendar-invitebox .calendar-agenda-preview {
+	display: none;
+	border-top: 1px solid #dfdfdf;
+	margin-top: 1em;
+	padding-top: 0.6em;
+}
+
+div.calendar-invitebox .calendar-agenda-preview h3.preview-title {
+	margin: 0 0 0.5em 0;
+	font-size: 12px;
+}
+
+div.calendar-invitebox .calendar-agenda-preview .event-row {
+	color: #777;
+	padding: 2px 0;
+	white-space: nowrap;
+	overflow: hidden;
+	text-overflow: ellipsis;
+}
+
+div.calendar-invitebox .calendar-agenda-preview .event-row.current {
+	color: #000;
+	font-weight: bold;
+}
+
+div.calendar-invitebox .calendar-agenda-preview .event-row.no-event {
+	font-style: italic;
+}
+
+div.calendar-invitebox .calendar-agenda-preview .event-date {
+	display: inline-block;
+	min-width: 8em;
+	margin-right: 1em;
+	white-space: nowrap;
+}
+
 /* iTIP attend reply page */
 
 .calendaritipattend .centerbox {
diff --git a/plugins/calendar/skins/larry/calendar.css b/plugins/calendar/skins/larry/calendar.css
index 54e0141..40d79fd 100644
--- a/plugins/calendar/skins/larry/calendar.css
+++ b/plugins/calendar/skins/larry/calendar.css
@@ -2110,6 +2110,44 @@ div.calendar-invitebox .rsvp-status.needs-action {
 	background-position: 2px 0;
 }
 
+div.calendar-invitebox .calendar-agenda-preview {
+	display: none;
+	border-top: 1px solid #dfdfdf;
+	margin-top: 1em;
+	padding-top: 0.6em;
+}
+
+div.calendar-invitebox .calendar-agenda-preview h3.preview-title {
+	margin: 0 0 0.5em 0;
+	font-size: 12px;
+	color: #333;
+}
+
+div.calendar-invitebox .calendar-agenda-preview .event-row {
+	color: #777;
+	padding: 2px 0;
+	white-space: nowrap;
+	overflow: hidden;
+	text-overflow: ellipsis;
+}
+
+div.calendar-invitebox .calendar-agenda-preview .event-row.current {
+	color: #333;
+	font-weight: bold;
+}
+
+div.calendar-invitebox .calendar-agenda-preview .event-row.no-event {
+	font-style: italic;
+}
+
+div.calendar-invitebox .calendar-agenda-preview .event-date {
+	display: inline-block;
+	min-width: 8em;
+	margin-right: 1em;
+	white-space: nowrap;
+}
+
+
 /* iTIP attend reply page */
 
 .calendaritipattend .centerbox {
diff --git a/plugins/libcalendaring/lib/libcalendaring_itip.php b/plugins/libcalendaring/lib/libcalendaring_itip.php
index a5b056f..6740bfa 100644
--- a/plugins/libcalendaring/lib/libcalendaring_itip.php
+++ b/plugins/libcalendaring/lib/libcalendaring_itip.php
@@ -434,6 +434,9 @@ class libcalendaring_itip
             $emails = $this->lib->get_user_emails();
             $title = $event['sequence'] > 0 ? $this->gettext('itipupdate') : $this->gettext('itipinvitation');
             $metadata['rsvp'] = true;
+            if (is_object($event['start'])) {
+                $metadata['date'] = $event['start']->format('U');
+            }
 
             // check for X-KOLAB-INVITATIONTYPE property and only show accept/decline buttons
             if (self::get_custom_property($event, 'X-KOLAB-INVITATIONTYPE') == 'CONFIRMATION') {
diff --git a/plugins/libcalendaring/libcalendaring.js b/plugins/libcalendaring/libcalendaring.js
index b23a3fe..5b8ad5c 100644
--- a/plugins/libcalendaring/libcalendaring.js
+++ b/plugins/libcalendaring/libcalendaring.js
@@ -912,6 +912,20 @@ rcube_libcalendaring.update_itip_object_status = function(p)
  
   // show rsvp/import buttons (with calendar selector)
   $('#'+p.action+'-'+p.id).show().find('input.button').last().after(p.select);
+
+  // show itip box appendix after replacing the given placeholders
+  if (p.append && p.append.selector) {
+    var elem = $(p.append.selector);
+    if (p.append.replacements) {
+      $.each(p.append.replacements, function(k, html) {
+        elem.html(elem.html().replace(k, html));
+      });
+    }
+    else if (p.append.html) {
+      elem.html(p.append.html)
+    }
+    elem.show();
+  }
 };
 
 /**




More information about the commits mailing list