3 commits - plugins/calendar plugins/libkolab plugins/tasklist

Thomas Brüderli bruederli at kolabsys.com
Mon Sep 8 18:56:57 CEST 2014


 plugins/calendar/calendar_ui.js                          |    2 
 plugins/calendar/drivers/kolab/kolab_driver.php          |   10 +-
 plugins/calendar/drivers/kolab/kolab_user_calendar.php   |   14 ++
 plugins/calendar/lib/calendar_ui.php                     |    2 
 plugins/calendar/skins/larry/calendar.css                |    5 +
 plugins/calendar/skins/larry/images/calendars.png        |binary
 plugins/libkolab/js/folderlist.js                        |   71 +++++++++++++--
 plugins/libkolab/lib/kolab_storage.php                   |   10 ++
 plugins/libkolab/lib/kolab_storage_folder_api.php        |    9 +
 plugins/libkolab/lib/kolab_storage_folder_user.php       |   34 ++++++-
 plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php |    3 
 plugins/tasklist/tasklist.js                             |    2 
 12 files changed, 143 insertions(+), 19 deletions(-)

New commits:
commit dc335c4d26713a1f6e18b263e26540d28df58aa2
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Mon Sep 8 18:56:23 2014 +0200

    Refine virtual user folders handling in new folder navigation according to #3378

diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php
index b9eba2d..fec96f4 100644
--- a/plugins/calendar/drivers/kolab/kolab_driver.php
+++ b/plugins/calendar/drivers/kolab/kolab_driver.php
@@ -93,10 +93,13 @@ class kolab_driver extends calendar_driver
     $this->calendars = array();
 
     foreach ($folders as $folder) {
-      if ($folder instanceof kolab_storage_folder_user)
+      if ($folder instanceof kolab_storage_folder_user) {
         $calendar = new kolab_user_calendar($folder->name, $this->cal);
-      else
+        $calendar->subscriptions = count($folder->children) > 0;
+      }
+      else {
         $calendar = new kolab_calendar($folder->name, $this->cal);
+      }
 
       if ($calendar->ready) {
         $this->calendars[$calendar->id] = $calendar;
@@ -210,7 +213,7 @@ class kolab_driver extends calendar_driver
       }
 
       if ($cal->subscriptions) {
-        $calendars[$cal->id]['subscribed'] = (bool)$cal->is_subscribed();
+        $calendars[$cal->id]['subscribed'] = $cal->is_subscribed();
       }
     }
 
@@ -488,6 +491,7 @@ class kolab_driver extends calendar_driver
         foreach (kolab_storage::list_user_folders($user, 'event', false) as $foldername) {
           $cal = new kolab_calendar($foldername, $this->cal);
           $this->calendars[$cal->id] = $cal;
+          $calendar->subscriptions = true;
         }
       }
 
diff --git a/plugins/calendar/drivers/kolab/kolab_user_calendar.php b/plugins/calendar/drivers/kolab/kolab_user_calendar.php
index 859dc4c..18b1ecc 100644
--- a/plugins/calendar/drivers/kolab/kolab_user_calendar.php
+++ b/plugins/calendar/drivers/kolab/kolab_user_calendar.php
@@ -51,6 +51,7 @@ class kolab_user_calendar extends kolab_calendar
     }
 
     $this->ready = !empty($this->userdata['kolabtargetfolder']);
+    $this->storage->type = 'event';
 
     if ($this->ready) {
       // ID is derrived from the user's kolabtargetfolder attribute
@@ -141,6 +142,15 @@ class kolab_user_calendar extends kolab_calendar
     return false;
   }
 
+  /**
+   * Check subscription status of this folder
+   *
+   * @return boolean True if subscribed, false if not
+   */
+  public function is_subscribed()
+  {
+    return $this->storage->is_subscribed();
+  }
 
   /**
    * Update properties of this calendar folder
@@ -201,7 +211,7 @@ class kolab_user_calendar extends kolab_calendar
 
     // aggregate all calendar folders the user shares (but are not subscribed)
     foreach (kolab_storage::list_user_folders($this->userdata, 'event', false) as $foldername) {
-      if (!kolab_storage::folder_is_subscribed($foldername, true)) {
+      if (!empty($_REQUEST['_quickview']) || !kolab_storage::folder_is_subscribed($foldername, true)) {
         $cal = new kolab_calendar($foldername, $this->cal);
         foreach ($cal->list_events($start, $end, $search, 1) as $event) {
           $this->events[$event['id']] = $event;
@@ -302,7 +312,7 @@ class kolab_user_calendar extends kolab_calendar
             'id'        => md5($this->id . $from->format('U') . '/' . $to->format('U')),
             'calendar'  => $this->id,
             'changed'   => $fb['created'] ?: new DateTime(),
-            'title'     => $titlemap[$type] ?: $type,
+            'title'     => $this->get_name() . ' ' . ($titlemap[$type] ?: $type),
             'start'     => $from,
             'end'       => $to,
             'free_busy' => $statusmap[$type] ?: 'busy',
diff --git a/plugins/calendar/lib/calendar_ui.php b/plugins/calendar/lib/calendar_ui.php
index e66e5f8..2693642 100644
--- a/plugins/calendar/lib/calendar_ui.php
+++ b/plugins/calendar/lib/calendar_ui.php
@@ -298,6 +298,8 @@ class calendar_ui
       $classes[] = 'readonly';
     if ($prop['subscribed'])
       $classes[] = 'subscribed';
+    if ($prop['subscribed'] === 2)
+      $classes[] = 'partial';
     if ($prop['class'])
       $classes[] = $prop['class'];
 
diff --git a/plugins/calendar/skins/larry/calendar.css b/plugins/calendar/skins/larry/calendar.css
index 17efff5..c6a17c1 100644
--- a/plugins/calendar/skins/larry/calendar.css
+++ b/plugins/calendar/skins/larry/calendar.css
@@ -289,6 +289,11 @@ pre {
 	background-position: -16px -110px;
 }
 
+#calendars .treelist div.subscribed.partial a.subscribed,
+#calendars .treelist div.subscribed.partial a.subscribed:focus {
+	background-position: -16px -148px;
+}
+
 #calendars .treelist li a.quickview {
 	display: inline-block;
 	position: absolute;
diff --git a/plugins/calendar/skins/larry/images/calendars.png b/plugins/calendar/skins/larry/images/calendars.png
index 5e53cb6..88eba63 100644
Binary files a/plugins/calendar/skins/larry/images/calendars.png and b/plugins/calendar/skins/larry/images/calendars.png differ
diff --git a/plugins/libkolab/js/folderlist.js b/plugins/libkolab/js/folderlist.js
index 1c8ce2f..b583947 100644
--- a/plugins/libkolab/js/folderlist.js
+++ b/plugins/libkolab/js/folderlist.js
@@ -149,7 +149,8 @@ function kolab_folderlist(node, p)
             prop = search_results[id],
             parent_id = prop.parent || null,
             has_children = node.children && node.children.length,
-            dom_node = has_children ? li.children().first().clone(true, true) : li.children().first();
+            dom_node = has_children ? li.children().first().clone(true, true) : li.children().first(),
+            childs = [];
 
         // find parent node and insert at the right place
         if (parent_id && me.get_node(parent_id)) {
@@ -171,18 +172,58 @@ function kolab_folderlist(node, p)
                 .removeClass('virtual');
         }
         else {
+            // copy childs, too
+            if (has_children && prop.group == 'other user') {
+                for (var cid, j=0; j < node.children.length; j++) {
+                    if ((cid = node.children[j].id) && search_results[cid]) {
+                        childs.push(search_results_widget.get_node(cid));
+                    }
+                }
+            }
+
             // move this result item to the main list widget
             me.insert({
                 id: id,
                 classes: [ prop.group || '' ],
                 virtual: prop.virtual,
                 html: dom_node,
+                level: node.level,
+                collapsed: true,
+                children: childs
             }, parent_id, prop.group);
         }
 
         delete prop.html;
         prop.active = active;
         me.triggerEvent('insert-item', { id: id, data: prop, item: li });
+
+        // register childs, too
+        if (childs.length) {
+            for (var cid, j=0; j < node.children.length; j++) {
+                if ((cid = node.children[j].id) && search_results[cid]) {
+                    prop = search_results[cid];
+                    delete prop.html;
+                    prop.active = false;
+                    me.triggerEvent('insert-item', { id: cid, data: prop });
+                }
+            }
+        }
+    }
+
+    // update the given item's parent's (partial) subscription state
+    function parent_subscription_status(li)
+    {
+        var top_li = li.closest(me.container.children('li')),
+            all_childs = $('li > div:not(.treetoggle)', top_li),
+            subscribed = all_childs.filter('.subscribed').length;
+
+        if (subscribed == 0) {
+            top_li.children('div:first').removeClass('subscribed partial');
+        }
+        else {
+            top_li.children('div:first')
+                .addClass('subscribed')[subscribed < all_childs.length ? 'addClass' : 'removeClass']('partial');
+        }
     }
 
     // do some magic when search is performed on the widget
@@ -242,21 +283,39 @@ function kolab_folderlist(node, p)
     this.container.on('click', 'a.subscribed, span.subscribed', function(e){
         var li = $(this).closest('li'),
             id = li.attr('id').replace(new RegExp('^'+p.id_prefix), ''),
-            div = li.children().first();
+            div = li.children().first(),
+            is_subscribed;
 
-        if (me.is_search())
+        if (me.is_search()) {
           id = id.replace(/--xsR$/, '');
+          li = $(me.get_item(id, true));
+          div = $(div).add(li.children().first());
+        }
 
         if (p.id_decode)
             id = p.id_decode(id);
 
         div.toggleClass('subscribed');
-        $(this).attr('aria-checked', div.hasClass('subscribed') ? 'true' : 'false');
-        me.triggerEvent('subscribe', { id: id, subscribed: div.hasClass('subscribed'), item: li });
+        is_subscribed = div.hasClass('subscribed');
+        $(this).attr('aria-checked', is_subscribed ? 'true' : 'false');
+        me.triggerEvent('subscribe', { id: id, subscribed: is_subscribed, item: li });
+
+        // update subscribe state of all 'virtual user' child folders
+        if (li.hasClass('other user')) {
+            $('ul li > div', li).each(function() {
+                $(this)[is_subscribed ? 'addClass' : 'removeClass']('subscribed');
+                $('.subscribed', div).attr('aria-checked', is_subscribed ? 'true' : 'false');
+            });
+            div.removeClass('partial');
+        }
+        // propagate subscription state to parent  'virtual user' folder
+        else if (li.closest('li.other.user').length) {
+            parent_subscription_status(li);
+        }
 
         e.stopPropagation();
         return false;
-    })
+    });
 
 }
 
diff --git a/plugins/libkolab/lib/kolab_storage.php b/plugins/libkolab/lib/kolab_storage.php
index 144655c..4c29a20 100644
--- a/plugins/libkolab/lib/kolab_storage.php
+++ b/plugins/libkolab/lib/kolab_storage.php
@@ -1534,6 +1534,16 @@ class kolab_storage
                     $folders[$foldername] = new kolab_storage_folder_user($foldername, $other_ns);
                 }
             }
+
+            // for every (subscribed) user folder, list all (unsubscribed) subfolders
+            foreach ($folders as $userfolder) {
+                foreach ((array)self::list_folders($userfolder->name . $delimiter, '*', $type, false, $folderdata) as $foldername) {
+                    if (!$folders[$foldername]) {
+                        $folders[$foldername] = new kolab_storage_folder($foldername, $folderdata[$foldername]);
+                        $userfolder->children[] = $folders[$foldername];
+                    }
+                }
+            }
         }
 
         return $folders;
diff --git a/plugins/libkolab/lib/kolab_storage_folder_api.php b/plugins/libkolab/lib/kolab_storage_folder_api.php
index ef3309e..9e64f4e 100644
--- a/plugins/libkolab/lib/kolab_storage_folder_api.php
+++ b/plugins/libkolab/lib/kolab_storage_folder_api.php
@@ -326,5 +326,14 @@ abstract class kolab_storage_folder_api
         return $subscribed ? kolab_storage::folder_subscribe($this->name) : kolab_storage::folder_unsubscribe($this->name);
     }
 
+    /**
+     * Return folder name as string representation of this object
+     *
+     * @return string Full IMAP folder name
+     */
+    public function __toString()
+    {
+        return $this->name;
+    }
 }
 
