Fix folders sorting issues (Bug #2210)
- move some shared code to kolab_storage - this requires recent Roundcube Framework (f13ae32a)
This commit is contained in:
parent
4f1b0ebe78
commit
43b287c470
3 changed files with 101 additions and 142 deletions
|
@ -110,7 +110,7 @@ class kolab_driver extends calendar_driver
|
||||||
|
|
||||||
// include virtual folders for a full folder tree
|
// include virtual folders for a full folder tree
|
||||||
if (!$active && !$personal && !$this->rc->output->ajax_call && in_array($this->rc->action, array('index','')))
|
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());
|
$folders = kolab_storage::folder_hierarchy($folders);
|
||||||
|
|
||||||
foreach ($folders as $id => $cal) {
|
foreach ($folders as $id => $cal) {
|
||||||
$fullname = $cal->get_name();
|
$fullname = $cal->get_name();
|
||||||
|
@ -148,39 +148,6 @@ class kolab_driver extends calendar_driver
|
||||||
return $calendars;
|
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
|
* Get list of calendars according to specified filters
|
||||||
*
|
*
|
||||||
|
@ -1281,32 +1248,3 @@ 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -433,7 +433,7 @@ class kolab_storage
|
||||||
// get username
|
// get username
|
||||||
$pos = strpos($folder, $delim);
|
$pos = strpos($folder, $delim);
|
||||||
if ($pos) {
|
if ($pos) {
|
||||||
$prefix = '('.substr($folder, 0, $pos).') ';
|
$prefix = '('.substr($folder, 0, $pos).')';
|
||||||
$folder = substr($folder, $pos+1);
|
$folder = substr($folder, $pos+1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -525,8 +525,8 @@ class kolab_storage
|
||||||
*/
|
*/
|
||||||
public static function folder_selector($type, $attrs, $current = '')
|
public static function folder_selector($type, $attrs, $current = '')
|
||||||
{
|
{
|
||||||
// get all folders of specified type
|
// get all folders of specified type (sorted)
|
||||||
$folders = self::get_folders($type, false);
|
$folders = self::get_folders($type, true);
|
||||||
|
|
||||||
$delim = self::$imap->get_hierarchy_delimiter();
|
$delim = self::$imap->get_hierarchy_delimiter();
|
||||||
$names = array();
|
$names = array();
|
||||||
|
@ -540,13 +540,15 @@ class kolab_storage
|
||||||
// Filter folders list
|
// Filter folders list
|
||||||
foreach ($folders as $c_folder) {
|
foreach ($folders as $c_folder) {
|
||||||
$name = $c_folder->name;
|
$name = $c_folder->name;
|
||||||
|
|
||||||
// skip current folder and it's subfolders
|
// skip current folder and it's subfolders
|
||||||
if ($len && ($name == $current || strpos($name, $current.$delim) === 0)) {
|
if ($len && ($name == $current || strpos($name, $current.$delim) === 0)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// always show the parent of current folder
|
// always show the parent of current folder
|
||||||
if ($p_len && $name == $parent) { }
|
if ($p_len && $name == $parent) {
|
||||||
|
}
|
||||||
// skip folders where user have no rights to create subfolders
|
// skip folders where user have no rights to create subfolders
|
||||||
else if ($c_folder->get_owner() != $_SESSION['username']) {
|
else if ($c_folder->get_owner() != $_SESSION['username']) {
|
||||||
$rights = $c_folder->get_myrights();
|
$rights = $c_folder->get_myrights();
|
||||||
|
@ -555,17 +557,14 @@ class kolab_storage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure parent folder is listed (might be skipped e.g. if it's namespace root)
|
||||||
|
if ($p_len && !isset($names[$parent]) && strpos($name, $parent.$delim) === 0) {
|
||||||
|
$names[$parent] = self::object_name($parent);
|
||||||
|
}
|
||||||
|
|
||||||
$names[$name] = self::object_name($name);
|
$names[$name] = self::object_name($name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure parent folder is listed (might be skipped e.g. if it's namespace root)
|
|
||||||
if ($p_len && !isset($names[$parent])) {
|
|
||||||
$names[$parent] = self::object_name($parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort folders list
|
|
||||||
asort($names, SORT_LOCALE_STRING);
|
|
||||||
|
|
||||||
// Build SELECT field of parent folder
|
// Build SELECT field of parent folder
|
||||||
$attrs['is_escaped'] = true;
|
$attrs['is_escaped'] = true;
|
||||||
$select = new html_select($attrs);
|
$select = new html_select($attrs);
|
||||||
|
@ -643,7 +642,8 @@ class kolab_storage
|
||||||
unset($folderdata[$folder]);
|
unset($folderdata[$folder]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return array_keys($folderdata);
|
|
||||||
|
return self::$imap->sort_folder_list(array_keys($folderdata), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get folders list
|
// Get folders list
|
||||||
|
@ -683,29 +683,78 @@ class kolab_storage
|
||||||
*/
|
*/
|
||||||
public static function sort_folders($folders)
|
public static function sort_folders($folders)
|
||||||
{
|
{
|
||||||
$pad = ' ';
|
$pad = ' ';
|
||||||
|
$out = array();
|
||||||
$nsnames = array('personal' => array(), 'shared' => array(), 'other' => array());
|
$nsnames = array('personal' => array(), 'shared' => array(), 'other' => array());
|
||||||
|
|
||||||
foreach ($folders as $folder) {
|
foreach ($folders as $folder) {
|
||||||
$folders[$folder->name] = $folder;
|
$folders[$folder->name] = $folder;
|
||||||
$ns = $folder->get_namespace();
|
$ns = $folder->get_namespace();
|
||||||
$nsnames[$ns][$folder->name] = strtolower(html_entity_decode(self::object_name($folder->name, $ns), ENT_COMPAT, RCUBE_CHARSET)) . $pad; // decode »
|
$nsnames[$ns][$folder->name] = strtolower(html_entity_decode(self::object_name($folder->name, $ns), ENT_COMPAT, RCUBE_CHARSET)) . $pad; // decode »
|
||||||
}
|
}
|
||||||
|
|
||||||
$names = array();
|
// $folders is a result of get_folders() we can assume folders were already sorted
|
||||||
foreach ($nsnames as $ns => $dummy) {
|
foreach (array_keys($nsnames) as $ns) {
|
||||||
asort($nsnames[$ns], SORT_LOCALE_STRING);
|
// asort($nsnames[$ns], SORT_LOCALE_STRING);
|
||||||
$names += $nsnames[$ns];
|
foreach (array_keys($nsnames[$ns]) as $utf7name) {
|
||||||
}
|
$out[] = $folders[$utf7name];
|
||||||
|
}
|
||||||
$out = array();
|
|
||||||
foreach ($names as $utf7name => $name) {
|
|
||||||
$out[] = $folders[$utf7name];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the folder tree and add the missing parents as virtual folders
|
||||||
|
*
|
||||||
|
* @param array $folders Folders list
|
||||||
|
*
|
||||||
|
* @return array Folders list
|
||||||
|
*/
|
||||||
|
public static function folder_hierarchy($folders)
|
||||||
|
{
|
||||||
|
$_folders = array();
|
||||||
|
$existing = array_map(function($folder){ return $folder->get_name(); }, $folders);
|
||||||
|
$delim = rcube::get_instance()->get_storage()->get_hierarchy_delimiter();
|
||||||
|
|
||||||
|
foreach ($folders as $idx => $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)) {
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$parents = array();
|
||||||
|
|
||||||
|
while (count($path) > 1 && ($parent = join($delim, $path))) {
|
||||||
|
$name = kolab_storage::object_name($parent, $folder->get_namespace());
|
||||||
|
if (!in_array($name, $existing)) {
|
||||||
|
$parents[$parent] = new virtual_kolab_storage_folder($name, $folder->get_namespace());
|
||||||
|
$parents[$parent]->id = kolab_storage::folder_id($parent);
|
||||||
|
$existing[] = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
array_pop($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($parents)) {
|
||||||
|
$parents = array_reverse(array_values($parents));
|
||||||
|
foreach ($parents as $parent) {
|
||||||
|
$_folders[] = $parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$_folders[] = $folder;
|
||||||
|
unset($folders[$idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $_folders;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns folder types indexed by folder name
|
* Returns folder types indexed by folder name
|
||||||
*
|
*
|
||||||
|
@ -1047,3 +1096,30 @@ class kolab_storage
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_name()
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ class tasklist_kolab_driver extends tasklist_driver
|
||||||
|
|
||||||
// include virtual folders for a full folder tree
|
// include virtual folders for a full folder tree
|
||||||
if (!$this->rc->output->ajax_call && in_array($this->rc->action, array('index','')))
|
if (!$this->rc->output->ajax_call && in_array($this->rc->action, array('index','')))
|
||||||
$folders = $this->_folder_hierarchy($folders, $delim);
|
$folders = kolab_storage::folder_hierarchy($folders);
|
||||||
|
|
||||||
foreach ($folders as $folder) {
|
foreach ($folders as $folder) {
|
||||||
$utf7name = $folder->name;
|
$utf7name = $folder->name;
|
||||||
|
@ -148,38 +148,6 @@ class tasklist_kolab_driver extends tasklist_driver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
* Get a list of available task lists from this source
|
||||||
*/
|
*/
|
||||||
|
@ -906,26 +874,3 @@ 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue