4 commits - plugins/calendar plugins/libkolab plugins/tasklist

Thomas Brüderli bruederli at kolabsys.com
Thu Jun 26 17:44:19 CEST 2014


 plugins/calendar/calendar.php                          |    7 
 plugins/calendar/calendar_ui.js                        |  304 ++++++++++-------
 plugins/calendar/drivers/kolab/kolab_user_calendar.php |    9 
 plugins/calendar/lib/calendar_ui.php                   |    1 
 plugins/calendar/lib/js/fullcalendar.js                |   13 
 plugins/calendar/localization/en_US.inc                |    1 
 plugins/calendar/skins/larry/calendar.css              |  124 +++++-
 plugins/calendar/skins/larry/images/calendars.png      |binary
 plugins/libkolab/js/folderlist.js                      |   14 
 plugins/tasklist/tasklist.js                           |    3 
 10 files changed, 309 insertions(+), 167 deletions(-)

New commits:
commit 3b80a73456ab025e12114f17d06b595a5e41449d
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Thu Jun 26 17:44:10 2014 +0200

    Minor codestyle fix

diff --git a/plugins/tasklist/tasklist.js b/plugins/tasklist/tasklist.js
index fb7c4ac..5994381 100644
--- a/plugins/tasklist/tasklist.js
+++ b/plugins/tasklist/tasklist.js
@@ -207,8 +207,9 @@ function rcube_tasklist_ui(settings)
         // handler for clicks on quickview buttons
         tasklists_widget.container.on('click', '.quickview', function(e){
             var id = $(this).closest('li').attr('id').replace(/^rcmlitasklist/, '');
-            set_focusview(focusview == id ? null : id)
+            set_focusview(focusview == id ? null : id);
             e.stopPropagation();
+            return false;
         });
 
         // register dbl-click handler to open calendar edit dialog


commit ab43057b1fa5104da744fc2deb6264d0524d2965
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Thu Jun 26 17:42:32 2014 +0200

    Implement quickview for calendars, showing free-busy data for other user's calendars (#3043)

diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php
index f863580..0313bb1 100644
--- a/plugins/calendar/calendar.php
+++ b/plugins/calendar/calendar.php
@@ -3,12 +3,11 @@
 /**
  * Calendar plugin for Roundcube webmail
  *
- * @version @package_version@
  * @author Lazlo Westerhof <hello at lazlo.me>
  * @author Thomas Bruederli <bruederli at kolabsys.com>
  *
  * Copyright (C) 2010, Lazlo Westerhof <hello at lazlo.me>
- * Copyright (C) 2012, Kolab Systems AG <contact at kolabsys.com>
+ * Copyright (C) 2014, 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
@@ -1397,7 +1396,9 @@ class calendar extends rcube_plugin
       'title'       => strval($event['title']),
       'description' => strval($event['description']),
       'location'    => strval($event['location']),
-      'className'   => ($addcss ? 'fc-event-cal-'.asciiwords($event['calendar'], true).' ' : '') . 'fc-event-cat-' . asciiwords(strtolower(join('-', (array)$event['categories'])), true),
+      'className'   => ($addcss ? 'fc-event-cal-'.asciiwords($event['calendar'], true).' ' : '') .
+          'fc-event-cat-' . asciiwords(strtolower(join('-', (array)$event['categories'])), true) .
+          rtrim(' ' . $event['className']),
       'allDay'      => ($event['allday'] == 1),
     ) + $event;
   }
diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js
index 3558d91..985a3b6 100644
--- a/plugins/calendar/calendar_ui.js
+++ b/plugins/calendar/calendar_ui.js
@@ -8,7 +8,7 @@
  * JavaScript code in this file.
  *
  * Copyright (C) 2010, Lazlo Westerhof <hello at lazlo.me>
- * Copyright (C) 2012, Kolab Systems AG <contact at kolabsys.com>
+ * Copyright (C) 2014, 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
@@ -83,6 +83,78 @@ function rcube_calendar_ui(settings)
       selectOtherMonths: true
     };
 
+    // global fullcalendar settings
+    var fullcalendar_defaults = {
+      aspectRatio: 1,
+      ignoreTimezone: true,  // will treat the given date strings as in local (browser's) timezone
+      monthNames : settings.months,
+      monthNamesShort : settings.months_short,
+      dayNames : settings.days,
+      dayNamesShort : settings.days_short,
+      firstDay : settings.first_day,
+      firstHour : settings.first_hour,
+      slotMinutes : 60/settings.timeslots,
+      timeFormat: {
+        '': settings.time_format,
+        agenda: settings.time_format + '{ - ' + settings.time_format + '}',
+        list: settings.time_format + '{ - ' + settings.time_format + '}',
+        table: settings.time_format + '{ - ' + settings.time_format + '}'
+      },
+      axisFormat : settings.time_format,
+      columnFormat: {
+        month: 'ddd', // Mon
+        week: 'ddd ' + settings.date_short, // Mon 9/7
+        day: 'dddd ' + settings.date_short,  // Monday 9/7
+        table: settings.date_agenda
+      },
+      titleFormat: {
+        month: 'MMMM yyyy',
+        week: settings.dates_long,
+        day: 'dddd ' + settings['date_long'],
+        table: settings.dates_long
+      },
+      listPage: 1,  // advance one day in agenda view
+      listRange: settings.agenda_range,
+      listSections: settings.agenda_sections,
+      tableCols: ['handle', 'date', 'time', 'title', 'location'],
+      defaultView: rcmail.env.view || settings.default_view,
+      allDayText: rcmail.gettext('all-day', 'calendar'),
+      buttonText: {
+        prev: ' ◄ ',
+        next: ' ► ',
+        today: settings['today'],
+        day: rcmail.gettext('day', 'calendar'),
+        week: rcmail.gettext('week', 'calendar'),
+        month: rcmail.gettext('month', 'calendar'),
+        table: rcmail.gettext('agenda', 'calendar')
+      },
+      listTexts: {
+        until: rcmail.gettext('until', 'calendar'),
+        past: rcmail.gettext('pastevents', 'calendar'),
+        today: rcmail.gettext('today', 'calendar'),
+        tomorrow: rcmail.gettext('tomorrow', 'calendar'),
+        thisWeek: rcmail.gettext('thisweek', 'calendar'),
+        nextWeek: rcmail.gettext('nextweek', 'calendar'),
+        thisMonth: rcmail.gettext('thismonth', 'calendar'),
+        nextMonth: rcmail.gettext('nextmonth', 'calendar'),
+        future: rcmail.gettext('futureevents', 'calendar'),
+        week: rcmail.gettext('weekofyear', 'calendar')
+      },
+      currentTimeIndicator: settings.time_indicator,
+      // event rendering
+      eventRender: fc_event_render,
+      // render element indicating more (invisible) events
+      overflowRender: function(data, element) {
+        element.html(rcmail.gettext('andnmore', 'calendar').replace('$nr', data.count))
+          .click(function(e){ me.fisheye_view(data.date); });
+      },
+      // callback when a specific event is clicked
+      eventClick: function(event, ev, view) {
+        if (!event.temp && String(event.className).indexOf('fc-type-freebusy') < 0)
+          event_show_dialog(event, ev);
+      }
+    };
+
     /***  imports  ***/
     var Q = this.quote_html;
     var text2html = this.text2html;
@@ -1598,25 +1670,13 @@ function rcube_calendar_ui(settings)
 
         // initialize resource calendar display
         var resource_cal = $(rcmail.gui_objects.resourceinfocalendar);
-        resource_cal.fullCalendar({
+        resource_cal.fullCalendar($.extend({}, fullcalendar_defaults, {
           header: { left: '', center: '', right: '' },
           height: resource_cal.height() + 4,
           defaultView: 'agendaWeek',
-          ignoreTimezone: true,
           eventSources: [],
-          monthNames: settings['months'],
-          monthNamesShort: settings['months_short'],
-          dayNames: settings['days'],
-          dayNamesShort : settings['days_short'],
-          firstDay: settings['first_day'],
-          firstHour: settings['first_hour'],
           slotMinutes: 60,
           allDaySlot: false,
-          timeFormat: { '': settings['time_format'] },
-          axisFormat: settings['time_format'],
-          columnFormat: { day: 'dddd ' + settings['date_short'] },
-          titleFormat: { day: 'dddd ' + settings['date_long'] },
-          currentTimeIndicator: settings.time_indicator,
           eventRender: function(event, element, view) {
             var title = rcmail.get_label(event.status, 'calendar');
             element.addClass('status-' + event.status);
@@ -1624,7 +1684,7 @@ function rcube_calendar_ui(settings)
             element.find('.fc-event-title').text(title);
             element.attr('aria-label', me.event_date_text(event, true) + ': ' + title);
           }
-        });
+        }));
 
         $('#resource-calendar-prev').click(function(){
           resource_cal.fullCalendar('prev');
@@ -2107,37 +2167,69 @@ function rcube_calendar_ui(settings)
             me.fisheye_date = null;
           }
         })