diff --git a/plugins/libkolab/lib/kolab_storage_folder_user.php b/plugins/libkolab/lib/kolab_storage_folder_user.php
index 1c37da9..7c141c5 100644
--- a/plugins/libkolab/lib/kolab_storage_folder_user.php
+++ b/plugins/libkolab/lib/kolab_storage_folder_user.php
@@ -26,6 +26,7 @@ class kolab_storage_folder_user extends kolab_storage_folder_virtual
     protected static $ldapcache = array();
 
     public $ldaprec;
+    public $type;
 
     /**
      * Default constructor
@@ -85,13 +86,28 @@ class kolab_storage_folder_user extends kolab_storage_folder_virtual
     }
 
     /**
-     * Check subscription status of this folder
+     * Check subscription status of this folder.
+     * Subscription of a virtual user folder depends on the subscriptions of subfolders.
      *
      * @return boolean True if subscribed, false if not
      */
     public function is_subscribed()
     {
-        return kolab_storage::folder_is_subscribed($this->name, true);
+        if (!empty($this->type)) {
+            $children = $subscribed = 0;
+            $delimiter = $this->imap->get_hierarchy_delimiter();
+            foreach ((array)kolab_storage::list_folders($this->name . $delimiter, '*', $this->type, false) as $subfolder) {
+                if (kolab_storage::folder_is_subscribed($subfolder)) {
+                    $subscribed++;
+                }
+                $children++;
+            }
+            if ($subscribed > 0) {
+                return $subscribed == $children ? true : 2;
+            }
+        }
+
+        return false;
     }
 
     /**
@@ -103,9 +119,17 @@ class kolab_storage_folder_user extends kolab_storage_folder_virtual
      */
     public function subscribe($subscribed)
     {
-        return $subscribed ?
-            kolab_storage::folder_subscribe($this->name, true) :
-            kolab_storage::folder_unsubscribe($this->name, true);
+        $success = false;
+
+        // (un)subscribe all subfolders of a given type
+        if (!empty($this->type)) {
+            $delimiter = $this->imap->get_hierarchy_delimiter();
+            foreach ((array)kolab_storage::list_folders($this->name . $delimiter, '*', $this->type, false) as $subfolder) {
+                $success |= ($subscribed ? kolab_storage::folder_subscribe($subfolder) : kolab_storage::folder_unsubscribe($subfolder));
+            }
+        }
+
+        return $success;
     }
 
 }
\ No newline at end of file


commit 7e6056770ee6c28f33f3f04dead92d5a689deaa0
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Mon Sep 8 18:52:06 2014 +0200

    Don't list all task list on empty search results

diff --git a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
index 253cb62..d757cb7 100644
--- a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
+++ b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
@@ -30,6 +30,7 @@ class tasklist_kolab_driver extends tasklist_driver
     public $attendees   = true;
     public $undelete    = false; // task undelete action
     public $alarm_types = array('DISPLAY','AUDIO');
+    public $search_more_results;
 
     private $rc;
     private $plugin;
@@ -153,7 +154,7 @@ class tasklist_kolab_driver extends tasklist_driver
     public function get_lists(&$tree = null)
     {
         // attempt to create a default list for this user
-        if (empty($this->lists)) {
+        if (empty($this->lists) && !isset($this->search_more_results)) {
             $prop = array('name' => 'Tasks', 'color' => '0000CC', 'default' => true);
             if ($this->create_list($prop))
                 $this->_read_lists(true);


commit 80a4dc75fd2a97a5701df54c292448b075ce64c4
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Wed Aug 27 15:55:34 2014 +0200

    Fix display of the attendee notify checkbox after the changes in ed6eaac9

diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js
index e7bdfa7..b36e2a8 100644
--- a/plugins/calendar/calendar_ui.js
+++ b/plugins/calendar/calendar_ui.js
@@ -726,7 +726,7 @@ function rcube_calendar_ui(settings)
       event_attendees = [];
       attendees_list = $('#edit-attendees-table > tbody').html('');
       resources_list = $('#edit-resources-table > tbody').html('');
-      $('#edit-attendees-notify')[(allow_invitations && (settings.itip_notify & 2) ? 'show' : 'hide')]();
+      $('#edit-attendees-notify')[(allow_invitations && has_attendees(event) && (settings.itip_notify & 2) ? 'show' : 'hide')]();
       $('#edit-localchanges-warning')[(has_attendees(event) && !(allow_invitations || (calendar.owner && is_organizer(event, calendar.owner))) ? 'show' : 'hide')]();
 
       var load_attendees_tab = function()
diff --git a/plugins/tasklist/tasklist.js b/plugins/tasklist/tasklist.js
index 82dd9c4..d5a5778 100644
--- a/plugins/tasklist/tasklist.js
+++ b/plugins/tasklist/tasklist.js
@@ -1985,7 +1985,7 @@ function rcube_tasklist_ui(settings)
 
         task_attendees = [];
         attendees_list = $('#edit-attendees-table > tbody').html('');
-        $('#edit-attendees-notify')[(allow_invitations && (settings.itip_notify & 2) ? 'show' : 'hide')]();
+        $('#edit-attendees-notify')[(allow_invitations && has_attendees(rec) && (settings.itip_notify & 2) ? 'show' : 'hide')]();
         $('#edit-localchanges-warning')[(has_attendees(rec) && !(allow_invitations || (rec.owner && is_organizer(rec, rec.owner))) ? 'show' : 'hide')]();
 
         // attendees (aka assignees)




More information about the commits mailing list