Branch 'roundcubemail-plugins-kolab-3.1' - 6 commits - plugins/calendar plugins/kolab_addressbook plugins/libkolab plugins/tasklist
Thomas Brüderli
bruederli at kolabsys.com
Tue Oct 15 10:32:44 CEST 2013
plugins/calendar/calendar_ui.js | 8 +
plugins/calendar/config.inc.php.dist | 7
plugins/calendar/drivers/kolab/kolab_calendar.php | 21 ++
plugins/calendar/drivers/kolab/kolab_driver.php | 118 ++++++++++++---
plugins/calendar/lib/calendar_ui.php | 15 +
plugins/calendar/localization/de_CH.inc | 1
plugins/calendar/localization/de_DE.inc | 1
plugins/calendar/localization/en_US.inc | 1
plugins/calendar/skins/classic/calendar.css | 7
plugins/calendar/skins/classic/templates/calendar.html | 4
plugins/calendar/skins/larry/calendar.css | 11 +
plugins/calendar/skins/larry/templates/calendar.html | 4
plugins/kolab_addressbook/config.inc.php.dist | 8 +
plugins/kolab_addressbook/kolab_addressbook.js | 24 +++
plugins/kolab_addressbook/kolab_addressbook.php | 1
plugins/kolab_addressbook/lib/kolab_addressbook_ui.php | 7
plugins/kolab_addressbook/lib/rcube_kolab_contacts.php | 18 ++
plugins/kolab_addressbook/localization/de_CH.inc | 2
plugins/kolab_addressbook/localization/de_DE.inc | 2
plugins/kolab_addressbook/localization/en_US.inc | 2
plugins/libkolab/lib/kolab_storage.php | 31 ++-
plugins/libkolab/lib/kolab_storage_folder.php | 2
plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php | 83 ++++++++++
plugins/tasklist/skins/larry/tasklist.css | 9 +
plugins/tasklist/tasklist.js | 4
plugins/tasklist/tasklist_ui.php | 13 +
26 files changed, 353 insertions(+), 51 deletions(-)
New commits:
commit 79b6799a58b6b8945ab1e1de0a0a509910b3ee4d
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date: Tue Oct 15 10:31:52 2013 +0200
Limit virtual folder tree to task/calendar main views
diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php
index 3df498d..cffe6b1 100644
--- a/plugins/calendar/drivers/kolab/kolab_driver.php
+++ b/plugins/calendar/drivers/kolab/kolab_driver.php
@@ -109,7 +109,7 @@ class kolab_driver extends calendar_driver
$calendars = $names = array();
// include virtual folders for a full folder tree
- if (!$active && !$personal && !$this->rc->output->ajax_call)
+ if (!$active && !$personal && !$this->rc->output->ajax_call && in_array($this->rc->action, array('index','')))
$folders = $this->_folder_hierarchy($folders, $this->rc->get_storage()->get_hierarchy_delimiter());
foreach ($folders as $id => $cal) {
diff --git a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
index 3c6690a..787ced4 100644
--- a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
+++ b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
@@ -84,7 +84,7 @@ class tasklist_kolab_driver extends tasklist_driver
$listnames = array();
// include virtual folders for a full folder tree
- if (!$this->rc->output->ajax_call)
+ if (!$this->rc->output->ajax_call && in_array($this->rc->action, array('index','')))
$folders = $this->_folder_hierarchy($folders, $delim);
foreach ($folders as $folder) {
commit eef0a950680aa1a498134ee165e203a1a88eb1cc
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date: Thu Oct 10 17:27:24 2013 +0200
Show complete folder hierarchy in calendars and tasklist listings with non-clickable virtual parent folders
diff --git a/plugins/calendar/drivers/kolab/kolab_calendar.php b/plugins/calendar/drivers/kolab/kolab_calendar.php
index 877c3f5..d238e90 100644
--- a/plugins/calendar/drivers/kolab/kolab_calendar.php
+++ b/plugins/calendar/drivers/kolab/kolab_calendar.php
@@ -33,6 +33,7 @@ class kolab_calendar
public $alarms = false;
public $categories = array();
public $storage;
+ public $name;
private $cal;
private $events = array();
@@ -48,7 +49,7 @@ class kolab_calendar
$this->cal = $calendar;
if (strlen($imap_folder))
- $this->imap_folder = $imap_folder;
+ $this->imap_folder = $this->name = $imap_folder;
// ID is derrived from folder name
$this->id = kolab_storage::folder_id($this->imap_folder);
diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php
index 05fd0e4..3df498d 100644
--- a/plugins/calendar/drivers/kolab/kolab_driver.php
+++ b/plugins/calendar/drivers/kolab/kolab_driver.php
@@ -105,31 +105,79 @@ class kolab_driver extends calendar_driver
}
}
- $calendars = $this->filter_calendars(false, $active, $personal);
- $names = array();
-
- foreach ($calendars as $id => $cal) {
- $name = kolab_storage::folder_displayname($cal->get_name(), $names);
-
- $calendars[$id] = array(
- 'id' => $cal->id,
- 'name' => $name,
- 'editname' => $cal->get_foldername(),
- 'color' => $cal->get_color(),
- 'readonly' => $cal->readonly,
- 'showalarms' => $cal->alarms,
- 'class_name' => $cal->get_namespace(),
- 'default' => $cal->storage->default,
- 'active' => $cal->storage->is_active(),
- 'owner' => $cal->get_owner(),
- 'children' => true, // TODO: determine if that folder indeed has child folders
- 'caldavurl' => $cal->get_caldav_url(),
- );
+ $folders = $this->filter_calendars(false, $active, $personal);
+ $calendars = $names = array();
+
+ // include virtual folders for a full folder tree
+ if (!$active && !$personal && !$this->rc->output->ajax_call)
+ $folders = $this->_folder_hierarchy($folders, $this->rc->get_storage()->get_hierarchy_delimiter());
+
+ foreach ($folders as $id => $cal) {
+ $fullname = $cal->get_name();
+ $name = kolab_storage::folder_displayname($fullname, $names);
+
+ // special handling for virtual folders
+ if ($cal->virtual) {
+ $calendars[$cal->id] = array(
+ 'id' => $cal->id,
+ 'name' => $name,
+ 'virtual' => true,
+ );
+ }
+ else {
+ $calendars[$cal->id] = array(
+ 'id' => $cal->id,
+ 'name' => $name,
+ 'altname' => $fullname,
+ 'editname' => $cal->get_foldername(),
+ 'color' => $cal->get_color(),
+ 'readonly' => $cal->readonly,
+ 'showalarms' => $cal->alarms,
+ 'class_name' => $cal->get_namespace(),
+ 'default' => $cal->storage->default,
+ 'active' => $cal->storage->is_active(),
+ 'owner' => $cal->get_owner(),
+ 'children' => true, // TODO: determine if that folder indeed has child folders
+ 'caldavurl' => $cal->get_caldav_url(),
+ );
+ }
}
return $calendars;
}
+ /**
+ * Check the folder tree and add the missing parents as virtual folders
+ */
+ private function _folder_hierarchy($folders, $delim)
+ {
+ $parents = array();
+ $existing = array_map(function($folder){ return $folder->get_name(); }, $folders);
+ foreach ($folders as $id => $folder) {
+ $path = explode($delim, $folder->name);
+ array_pop($path);
+
+ // skip top folders or ones with a custom displayname
+ if (count($path) <= 1 || kolab_storage::custom_displayname($folder->name))
+ continue;
+
+ while (count($path) > 1 && ($parent = join($delim, $path))) {
+ if (!in_array($parent, $existing) && !$parents[$parent]) {
+ $name = kolab_storage::object_name($parent, $folder->get_namespace());
+ $parents[$parent] = new virtual_kolab_calendar($name, $folder->get_namespace());
+ $parents[$parent]->id = kolab_storage::folder_id($parent);
+ }
+ array_pop($path);
+ }
+ }
+
+ // add virtual parents to the list and sort again
+ if (count($parents)) {
+ $folders = kolab_storage::sort_folders(array_merge($folders, array_values($parents)));
+ }
+
+ return $folders;
+ }
/**
* Get list of calendars according to specified filters
@@ -1041,7 +1089,7 @@ class kolab_driver extends calendar_driver
// Disable folder name input
if (!empty($options) && ($options['norename'] || $options['protected'])) {
$input_name = new html_hiddenfield(array('name' => 'name', 'id' => 'calendar-name'));
- $formfields['name']['value'] = Q(str_replace($delim, ' » ', kolab_storage::object_name($folder)))
+ $formfields['name']['value'] = kolab_storage::object_name($folder)
. $input_name->show($folder);
}
@@ -1229,3 +1277,32 @@ class kolab_driver extends calendar_driver
}
}
+
+
+/**
+ * Helper class that represents a virtual IMAP folder
+ * with a subset of the kolab_calendar API.
+ */
+class virtual_kolab_calendar
+{
+ public $name;
+ public $namespace;
+ public $virtual = true;
+
+ public function __construct($name, $ns)
+ {
+ $this->name = $name;
+ $this->namespace = $ns;
+ }
+
+ public function get_name()
+ {
+ return $this->name;
+ }
+
+ public function get_namespace()
+ {
+ return $this->namespace;
+ }
+}
+
diff --git a/plugins/calendar/lib/calendar_ui.php b/plugins/calendar/lib/calendar_ui.php
index 23a335a..9ea93ef 100644
--- a/plugins/calendar/lib/calendar_ui.php
+++ b/plugins/calendar/lib/calendar_ui.php
@@ -194,21 +194,24 @@ class calendar_ui
$prop['attachments'] = $this->cal->driver->attachments;
$prop['undelete'] = $this->cal->driver->undelete;
$prop['feedurl'] = $this->cal->get_url(array('_cal' => $this->cal->ical_feed_hash($id) . '.ics', 'action' => 'feed'));
- $jsenv[$id] = $prop;
+
+ if (!$prop['virtual'])
+ $jsenv[$id] = $prop;
$html_id = html_identifier($id);
$class = 'cal-' . asciiwords($id, true);
- $listname = html_entity_decode($prop['name'], ENT_COMPAT, RCMAIL_CHARSET);
- $title = strlen($listname) > 25 ? $listname : '';
+ $title = !empty($prop['altname']) && $prop['altname'] != $prop['name'] ? html_entity_decode($prop['altname'], ENT_COMPAT, RCMAIL_CHARSET) : '';
- if ($prop['readonly'])
+ if ($prop['virtual'])
+ $class .= ' virtual';
+ else if ($prop['readonly'])
$class .= ' readonly';
if ($prop['class_name'])
$class .= ' '.$prop['class_name'];
$li .= html::tag('li', array('id' => 'rcmlical' . $html_id, 'class' => $class),
- html::tag('input', array('type' => 'checkbox', 'name' => '_cal[]', 'value' => $id, 'checked' => $prop['active']), '') .
- html::span('handle', ' ') .
+ ($prop['virtual'] ? '' : html::tag('input', array('type' => 'checkbox', 'name' => '_cal[]', 'value' => $id, 'checked' => $prop['active']), '') .
+ html::span('handle', ' ')) .
html::span(array('class' => 'calname', 'title' => $title), $prop['name']));
}
diff --git a/plugins/calendar/skins/classic/calendar.css b/plugins/calendar/skins/classic/calendar.css
index 835bdac..c646b0d 100644
--- a/plugins/calendar/skins/classic/calendar.css
+++ b/plugins/calendar/skins/classic/calendar.css
@@ -164,6 +164,10 @@ pre {
background-position: 0 -92px;
}
+#calendarslist li.virtual span.calname {
+ color: #666;
+}
+
#calfeedurl,
#caldavurl {
width: 98%;
diff --git a/plugins/calendar/skins/larry/calendar.css b/plugins/calendar/skins/larry/calendar.css
index 8775b2a..48160ad 100644
--- a/plugins/calendar/skins/larry/calendar.css
+++ b/plugins/calendar/skins/larry/calendar.css
@@ -157,6 +157,10 @@ pre {
position: relative;
}
+#calendarslist li.virtual {
+ padding-top: 2px;
+}
+
#calendarslist li label {
display: block;
}
@@ -225,6 +229,10 @@ pre {
background-position: right -92px;
}
+#calendarslist li.virtual span.calname {
+ color: #aaa;
+}
+
#calfeedurl,
#caldavurl {
width: 98%;
diff --git a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
index 90772ac..3c6690a 100644
--- a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
+++ b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
@@ -80,21 +80,36 @@ class tasklist_kolab_driver extends tasklist_driver
}
$delim = $this->rc->get_storage()->get_hierarchy_delimiter();
+ $prefs = $this->rc->config->get('kolab_tasklists', array());
$listnames = array();
- $prefs = $this->rc->config->get('kolab_tasklists', array());
+ // include virtual folders for a full folder tree
+ if (!$this->rc->output->ajax_call)
+ $folders = $this->_folder_hierarchy($folders, $delim);
foreach ($folders as $folder) {
$utf7name = $folder->name;
- $this->folders[$folder->name] = $folder;
$path_imap = explode($delim, $utf7name);
$editname = rcube_charset::convert(array_pop($path_imap), 'UTF7-IMAP'); // pop off raw name part
$path_imap = join($delim, $path_imap);
- $name = kolab_storage::folder_displayname(kolab_storage::object_name($utf7name), $listnames);
+ $fullname = kolab_storage::object_name($utf7name);
+ $name = kolab_storage::folder_displayname($fullname, $listnames);
+
+ // special handling for virtual folders
+ if ($folder->virtual) {
+ $list_id = kolab_storage::folder_id($utf7name);
+ $this->lists[$list_id] = array(
+ 'id' => $list_id,
+ 'name' => $name,
+ 'virtual' => true,
+ );
+ continue;
+ }
if ($folder->get_namespace() == 'personal') {
+ $norename = false;
$readonly = false;
$alarms = true;
}
@@ -105,16 +120,20 @@ class tasklist_kolab_driver extends tasklist_driver
if (strpos($rights, 'i') !== false)
$readonly = false;
}
+ $info = $folder->get_folder_info();
+ $norename = $readonly || $info['norename'] || $info['protected'];
}
$list_id = kolab_storage::folder_id($utf7name);
$tasklist = array(
'id' => $list_id,
'name' => $name,
+ 'altname' => $fullname,
'editname' => $editname,
'color' => $folder->get_color('0000CC'),
'showalarms' => isset($prefs[$list_id]['showalarms']) ? $prefs[$list_id]['showalarms'] : $alarms,
- 'editable' => !$readonly,
+ 'editable' => !$readionly,
+ 'norename' => $norename,
'active' => $folder->is_active(),
'parentfolder' => $path_imap,
'default' => $folder->default,
@@ -123,9 +142,42 @@ class tasklist_kolab_driver extends tasklist_driver
);
$this->lists[$tasklist['id']] = $tasklist;
$this->folders[$tasklist['id']] = $folder;
+ $this->folders[$folder->name] = $folder;
+ }
+ }
+
+ /**
+ * Check the folder tree and add the missing parents as virtual folders
+ */
+ private function _folder_hierarchy($folders, $delim)
+ {
+ $parents = array();
+ $existing = array_map(function($folder){ return $folder->name; }, $folders);
+ foreach ($folders as $id => $folder) {
+ $path = explode($delim, $folder->name);
+ array_pop($path);
+
+ // skip top folders or ones with a custom displayname
+ if (count($path) <= 1 || kolab_storage::custom_displayname($folder->name))
+ continue;
+
+ while (count($path) > 1 && ($parent = join($delim, $path))) {
+ if (!in_array($parent, $existing) && !$parents[$parent]) {
+ $parents[$parent] = new virtual_kolab_storage_folder($parent, $folder->get_namespace());
+ }
+ array_pop($path);
+ }
}
+
+ // add virtual parents to the list and sort again
+ if (count($parents)) {
+ $folders = kolab_storage::sort_folders(array_merge($folders, array_values($parents)));
+ }
+
+ return $folders;
}
+
/**
* Get a list of available task lists from this source
*/
@@ -848,3 +900,26 @@ class tasklist_kolab_driver extends tasklist_driver
}
}
+
+/**
+ * Helper class that represents a virtual IMAP folder
+ * with a subset of the kolab_storage_folder API.
+ */
+class virtual_kolab_storage_folder
+{
+ public $name;
+ public $namespace;
+ public $virtual = true;
+
+ public function __construct($name, $ns)
+ {
+ $this->name = $name;
+ $this->namespace = $ns;
+ }
+
+ public function get_namespace()
+ {
+ return $this->namespace;
+ }
+}
+
diff --git a/plugins/tasklist/skins/larry/tasklist.css b/plugins/tasklist/skins/larry/tasklist.css
index 5582bad..173704d 100644
--- a/plugins/tasklist/skins/larry/tasklist.css
+++ b/plugins/tasklist/skins/larry/tasklist.css
@@ -195,6 +195,11 @@ body.attachmentwin #topnav .topright {
white-space: nowrap;
}
+#tasklists li.virtual {
+ padding-top: 4px;
+ height: 16px;
+}
+
#tasklists li label {
display: block;
}
@@ -240,6 +245,10 @@ body.attachmentwin #topnav .topright {
background-position: right -214px;
}
+#tasklists li.virtual span.listname {
+ color: #aaa;
+}
+
#tasklists li input {
position: absolute;
top: 5px;
diff --git a/plugins/tasklist/tasklist.js b/plugins/tasklist/tasklist.js
index 7d91e07..bfe19d5 100644
--- a/plugins/tasklist/tasklist.js
+++ b/plugins/tasklist/tasklist.js
@@ -1413,7 +1413,7 @@ function rcube_tasklist_ui(settings)
list = { name:'', editable:true, showalarms:true };
// fill edit form
- var name = $('#taskedit-tasklistame').prop('disabled', !list.editable).val(list.editname || list.name),
+ var name = $('#taskedit-tasklistame').prop('disabled', list.norename||false).val(list.editname || list.name),
alarms = $('#taskedit-showalarms').prop('checked', list.showalarms).get(0),
parent = $('#taskedit-parentfolder').val(list.parentfolder);
@@ -1465,7 +1465,7 @@ function rcube_tasklist_ui(settings)
function list_remove(id)
{
var list = me.tasklists[id];
- if (list && list.editable && confirm(rcmail.gettext(list.children ? 'deletelistconfirmrecursive' : 'deletelistconfirm', 'tasklist'))) {
+ if (list && !list.norename && confirm(rcmail.gettext(list.children ? 'deletelistconfirmrecursive' : 'deletelistconfirm', 'tasklist'))) {
saving_lock = rcmail.set_busy(true, 'tasklist.savingdata');
rcmail.http_post('tasklist', { action:'remove', l:{ id:list.id } });
return true;
diff --git a/plugins/tasklist/tasklist_ui.php b/plugins/tasklist/tasklist_ui.php
index 66a7ab0..99d0875 100644
--- a/plugins/tasklist/tasklist_ui.php
+++ b/plugins/tasklist/tasklist_ui.php
@@ -100,20 +100,23 @@ class tasklist_ui
$prop['undelete'] = $this->plugin->driver->undelete;
$prop['sortable'] = $this->plugin->driver->sortable;
$prop['attachments'] = $this->plugin->driver->attachments;
- $jsenv[$id] = $prop;
+
+ if (!$prop['virtual'])
+ $jsenv[$id] = $prop;
$html_id = html_identifier($id);
$class = 'tasks-' . asciiwords($id, true);
- $listname = html_entity_decode($prop['name'], ENT_COMPAT, RCMAIL_CHARSET);
- $title = strlen($listname) > 25 ? $listname : '';
+ $title = !empty($prop['altname']) && $prop['altname'] != $prop['name'] ? html_entity_decode($prop['altname'], ENT_COMPAT, RCMAIL_CHARSET) : '';
- if (!$prop['editable'])
+ if ($prop['virtual'])
+ $class .= ' virtual';
+ else if (!$prop['editable'])
$class .= ' readonly';
if ($prop['class_name'])
$class .= ' '.$prop['class_name'];
$li .= html::tag('li', array('id' => 'rcmlitasklist' . $html_id, 'class' => $class),
- html::tag('input', array('type' => 'checkbox', 'name' => '_list[]', 'value' => $id, 'checked' => $prop['active'])) .
+ ($prop['virtual'] ? '' : html::tag('input', array('type' => 'checkbox', 'name' => '_list[]', 'value' => $id, 'checked' => $prop['active']))) .
html::span('handle', ' ') .
html::span(array('class' => 'listname', 'title' => $title), $prop['name']));
}
commit c5b3ba8770ec519f13d3fe4bf7873082be368cc9
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date: Thu Oct 10 17:07:20 2013 +0200
Also list unsubscribed folders for parent-selector
diff --git a/plugins/libkolab/lib/kolab_storage.php b/plugins/libkolab/lib/kolab_storage.php
index 8c28955..1e44de1 100644
--- a/plugins/libkolab/lib/kolab_storage.php
+++ b/plugins/libkolab/lib/kolab_storage.php
@@ -103,15 +103,16 @@ class kolab_storage
* Get a list of storage folders for the given data type
*
* @param string Data type to list folders for (contact,distribution-list,event,task,note)
+ * @param boolean Enable to return subscribed folders only (null to use configured subscription mode)
*
* @return array List of Kolab_Folder objects (folder names in UTF7-IMAP)
*/
- public static function get_folders($type)
+ public static function get_folders($type, $subscribed = null)
{
$folders = $folderdata = array();
if (self::setup()) {
- foreach ((array)self::list_folders('', '*', $type, null, $folderdata) as $foldername) {
+ foreach ((array)self::list_folders('', '*', $type, $subscribed, $folderdata) as $foldername) {
$folders[$foldername] = new kolab_storage_folder($foldername, $folderdata[$foldername]);
}
}
@@ -516,7 +517,7 @@ class kolab_storage
public static function folder_selector($type, $attrs, $current = '')
{
// get all folders of specified type
- $folders = self::get_folders($type);
+ $folders = self::get_folders($type, false);
$delim = self::$imap->get_hierarchy_delimiter();
$names = array();
commit d0c414e8e8de4c2d3d5a4c8ab56fba0dd8ceaeaa
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date: Thu Oct 10 16:46:20 2013 +0200
Make some getter methods available for others
diff --git a/plugins/libkolab/lib/kolab_storage.php b/plugins/libkolab/lib/kolab_storage.php
index ebfddcb..8c28955 100644
--- a/plugins/libkolab/lib/kolab_storage.php
+++ b/plugins/libkolab/lib/kolab_storage.php
@@ -395,11 +395,8 @@ class kolab_storage
self::setup();
// find custom display name in folder METADATA
- if (self::$config->get('kolab_custom_display_names', true)) {
- $metadata = self::$imap->get_metadata($folder, array(self::NAME_KEY_PRIVATE, self::NAME_KEY_SHARED));
- if (($name = $metadata[$folder][self::NAME_KEY_PRIVATE]) || ($name = $metadata[$folder][self::NAME_KEY_SHARED])) {
- return $name;
- }
+ if ($name = self::custom_displayname($folder)) {
+ return $name;
}
$found = false;
@@ -468,6 +465,21 @@ class kolab_storage
return $folder;
}
+ /**
+ * Get custom display name (saved in metadata) for the given folder
+ */
+ public static function custom_displayname($folder)
+ {
+ // find custom display name in folder METADATA
+ if (self::$config->get('kolab_custom_display_names', true)) {
+ $metadata = self::$imap->get_metadata($folder, array(self::NAME_KEY_PRIVATE, self::NAME_KEY_SHARED));
+ if (($name = $metadata[$folder][self::NAME_KEY_PRIVATE]) || ($name = $metadata[$folder][self::NAME_KEY_SHARED])) {
+ return $name;
+ }
+ }
+
+ return false;
+ }
/**
* Helper method to generate a truncated folder name to display
@@ -482,7 +494,7 @@ class kolab_storage
$length = strlen($names[$i] . ' » ');
$prefix = substr($name, 0, $length);
$count = count(explode(' » ', $prefix));
- $name = str_repeat(' ', $count-1) . '» ' . substr($name, $length);
+ $name = str_repeat(' ', $count-1) . '» ' . substr($name, $length);
break;
}
}
diff --git a/plugins/libkolab/lib/kolab_storage_folder.php b/plugins/libkolab/lib/kolab_storage_folder.php
index 294755b..896061e 100644
--- a/plugins/libkolab/lib/kolab_storage_folder.php
+++ b/plugins/libkolab/lib/kolab_storage_folder.php
@@ -92,7 +92,7 @@ class kolab_storage_folder
/**
*
*/
- private function get_folder_info()
+ public function get_folder_info()
{
if (!isset($this->info))
$this->info = $this->imap->folder_info($this->name);
commit 3d494afddb626d60ba7012911772ec44aad36bf3
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date: Thu Oct 3 12:44:41 2013 +0200
Add option to display direct CardDAV urls for Kolab address books in the Roundcube UI
diff --git a/plugins/kolab_addressbook/config.inc.php.dist b/plugins/kolab_addressbook/config.inc.php.dist
index 02745c8..0a0decf 100644
--- a/plugins/kolab_addressbook/config.inc.php.dist
+++ b/plugins/kolab_addressbook/config.inc.php.dist
@@ -11,4 +11,12 @@
*/
$rcmail_config['kolab_addressbook_prio'] = 0;
+// Base URL to build fully qualified URIs to access calendars via CALDAV
+// The following replacement variables are supported:
+// %h - Current HTTP host
+// %u - Current webmail user name
+// %n - Folder name
+// %i - Folder UUID
+// $rcmail_config['kolab_addressbook_carddav_url'] = 'http://%h/iRony/addressbooks/%u/%i';
+
?>
diff --git a/plugins/kolab_addressbook/kolab_addressbook.js b/plugins/kolab_addressbook/kolab_addressbook.js
index b024fab..5824880 100644
--- a/plugins/kolab_addressbook/kolab_addressbook.js
+++ b/plugins/kolab_addressbook/kolab_addressbook.js
@@ -18,6 +18,7 @@ rcube_webmail.prototype.set_book_actions = function()
this.enable_command('book-create', true);
this.enable_command('book-edit', 'book-delete', source && sources[source] && sources[source].kolab && sources[source].editable);
+ this.enable_command('book-showurl', source && sources[source] && sources[source].carddavurl);
};
rcube_webmail.prototype.book_create = function()
@@ -38,6 +39,29 @@ rcube_webmail.prototype.book_delete = function()
}
};
+rcube_webmail.prototype.book_showurl = function()
+{
+ var source = this.env.source ? this.env.address_sources[this.env.source] : null;
+ if (source && source.carddavurl) {
+ $('div.showurldialog:ui-dialog').dialog('close');
+
+ var $dialog = $('<div>').addClass('showurldialog').append('<p>'+rcmail.gettext('carddavurldescription', 'kolab_addressbook')+'</p>'),
+ textbox = $('<textarea>').addClass('urlbox').css('width', '100%').attr('rows', 2).appendTo($dialog);
+
+ $dialog.dialog({
+ resizable: true,
+ closeOnEscape: true,
+ title: rcmail.gettext('bookshowurl', 'kolab_addressbook'),
+ close: function() {
+ $dialog.dialog("destroy").remove();
+ },
+ width: 520
+ }).show();
+
+ textbox.val(source.carddavurl).select();
+ }
+};
+
// displays page with book edit/create form
rcube_webmail.prototype.book_show_contentframe = function(action, framed)
{
diff --git a/plugins/kolab_addressbook/kolab_addressbook.php b/plugins/kolab_addressbook/kolab_addressbook.php
index d6f0d6d..a3f480c 100644
--- a/plugins/kolab_addressbook/kolab_addressbook.php
+++ b/plugins/kolab_addressbook/kolab_addressbook.php
@@ -117,6 +117,7 @@ class kolab_addressbook extends rcube_plugin
'undelete' => $abook->undelete && $undelete,
'realname' => rcube_charset::convert($abook->get_realname(), 'UTF7-IMAP'), // IMAP folder name
'class_name' => $abook->get_namespace(),
+ 'carddavurl' => $abook->get_carddav_url(),
'kolab' => true,
);
}
diff --git a/plugins/kolab_addressbook/lib/kolab_addressbook_ui.php b/plugins/kolab_addressbook/lib/kolab_addressbook_ui.php
index 7546046..5e4e4d5 100644
--- a/plugins/kolab_addressbook/lib/kolab_addressbook_ui.php
+++ b/plugins/kolab_addressbook/lib/kolab_addressbook_ui.php
@@ -58,6 +58,10 @@ class kolab_addressbook_ui
$options = array('book-create', 'book-edit', 'book-delete');
$idx = 0;
+ if ($this->rc->config->get('kolab_addressbook_carddav_url')) {
+ $options[] = 'book-showurl';
+ }
+
foreach ($options as $command) {
$content = html::tag('li', $idx ? null : array('class' => 'separator_above'),
$this->plugin->api->output->button(array(
@@ -82,7 +86,8 @@ class kolab_addressbook_ui
$this->plugin->api->add_content($content, 'groupoptions');
$this->rc->output->add_label('kolab_addressbook.bookdeleteconfirm',
- 'kolab_addressbook.bookdeleting');
+ 'kolab_addressbook.bookdeleting', 'kolab_addressbook.bookshowurl',
+ 'kolab_addressbook.carddavurldescription');
}
// book create/edit form
else {
diff --git a/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php b/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php
index 365e251..13c7740 100644
--- a/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php
+++ b/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php
@@ -178,6 +178,24 @@ class rcube_kolab_contacts extends rcube_addressbook
return $this->namespace;
}
+ /**
+ * Compose an URL for CardDAV access to this address book (if configured)
+ */
+ public function get_carddav_url()
+ {
+ $url = null;
+ $rcmail = rcmail::get_instance();
+ if ($template = $rcmail->config->get('kolab_addressbook_carddav_url', null)) {
+ return strtr($template, array(
+ '%h' => $_SERVER['HTTP_HOST'],
+ '%u' => urlencode($rcmail->get_user_name()),
+ '%i' => urlencode($this->storagefolder->get_uid()),
+ '%n' => urlencode($this->imap_folder),
+ ));
+ }
+
+ return false;
+ }
/**
* Setter for the current group
diff --git a/plugins/kolab_addressbook/localization/de_CH.inc b/plugins/kolab_addressbook/localization/de_CH.inc
index 3439448..130564b 100644
--- a/plugins/kolab_addressbook/localization/de_CH.inc
+++ b/plugins/kolab_addressbook/localization/de_CH.inc
@@ -25,6 +25,8 @@ $labels['bookdelete'] = 'Adressbuch löschen';
$labels['bookproperties'] = 'Eigenschaften des Adressbuchs';
$labels['bookname'] = 'Name des Buches';
$labels['parentbook'] = 'Ãbergeordnetes Buch';
+$labels['bookshowurl'] = 'CardDAV-URL anzeigen';
+$labels['carddavurldescription'] = 'Benutzen Sie folgende Addresse in einer <a href="http://en.wikipedia.org/wiki/CardDAV" target="_blank">CalDAV</a>-Anwendung um dieses spezifische Adressbuch mit dem Computer oder Mobiltelefon zu synchronisieren.';
$labels['addressbookprio'] = 'Reihenfolge der Adressbücher';
$labels['personalfirst'] = 'Private(s) Adressbuch/Adressbücher zuerst';
diff --git a/plugins/kolab_addressbook/localization/de_DE.inc b/plugins/kolab_addressbook/localization/de_DE.inc
index 2c2a5d2..8f44c8f 100644
--- a/plugins/kolab_addressbook/localization/de_DE.inc
+++ b/plugins/kolab_addressbook/localization/de_DE.inc
@@ -25,6 +25,8 @@ $labels['bookdelete'] = 'Adressbuch löschen';
$labels['bookproperties'] = 'Eigenschaften des Adressbuchs';
$labels['bookname'] = 'Name des Buches';
$labels['parentbook'] = 'Ãbergeordnetes Buch';
+$labels['bookshowurl'] = 'CardDAV-URL anzeigen';
+$labels['carddavurldescription'] = 'Benutzen Sie folgende Addresse in einer <a href="http://en.wikipedia.org/wiki/CardDAV" target="_blank">CalDAV</a>-Anwendung um dieses spezifische Adressbuch mit dem Computer oder Mobiltelefon zu synchronisieren.';
$labels['addressbookprio'] = 'Reihenfolge der Adressbücher';
$labels['personalfirst'] = 'Private(s) Adressbuch/Adressbücher zuerst';
diff --git a/plugins/kolab_addressbook/localization/en_US.inc b/plugins/kolab_addressbook/localization/en_US.inc
index a66426f..c1ab0f5 100644
--- a/plugins/kolab_addressbook/localization/en_US.inc
+++ b/plugins/kolab_addressbook/localization/en_US.inc
@@ -25,6 +25,8 @@ $labels['bookdelete'] = 'Delete address book';
$labels['bookproperties'] = 'Address book properties';
$labels['bookname'] = 'Book name';
$labels['parentbook'] = 'Superior book';
+$labels['bookshowurl'] = 'Show CardDAV URL';
+$labels['carddavurldescription'] = 'Copy this address to a <a href="http://en.wikipedia.org/wiki/CardDAV" target="_blank">CardDAV</a> client application to fully synchronize this specific address book with your computer or mobile device.';
$labels['addressbookprio'] = 'Address book(s) selection/behaviour';
$labels['personalfirst'] = 'Personal address book(s) first';
commit a604dbd3e47168ea31ca13b73fdce843774c9818
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date: Thu Oct 3 12:07:02 2013 +0200
Add option to display direct CalDAV urls for calendars in the UI
diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js
index 2747641..81e350f 100644
--- a/plugins/calendar/calendar_ui.js
+++ b/plugins/calendar/calendar_ui.js
@@ -2009,6 +2009,14 @@ function rcube_calendar_ui(settings)
$dialog.dialog('close');
if (calendar.feedurl) {
+ if (calendar.caldavurl) {
+ $('#caldavurl').val(calendar.caldavurl);
+ $('#calendarcaldavurl').show();
+ }
+ else {
+ $('#calendarcaldavurl').hide();
+ }
+
$dialog.dialog({
resizable: true,
closeOnEscape: true,
diff --git a/plugins/calendar/config.inc.php.dist b/plugins/calendar/config.inc.php.dist
index a8d5da8..56748bf 100644
--- a/plugins/calendar/config.inc.php.dist
+++ b/plugins/calendar/config.inc.php.dist
@@ -119,5 +119,12 @@ $rcmail_config['calendar_itip_smtp_user'] = 'smtpauth';
// SMTP password used to send (anonymous) itip messages
$rcmail_config['calendar_itip_smtp_pass'] = '123456';
+// Base URL to build fully qualified URIs to access calendars via CALDAV
+// The following replacement variables are supported:
+// %h - Current HTTP host
+// %u - Current webmail user name
+// %n - Calendar name
+// %i - Calendar UUID
+// $rcmail_config['calendar_caldav_url'] = 'http://%h/iRony/calendars/%u/%i';
?>
\ No newline at end of file
diff --git a/plugins/calendar/drivers/kolab/kolab_calendar.php b/plugins/calendar/drivers/kolab/kolab_calendar.php
index 1cf7107..877c3f5 100644
--- a/plugins/calendar/drivers/kolab/kolab_calendar.php
+++ b/plugins/calendar/drivers/kolab/kolab_calendar.php
@@ -156,6 +156,24 @@ class kolab_calendar
}
/**
+ * Compose an URL for CalDAV access to this calendar (if configured)
+ */
+ public function get_caldav_url()
+ {
+ $url = null;
+ if ($template = $this->cal->rc->config->get('calendar_caldav_url', null)) {
+ return strtr($template, array(
+ '%h' => $_SERVER['HTTP_HOST'],
+ '%u' => urlencode($this->cal->rc->get_user_name()),
+ '%i' => urlencode($this->storage->get_uid()),
+ '%n' => urlencode($this->imap_folder),
+ ));
+ }
+
+ return false;
+ }
+
+ /**
* Return the corresponding kolab_storage_folder instance
*/
public function get_folder()
diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php
index 77b6a0a..05fd0e4 100644
--- a/plugins/calendar/drivers/kolab/kolab_driver.php
+++ b/plugins/calendar/drivers/kolab/kolab_driver.php
@@ -123,6 +123,7 @@ class kolab_driver extends calendar_driver
'active' => $cal->storage->is_active(),
'owner' => $cal->get_owner(),
'children' => true, // TODO: determine if that folder indeed has child folders
+ 'caldavurl' => $cal->get_caldav_url(),
);
}
diff --git a/plugins/calendar/localization/de_CH.inc b/plugins/calendar/localization/de_CH.inc
index cd3399f..b580fc2 100644
--- a/plugins/calendar/localization/de_CH.inc
+++ b/plugins/calendar/localization/de_CH.inc
@@ -76,6 +76,7 @@ $labels['onemonthback'] = '1 Monat zurück';
$labels['nmonthsback'] = '$nr Monate zurück';
$labels['showurl'] = 'URL anzeigen';
$labels['showurldescription'] = 'Ãber die folgende Adresse können Sie mit einem beliebigen Kalenderprogramm Ihren Kalender abrufen (nur lesend), sofern dieses das iCal-Format unterstützt.';
+$labels['caldavurldescription'] = 'Benutzen Sie folgende Addresse in einer <a href="http://de.wikipedia.org/wiki/CalDAV" target="_blank">CalDAV</a>-Anwendung (wie z.B. Evolution oder Mozilla Thunderbird) um diesen spezifischen Kalender mit dem Computer oder Mobiltelefon zu synchronisieren.';
// agenda view
$labels['listrange'] = 'Angezeigter Bereich:';
diff --git a/plugins/calendar/localization/de_DE.inc b/plugins/calendar/localization/de_DE.inc
index cb96b0d..60e6ad2 100644
--- a/plugins/calendar/localization/de_DE.inc
+++ b/plugins/calendar/localization/de_DE.inc
@@ -76,6 +76,7 @@ $labels['onemonthback'] = '1 Monat zurück';
$labels['nmonthsback'] = '$nr Monate zurück';
$labels['showurl'] = 'URL anzeigen';
$labels['showurldescription'] = 'Ãber die folgende Adresse können Sie mit einem beliebigen Kalenderprogramm Ihren Kalender abrufen (nur lesend), sofern dieses das iCal-Format unterstützt.';
+$labels['caldavurldescription'] = 'Benutzen Sie folgende Addresse in einer <a href="http://de.wikipedia.org/wiki/CalDAV" target="_blank">CalDAV</a>-Anwendung (wie z.B. Evolution oder Mozilla Thunderbird) um diesen spezifischen Kalender mit dem Computer oder Mobiltelefon zu synchronisieren.';
// agenda view
$labels['listrange'] = 'Angezeigter Bereich:';
diff --git a/plugins/calendar/localization/en_US.inc b/plugins/calendar/localization/en_US.inc
index 3bf52ba..9a631b2 100644
--- a/plugins/calendar/localization/en_US.inc
+++ b/plugins/calendar/localization/en_US.inc
@@ -77,6 +77,7 @@ $labels['onemonthback'] = '1 month back';
$labels['nmonthsback'] = '$nr months back';
$labels['showurl'] = 'Show calendar URL';
$labels['showurldescription'] = 'Use the following address to access (read only) your calendar from other applications. You can copy and paste this into any calendar software that supports the iCal format.';
+$labels['caldavurldescription'] = 'Copy this address to a <a href="http://en.wikipedia.org/wiki/CalDAV" target="_blank">CalDAV</a> client application (e.g. Evolution or Mozilla Thunderbird) to fully synchronize this specific calendar with your computer or mobile device.';
// agenda view
$labels['listrange'] = 'Range to display:';
diff --git a/plugins/calendar/skins/classic/calendar.css b/plugins/calendar/skins/classic/calendar.css
index 117c2ce..835bdac 100644
--- a/plugins/calendar/skins/classic/calendar.css
+++ b/plugins/calendar/skins/classic/calendar.css
@@ -164,7 +164,8 @@ pre {
background-position: 0 -92px;
}
-#calfeedurl {
+#calfeedurl,
+#caldavurl {
width: 98%;
background: #fbfbfb;
padding: 4px;
diff --git a/plugins/calendar/skins/classic/templates/calendar.html b/plugins/calendar/skins/classic/templates/calendar.html
index a78e76f..ba80ca3 100644
--- a/plugins/calendar/skins/classic/templates/calendar.html
+++ b/plugins/calendar/skins/classic/templates/calendar.html
@@ -150,6 +150,10 @@
<div id="calendarurlbox" class="uidialog">
<p><roundcube:label name="calendar.showurldescription" /></p>
<textarea id="calfeedurl" rows="2" readonly="readonly"></textarea>
+ <div id="calendarcaldavurl" style="display:none">
+ <p><roundcube:label name="calendar.caldavurldescription" html="yes" /></p>
+ <textarea id="caldavurl" rows="2" readonly="readonly"></textarea>
+ </div>
</div>
<div id="calendartoolbar">
diff --git a/plugins/calendar/skins/larry/calendar.css b/plugins/calendar/skins/larry/calendar.css
index b11abfa..8775b2a 100644
--- a/plugins/calendar/skins/larry/calendar.css
+++ b/plugins/calendar/skins/larry/calendar.css
@@ -225,7 +225,8 @@ pre {
background-position: right -92px;
}
-#calfeedurl {
+#calfeedurl,
+#caldavurl {
width: 98%;
background: #fbfbfb;
padding: 4px;
diff --git a/plugins/calendar/skins/larry/templates/calendar.html b/plugins/calendar/skins/larry/templates/calendar.html
index bc9beca..79ce5ad 100644
--- a/plugins/calendar/skins/larry/templates/calendar.html
+++ b/plugins/calendar/skins/larry/templates/calendar.html
@@ -164,6 +164,10 @@
<div id="calendarurlbox" class="uidialog">
<p><roundcube:label name="calendar.showurldescription" /></p>
<textarea id="calfeedurl" rows="2" readonly="readonly"></textarea>
+ <div id="calendarcaldavurl" style="display:none">
+ <p><roundcube:label name="calendar.caldavurldescription" html="yes" /></p>
+ <textarea id="caldavurl" rows="2" readonly="readonly"></textarea>
+ </div>
</div>
<roundcube:object name="plugin.calendar_css" />
More information about the commits
mailing list