-        .fullCalendar({
+        .fullCalendar($.extend({}, fullcalendar_defaults, {
           header: { left: '', center: '', right: '' },
           height: h - 50,
-          defaultView: 'agendaDay',
           date: date.getDate(),
           month: date.getMonth(),
           year: date.getFullYear(),
-          ignoreTimezone: true,  /* will treat the given date strings as in local (browser's) timezone */
-          eventSources: sources,
-          monthNames : settings['months'],
-          monthNamesShort : settings['months_short'],
-          dayNames : settings['days'],
-          dayNamesShort : settings['days_short'],
-          firstDay : settings['first_day'],
-          firstHour : settings['first_hour'],
-          slotMinutes : 60/settings['timeslots'],
-          timeFormat: { '': settings['time_format'] },
-          axisFormat : settings['time_format'],
-          columnFormat: { day: 'dddd ' + settings['date_short'] },
-          titleFormat: { day: 'dddd ' + settings['date_long'] },
-          allDayText: rcmail.gettext('all-day', 'calendar'),
-          currentTimeIndicator: settings.time_indicator,
-          eventRender: fc_event_render,
-          eventClick: function(event, ev, view) {
-            event_show_dialog(event, ev);
-          }
-        });
+          eventSources: sources
+        }));
         
         this.fisheye_date = date;
     };
 
+    // opens the given calendar in a popup dialog
+    this.quickview = function(id)
+    {
+      $('#quickview-calendar:ui-dialog').dialog('close');
+
+      var dialog, src, cal = this.calendars[id], date = fc.fullCalendar('getDate'),
+        h = $(window).height() - 50,
+        me = this;
+
+      // clone and modify calendar properties
+      src = $.extend({}, cal);
+      src.editable = false;
+      src.url += '&_quickview=1';
+
+      dialog = $('<div>')
+        .attr('id', 'quickview-calendar')
+        .dialog({
+          modal: true,
+          width: Math.min(1000, $(window).width() - 100),
+          height: h,
+          title: cal.name.replace('»', '»').replace(' ', ' '),
+          open: function() {
+            setTimeout(function() { dialog.find('.fc-button-next').first().focus(); }, 10);
+          },
+          close: function() {
+            dialog.dialog('destroy').fullCalendar('destroy').remove();
+            me.quickview_active = null;
+          },
+          resize: function(e) {
+            // adjust height when dialog resizes
+            dialog.fullCalendar('option', 'height', dialog.height() + 8);
+          }
+        })
+        .fullCalendar($.extend({}, fullcalendar_defaults, {
+          header: {
+            left: 'agendaDay,agendaWeek,month,table',
+            center: 'title',
+            right: 'prev,next today'
+          },
+          height: h - 50,
+          defaultView: fc.fullCalendar('getView').name || fullcalendar_defaults.defaultView,
+          date: date.getDate(),
+          month: date.getMonth(),
+          year: date.getFullYear(),
+          slotMinutes: 60,
+          eventSources: [ src ]
+        }));
+
+        me.quickview_active = id;
+    };
+
     //public method to show the print dialog.
     this.print_calendars = function(view)
     {
@@ -2464,6 +2556,22 @@ function rcube_calendar_ui(settings)
     {
       var source = me.calendars[p.source];
 
+      // helper function to update the given fullcalendar view
+      function update_view(view, event, source) {
+        var existing = view.fullCalendar('clientEvents', event._id);
+        if (existing.length) {
+          $.extend(existing[0], event);
+          view.fullCalendar('updateEvent', existing[0]);
+          // remove old recurrence instances
+          if (event.recurrence && !event.recurrence_id)
+            view.fullCalendar('removeEvents', function(e){ return e._id.indexOf(event._id+'-') == 0; });
+        }
+        else {
+          event.source = source;  // link with source
+          view.fullCalendar('renderEvent', event);
+        }
+      }
+
       if (source && (p.refetch || (p.update && !source.active))) {
         // activate event source if new event was added to an invisible calendar
         if (!source.active) {
@@ -2473,31 +2581,31 @@ function rcube_calendar_ui(settings)
         }
         else
           fc.fullCalendar('refetchEvents', source);
+
+        if (this.quickview_active)
+          $('#quickview-calendar').fullCalendar('refetchEvents');
       }
       // add/update single event object
       else if (source && p.update) {
         var event = p.update;
         event.temp = false;
+
+        // update quickview
+        if (this.quickview_active)
+          update_view($('#quickview-calendar'), event, source);
+          // update fish-eye view
+        if (this.fisheye_date)
+          update_view($('#fish-eye-view'), event, source);
+
+        // update main view
         event.editable = source.editable;
-        var existing = fc.fullCalendar('clientEvents', event._id);
-        if (existing.length) {
-          $.extend(existing[0], event);
-          fc.fullCalendar('updateEvent', existing[0]);
-          // remove old recurrence instances
-          if (event.recurrence && !event.recurrence_id)
-            fc.fullCalendar('removeEvents', function(e){ return e._id.indexOf(event._id+'-') == 0; });
-        }
-        else {
-          event.source = source;  // link with source
-          fc.fullCalendar('renderEvent', event);
-        }
-        // refresh fish-eye view
-        if (me.fisheye_date)
-          me.fisheye_view(me.fisheye_date);
+        update_view(fc, event, source);
       }
       // refetch all calendars
       else if (p.refetch) {
         fc.fullCalendar('refetchEvents');
+        if (this.quickview_active)
+          $('#quickview-calendar').fullCalendar('refetchEvents');
       }
 
       // remove temp events
@@ -2811,6 +2919,18 @@ function rcube_calendar_ui(settings)
       else
         rcmail.display_message(rcmail.gettext('nocalendarsfound','calendar'), 'info');
     });
+    calendars_list.addEventListener('click-item', function(event) {
+      // handle clicks on quickview icon: temprarily add this source and open in quickview
+      if ($(event.target).hasClass('quickview') && event.data) {
+        if (!me.calendars[event.data.id]) {
+          event.data.readonly = true;
+          event.data.active = false;
+          event.data.subscribed = false;
+          add_calendar_source(event.data);
+        }
+        me.quickview(event.data.id);
+      }
+    });
 
     // init (delegate) event handler on calendar list checkboxes
     $(rcmail.gui_objects.calendarslist).on('click', 'input[type=checkbox]', function(e){
@@ -2839,6 +2959,14 @@ function rcube_calendar_ui(settings)
             calendars_list.select(this.value);
             return rcube_event.cancel(e);
         }
+    })
+    // init (delegate) event handler on quickview links
+    .on('click', 'a.quickview', function(e) {
+      var id = $(this).closest('li').attr('id').replace(/^rcmlical/, '');
+      if (me.calendars[id])
+        me.quickview(id);
+      e.stopPropagation();
+      return false;
     });
 
     // register dbl-click handler to open calendar edit dialog
@@ -2859,75 +2987,19 @@ function rcube_calendar_ui(settings)
       viewdate.setTime(fromunixtime(rcmail.env.date));
     
     // initalize the fullCalendar plugin
-    var fc = $('#calendar').fullCalendar({
+    var fc = $('#calendar').fullCalendar($.extend({}, fullcalendar_defaults, {
       header: {
         right: 'prev,next today',
         center: 'title',
         left: 'agendaDay,agendaWeek,month,table'
       },
-      aspectRatio: 1,
       date: viewdate.getDate(),
       month: viewdate.getMonth(),
       year: viewdate.getFullYear(),
-      ignoreTimezone: true,  // will treat the given date strings as in local (browser's) timezone
       height: $('#calendar').height(),
       eventSources: event_sources,
-      monthNames : settings['months'],
-      monthNamesShort : settings['months_short'],
-      dayNames : settings['days'],
-      dayNamesShort : settings['days_short'],
-      firstDay : settings['first_day'],
-      firstHour : settings['first_hour'],
-      slotMinutes : 60/settings['timeslots'],
-      timeFormat: {
-        '': settings['time_format'],
-        agenda: settings['time_format'] + '{ - ' + settings['time_format'] + '}',
-        list: settings['time_format'] + '{ - ' + settings['time_format'] + '}',
-        table: settings['time_format'] + '{ - ' + settings['time_format'] + '}'
-      },
-      axisFormat : settings['time_format'],
-      columnFormat: {
-        month: 'ddd', // Mon
-        week: 'ddd ' + settings['date_short'], // Mon 9/7
-        day: 'dddd ' + settings['date_short'],  // Monday 9/7
-        table: settings['date_agenda']
-      },
-      titleFormat: {
-        month: 'MMMM yyyy',
-        week: settings['dates_long'],
-        day: 'dddd ' + settings['date_long'],
-        table: settings['dates_long']
-      },
-      listPage: 1,  // advance one day in agenda view
-      listRange: settings['agenda_range'],
-      listSections: settings['agenda_sections'],
-      tableCols: ['handle', 'date', 'time', 'title', 'location'],
-      defaultView: rcmail.env.view || settings['default_view'],
-      allDayText: rcmail.gettext('all-day', 'calendar'),
-      buttonText: {
-        prev: (bw.ie6 ? ' << ' : ' ◄ '),
-        next: (bw.ie6 ? ' >> ' : ' ► '),
-        today: settings['today'],
-        day: rcmail.gettext('day', 'calendar'),
-        week: rcmail.gettext('week', 'calendar'),
-        month: rcmail.gettext('month', 'calendar'),
-        table: rcmail.gettext('agenda', 'calendar')
-      },
-      listTexts: {
-        until: rcmail.gettext('until', 'calendar'),
-        past: rcmail.gettext('pastevents', 'calendar'),
-        today: rcmail.gettext('today', 'calendar'),
-        tomorrow: rcmail.gettext('tomorrow', 'calendar'),
-        thisWeek: rcmail.gettext('thisweek', 'calendar'),
-        nextWeek: rcmail.gettext('nextweek', 'calendar'),
-        thisMonth: rcmail.gettext('thismonth', 'calendar'),
-        nextMonth: rcmail.gettext('nextmonth', 'calendar'),
-        future: rcmail.gettext('futureevents', 'calendar'),
-        week: rcmail.gettext('weekofyear', 'calendar')
-      },
       selectable: true,
       selectHelper: false,
-      currentTimeIndicator: settings.time_indicator,
       loading: function(isLoading) {
         me.is_loading = isLoading;
         this._rc_loading = rcmail.set_busy(isLoading, 'loading', this._rc_loading);
@@ -2935,13 +3007,6 @@ function rcube_calendar_ui(settings)
         if (!isLoading)
           me.events_loaded($(this).fullCalendar('clientEvents').length);
       },
-      // event rendering
-      eventRender: fc_event_render,
-      // render element indicating more (invisible) events
-      overflowRender: function(data, element) {
-        element.html(rcmail.gettext('andnmore', 'calendar').replace('$nr', data.count))
-          .click(function(e){ me.fisheye_view(data.date); });
-      },
       // callback for date range selection
       select: function(start, end, allDay, e, view) {
         var range_select = (!allDay || start.getDate() != end.getDate())
@@ -2966,11 +3031,6 @@ function rcube_calendar_ui(settings)
         day_clicked = date.getTime();
         day_clicked_ts = now;
       },
-      // callback when a specific event is clicked
-      eventClick: function(event, ev, view) {
-        if (!event.temp)
-          event_show_dialog(event, ev);
-      },
       // callback when an event was dragged and finally dropped
       eventDrop: function(event, dayDelta, minuteDelta, allDay, revertFunc) {
         if (event.end == null || event.end.getTime() < event.start.getTime()) {
@@ -3040,7 +3100,7 @@ function rcube_calendar_ui(settings)
         if (fc && view.name == 'month')
           fc.fullCalendar('option', 'maxHeight', Math.floor((view.element.parent().height()-18) / 6) - 35);
       }
-    });
+    }));
 
     // format time string
     var formattime = function(hour, minutes, start) {
diff --git a/plugins/calendar/drivers/kolab/kolab_user_calendar.php b/plugins/calendar/drivers/kolab/kolab_user_calendar.php
index c52bfd7..bcfc772 100644
--- a/plugins/calendar/drivers/kolab/kolab_user_calendar.php
+++ b/plugins/calendar/drivers/kolab/kolab_user_calendar.php
@@ -210,8 +210,10 @@ class kolab_user_calendar extends kolab_calendar
       }
     }
 
-    // get events from the user's free/busy feed
-    $this->fetch_freebusy($limit_changed);
+    // get events from the user's free/busy feed (for quickview only)
+    if (!empty($_REQUEST['_quickview']) && empty($search)) {
+      $this->fetch_freebusy($limit_changed);
+    }
 
     $events = array();
     foreach ($this->events as $id => $event) {
@@ -281,7 +283,7 @@ class kolab_user_calendar extends kolab_calendar
 
     // console('_fetch_freebusy', kolab_storage::get_freebusy_url($this->userdata['mail']), $fbdata);
 
-    // parse free-busy information using Horde classes
+    // parse free-busy information
     $count = 0;
     if ($fbdata) {
       $ical = $this->cal->get_ical();
@@ -304,6 +306,7 @@ class kolab_user_calendar extends kolab_calendar
             'start'     => $from,
             'end'       => $to,
             'free_busy' => $statusmap[$type] ?: 'busy',
+            'className' => 'fc-type-freebusy',
             'organizer' => array(
               'email' => $this->userdata['mail'],
               'name'  => $this->userdata['displayname'],
diff --git a/plugins/calendar/lib/calendar_ui.php b/plugins/calendar/lib/calendar_ui.php
index 5e1bd44..4fef691 100644
--- a/plugins/calendar/lib/calendar_ui.php
+++ b/plugins/calendar/lib/calendar_ui.php
@@ -308,6 +308,7 @@ class calendar_ui
         html::span(array('class' => 'calname', 'id' => $label_id, 'title' => $title), $prop['editname'] ? Q($prop['editname']) : $prop['listname']) .
         ($prop['virtual'] ? '' :
           html::tag('input', array('type' => 'checkbox', 'name' => '_cal[]', 'value' => $id, 'checked' => $prop['active'], 'aria-labelledby' => $label_id), '') .
+          html::a(array('href' => '#', 'class' => 'quickview', 'title' => $this->cal->gettext('quickview'), 'role' => 'checkbox', 'aria-checked' => 'false'), '') .
           (isset($prop['subscribed']) ? html::a(array('href' => '#', 'class' => 'subscribed', 'title' => $this->cal->gettext('calendarsubscribe'), 'role' => 'checkbox', 'aria-checked' => $prop['subscribed'] ? 'true' : 'false'), ' ') : '') .
           html::span(array('class' => 'handle', 'style' => "background-color: #" . ($prop['color'] ?: 'f00')), ' ')
         )
diff --git a/plugins/calendar/localization/en_US.inc b/plugins/calendar/localization/en_US.inc
index 80d36cb..87a3e65 100644
--- a/plugins/calendar/localization/en_US.inc
+++ b/plugins/calendar/localization/en_US.inc
@@ -94,6 +94,7 @@ $labels['calsearchresults'] = 'Available Calendars';
 $labels['calendarsubscribe'] = 'List permanently';
 $labels['nocalendarsfound'] = 'No calendars found';
 $labels['nrcalendarsfound'] = '$nr calendars found';
+$labels['quickview'] = 'View only this calendar';
 
 // agenda view
 $labels['listrange'] = 'Range to display:';
diff --git a/plugins/calendar/skins/larry/calendar.css b/plugins/calendar/skins/larry/calendar.css
index d78d9ec..de6aab5 100644
--- a/plugins/calendar/skins/larry/calendar.css
+++ b/plugins/calendar/skins/larry/calendar.css
@@ -219,11 +219,11 @@ pre {
 
 #calendars .treelist li span.calname {
 	display: block;
-	padding: 0px 30px 2px 2px;
+	padding: 0px 18px 2px 2px;
 	position: absolute;
 	top: 7px;
 	left: 38px;
-	right: 40px;
+	right: 60px;
 	cursor: default;
 	background: url(images/calendars.png) right 20px no-repeat;
 	overflow: hidden;
@@ -240,7 +240,7 @@ pre {
 
 #calendars .treelist.flat li span.calname {
 	left: 24px;
-	right: 22px;
+	right: 42px;
 }
 
 #calendars .treelist li span.handle {
@@ -288,6 +288,29 @@ pre {
 	background-position: -16px -110px;
 }
 
+#calendars .treelist li a.quickview {
+	display: inline-block;
+	position: absolute;
+	top: 6px;
+	right: 42px;
+	width: 16px;
+	height: 16px;
+	padding: 0;
+	background: url(images/calendars.png) -100px 0 no-repeat;
+	overflow: hidden;
+	text-indent: -5000px;
+	cursor: pointer;
+}
+
+#calendars .treelist div > a.quickview:focus,
+#calendars .treelist li div:hover > a.quickview {
+	background-position: 0 -128px;
+}
+
+#calendars .treelist li div.focusview > a.quickview {
+	background-position: -18px -128px;
+}
+
 #calendars .treelist li input {
 	position: absolute;
 	top: 5px;
@@ -1316,9 +1339,26 @@ a.dropdown-link:after {
 	bottom: 2px;
 }
 
+#quickview-calendar {
+	padding: 8px;
+	overflow: hidden;
+}
+
 .calendarmain .fc-button,
 .calendarmain .fc-button.fc-state-default,
 .calendarmain .fc-button.fc-state-hover {
+	background-color: #f5f5f5;
+	background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
+	background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
+	background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
+	background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
+	background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);
+	background-position: 0 0;
+}
+
+.calendarmain #calendar .fc-button,
+.calendarmain #calendar .fc-button.fc-state-default,
+.calendarmain #calendar .fc-button.fc-state-hover {
 	margin: 0 0 0 0;
 	height: 20px;
 	line-height: 20px;
@@ -1338,22 +1378,15 @@ a.dropdown-link:after {
 	text-decoration: none;
 }
 
-.calendarmain .fc-button.fc-state-disabled {
+.calendarmain #calendar .fc-button.fc-state-disabled {
 	color: #999;
 	background: #d8d8d8;
 }
 
-.calendarmain .fc-button.fc-state-down {
-	margin: 0;
-	background: #bababa;
-	background: -moz-linear-gradient(top, #bababa 0%, #d8d8d8 100%);
-	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#bababa), color-stop(100%,#d8d8d8));
-	background: -o-linear-gradient(top, #bababa 0%, #d8d8d8 100%);
-	background: -ms-linear-gradient(top, #bababa 0%, #d8d8d8 100%);
-	background: linear-gradient(top, #bababa 0%, #d8d8d8 100%);
-}
-
-.calendarmain .fc-button.fc-state-active {
+.calendarmain .fc-button.fc-state-active,
+.calendarmain .fc-button.fc-state-down,
+.calendarmain #calendar .fc-button.fc-state-active,
+.calendarmain #calendar .fc-button.fc-state-down {
 	color: #333;
 	background: #bababa;
 	background: -moz-linear-gradient(top, #bababa 0%, #d8d8d8 100%);
@@ -1363,12 +1396,12 @@ a.dropdown-link:after {
 	background: linear-gradient(top, #bababa 0%, #d8d8d8 100%);
 }
 
-.calendarmain .fc-header .fc-button {
+.calendarmain #calendar .fc-header .fc-button {
 	margin-left: -1px;
 	margin-right: 0;
 }
 
-.calendarmain .fc-header-left .fc-button {
+.calendarmain #calendar .fc-header-left .fc-button {
 	display: inline-block;
 	margin: 0;
 	text-align: center;
@@ -1393,58 +1426,58 @@ a.dropdown-link:after {
 	outline: none;
 }
 
-.calendarmain .fc-header-left .fc-button:focus {
+.calendarmain #calendar .fc-header-left .fc-button:focus {
 	color: #fff;
 	text-shadow: 0px 1px 1px #666;
 	background-color: rgba(30,150,192, 0.5);
 	border-radius: 3px;
 }
 
-.calendarmain .fc-header-left .fc-button.fc-state-active {
+.calendarmain #calendar .fc-header-left .fc-button.fc-state-active {
 	font-weight: bold;
 	color: #222;
 	text-shadow: none;
 	background-color: transparent;
 }
 
-.calendarmain .fc-header-left .fc-button-agendaDay {
+.calendarmain #calendar .fc-header-left .fc-button-agendaDay {
 	background-position: center -120px;
 }
 
-.calendarmain .fc-header-left .fc-button-agendaDay.fc-state-active {
+.calendarmain #calendar .fc-header-left .fc-button-agendaDay.fc-state-active {
 	background-position: center -160px;
 }
 
-.calendarmain .fc-header-left .fc-button-agendaWeek {
+.calendarmain #calendar .fc-header-left .fc-button-agendaWeek {
 	background-position: center -200px;
 }
 
-.calendarmain .fc-header-left .fc-button-agendaWeek.fc-state-active {
+.calendarmain #calendar .fc-header-left .fc-button-agendaWeek.fc-state-active {
 	background-position: center -240px;
 }
 
-.calendarmain .fc-header-left .fc-button-month {
+.calendarmain #calendar .fc-header-left .fc-button-month {
 	background-position: center -280px;
 }
 
-.calendarmain .fc-header-left .fc-button-month.fc-state-active {
+.calendarmain #calendar .fc-header-left .fc-button-month.fc-state-active {
 	background-position: center -320px;
 }
 
-.calendarmain .fc-header-left .fc-button-table {
+.calendarmain #calendar .fc-header-left .fc-button-table {
 	background-position: center -360px;
 }
 
-.calendarmain .fc-header-left .fc-button-table.fc-state-active {
+.calendarmain #calendar .fc-header-left .fc-button-table.fc-state-active {
 	background-position: center -400px;
 }
 
-.calendarmain .fc-header-right {
+.calendarmain #calendar .fc-header-right {
 	padding-right: 252px;
 	padding-top: 4px;
 }
 
-.fc-header-title {
+.calendarmain #calendar .fc-header-title {
 	padding-top: 5px;
 }
 
@@ -1452,6 +1485,39 @@ a.dropdown-link:after {
 	font-size: 1em !important;
 }
 
+.fc-type-freebusy {
+	opacity: 0.55;
+	color: #fff !important;
+
+	background: rgba(80,80,80,0.85) !important;
+	background: -moz-linear-gradient(top, rgba(80,80,80,0.85) 0%, rgba(48,48,48,0.9) 100%) !important;
+	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(80,80,80,0.85)), color-stop(100%,rgba(48,48,48,0.9))) !important;
+	background: -webkit-linear-gradient(top, rgba(80,80,80,0.85) 0%, rgba(48,48,48,0.85) 100%) !important;
+	background: -o-linear-gradient(top, rgba(80,80,80,0.85) 0%, rgba(48,48,48,0.85) 100%) !important;
+	background: -ms-linear-gradient(top, rgba(80,80,80,0.85) 0%, rgba(48,48,48,0.85) 100%) !important;
+	background: linear-gradient(to bottom, rgba(80,80,80,0.85) 0%, rgba(48,48,48,0.85) 100%) !important;
+
+	-moz-box-shadow: inset 0px 1px 0 0px #888;
+	-webkit-box-shadow: inset 0px 1px 0 0px #888;
+	-o-box-shadow: inset 0px 1px 0 0px #888;
+	box-shadow: inset 0px 1px 0 0px #888;
+
+	border-color: #444 !important;
+	cursor: default !important;
+}
+
+.fc-type-freebusy .fc-event-skin,
+.fc-type-freebusy .fc-event-inner {
+	background-color: transparent !important;
+	border-color: #444 !important;
+	color: #fff !important;
+	text-shadow: 0 1px 1px #000;
+}
+
+.fc-type-freebusy .fc-event-title {
+	display: none;
+}
+
 .calendarmain .fc-event:focus {
 	outline: 1px solid rgba(71,135,177, 0.4);
 	-webkit-box-shadow: 0 0 2px 3px rgba(71,135,177, 0.6);
diff --git a/plugins/calendar/skins/larry/images/calendars.png b/plugins/calendar/skins/larry/images/calendars.png
index 117d329..bf84f3a 100644
Binary files a/plugins/calendar/skins/larry/images/calendars.png and b/plugins/calendar/skins/larry/images/calendars.png differ


commit 30c684026953722e48052eae387ec53bcdabc7dd
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Thu Jun 26 17:40:19 2014 +0200

    Forward clicks on folderlist search results with full node data

diff --git a/plugins/libkolab/js/folderlist.js b/plugins/libkolab/js/folderlist.js
index 543673b..6caf419 100644
--- a/plugins/libkolab/js/folderlist.js
+++ b/plugins/libkolab/js/folderlist.js
@@ -71,6 +71,9 @@ function kolab_folderlist(node, p)
                       node = search_results_widget.get_node(id),
                       has_children = node.children && node.children.length;
 
+                      e.stopPropagation();
+                      e.bubbles = false;
+
                       // activate + subscribe
                       if ($(e.target).hasClass('subscribed')) {
                           search_results[id].subscribed = true;
@@ -98,6 +101,17 @@ function kolab_folderlist(node, p)
                       if (rcube_event.is_keyboard(e)) {
                         $(me.get_item(id, true)).find('input[type=checkbox]').first().focus();
                       }
+                  })
+                  .on('click', function(e) {
+                      var prop, id = String($(e.target).closest('li').attr('id')).replace(new RegExp('^'+p.id_prefix), '');
+                      if (p.id_decode)
+                          id = p.id_decode(id);
+
+                      // forward event
+                      if (prop = search_results[id]) {
+                        e.data = prop;
+                        me.triggerEvent('click-item', e);
+                      }
                   });
           }
 


commit dd2ad15cdcee4a4f4fd608846b3990685dfba623
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Thu Jun 26 15:28:17 2014 +0200

    Remove duplicate function

diff --git a/plugins/calendar/lib/js/fullcalendar.js b/plugins/calendar/lib/js/fullcalendar.js
index dc2fe10..e286310 100644
--- a/plugins/calendar/lib/js/fullcalendar.js
+++ b/plugins/calendar/lib/js/fullcalendar.js
@@ -509,9 +509,9 @@ function Calendar(element, options, eventSources) {
 	// TODO: going forward, most of this stuff should be directly handled by the view
 
 
-	function refetchEvents() { // can be called as an API method
+	function refetchEvents(source) { // can be called as an API method
 		clearEvents();
-		fetchAndRenderEvents();
+		fetchAndRenderEvents(source);
 	}
 
 
@@ -547,18 +547,13 @@ function Calendar(element, options, eventSources) {
 	}
 
 
-	function fetchAndRenderEvents() {
-		fetchEvents(currentView.visStart, currentView.visEnd);
+	function fetchAndRenderEvents(source) {
+		fetchEvents(currentView.visStart, currentView.visEnd, source);
 			// ... will call reportEvents
 			// ... which will call renderEvents
 	}
 
 
-	function refetchEvents(source) {
-		fetchEvents(currentView.visStart, currentView.visEnd, source); // will call reportEvents
-	}
-
-	
 	// called when event data arrives
 	function reportEvents(_events) {
 		events = _events;




More information about the commits mailing list