Add new folder navigation to tasks module (#3047)
This commit is contained in:
parent
184730b347
commit
f4f5a30e0a
13 changed files with 633 additions and 159 deletions
|
@ -119,8 +119,8 @@ class calendar_ui
|
|||
$this->rc->output->include_script('treelist.js');
|
||||
|
||||
// include kolab folderlist widget if available
|
||||
if (is_readable($this->cal->home . '/lib/js/folderlist.js')) {
|
||||
$this->cal->include_script('lib/js/folderlist.js');
|
||||
if (is_readable($this->cal->api->dir . 'libkolab/js/folderlist.js')) {
|
||||
$this->cal->api->include_script('libkolab/js/folderlist.js');
|
||||
}
|
||||
|
||||
jqueryui::miniColors();
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../../../libkolab/js/folderlist.js
|
|
@ -149,6 +149,24 @@ abstract class kolab_storage_folder_api
|
|||
return rcube_charset::convert(end($parts), 'UTF7-IMAP');
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for parent folder path
|
||||
*
|
||||
* @return string Full path to parent folder
|
||||
*/
|
||||
public function get_parent()
|
||||
{
|
||||
$path = explode('/', $this->name);
|
||||
array_pop($path);
|
||||
|
||||
// don't list top-level namespace folder
|
||||
if (count($path) == 1 && in_array($this->get_namespace(), array('other', 'shared'))) {
|
||||
$path = array();
|
||||
}
|
||||
|
||||
return join('/', $path);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the color value stored in metadata
|
||||
|
|
|
@ -199,6 +199,18 @@ class tasklist_database_driver extends tasklist_driver
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for shared or otherwise not listed tasklists the user has access
|
||||
*
|
||||
* @param string Search string
|
||||
* @param string Section/source to search
|
||||
* @return array List of tasklists
|
||||
*/
|
||||
public function search_lists($query, $source)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of tasks matching the given filter
|
||||
*
|
||||
|
|
|
@ -45,12 +45,15 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
$this->rc = $plugin->rc;
|
||||
$this->plugin = $plugin;
|
||||
|
||||
$this->_read_lists();
|
||||
|
||||
if (kolab_storage::$version == '2.0') {
|
||||
$this->alarm_absolute = false;
|
||||
}
|
||||
|
||||
// tasklist use fully encoded identifiers
|
||||
kolab_storage::$encode_ids = true;
|
||||
|
||||
$this->_read_lists();
|
||||
|
||||
$this->plugin->register_action('folder-acl', array($this, 'folder_acl'));
|
||||
}
|
||||
|
||||
|
@ -83,87 +86,171 @@ 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();
|
||||
|
||||
// include virtual folders for a full folder tree
|
||||
if (!$this->rc->output->ajax_call && in_array($this->rc->action, array('index','')))
|
||||
$folders = kolab_storage::folder_hierarchy($folders);
|
||||
|
||||
foreach ($folders as $folder) {
|
||||
$utf7name = $folder->name;
|
||||
$tasklist = $this->folder_props($folder, $delim, $prefs);
|
||||
|
||||
$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);
|
||||
|
||||
$fullname = $folder->get_name();
|
||||
$listname = 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' => $fullname,
|
||||
'listname' => $listname,
|
||||
'virtual' => true,
|
||||
'editable' => false,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($folder->get_namespace() == 'personal') {
|
||||
$norename = false;
|
||||
$readonly = false;
|
||||
$alarms = true;
|
||||
}
|
||||
else {
|
||||
$alarms = false;
|
||||
$readonly = true;
|
||||
if (($rights = $folder->get_myrights()) && !PEAR::isError($rights)) {
|
||||
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' => $fullname,
|
||||
'listname' => $listname,
|
||||
'editname' => $editname,
|
||||
'color' => $folder->get_color('0000CC'),
|
||||
'showalarms' => isset($prefs[$list_id]['showalarms']) ? $prefs[$list_id]['showalarms'] : $alarms,
|
||||
'editable' => !$readionly,
|
||||
'norename' => $norename,
|
||||
'active' => $folder->is_active(),
|
||||
'parentfolder' => $path_imap,
|
||||
'default' => $folder->default,
|
||||
'children' => true, // TODO: determine if that folder indeed has child folders
|
||||
'class_name' => trim($folder->get_namespace() . ($folder->default ? ' default' : '')),
|
||||
);
|
||||
$this->lists[$tasklist['id']] = $tasklist;
|
||||
$this->folders[$tasklist['id']] = $folder;
|
||||
$this->folders[$folder->name] = $folder;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive list properties from the given kolab_storage_folder object
|
||||
*/
|
||||
protected function folder_props($folder, $delim, $prefs)
|
||||
{
|
||||
if ($folder->get_namespace() == 'personal') {
|
||||
$norename = false;
|
||||
$readonly = false;
|
||||
$alarms = true;
|
||||
}
|
||||
else {
|
||||
$alarms = false;
|
||||
$readonly = true;
|
||||
if (($rights = $folder->get_myrights()) && !PEAR::isError($rights)) {
|
||||
if (strpos($rights, 'i') !== false)
|
||||
$readonly = false;
|
||||
}
|
||||
$info = $folder->get_folder_info();
|
||||
$norename = $readonly || $info['norename'] || $info['protected'];
|
||||
}
|
||||
|
||||
$list_id = $folder->id; #kolab_storage::folder_id($folder->name);
|
||||
$old_id = kolab_storage::folder_id($folder->name, false);
|
||||
|
||||
if (!isset($prefs[$list_id]['showalarms']) && isset($prefs[$old_id]['showalarms'])) {
|
||||
$prefs[$list_id]['showalarms'] = $prefs[$old_id]['showalarms'];
|
||||
}
|
||||
|
||||
return array(
|
||||
'id' => $list_id,
|
||||
'name' => $folder->get_name(),
|
||||
'listname' => $folder->get_foldername(),
|
||||
'editname' => $folder->get_foldername(),
|
||||
'color' => $folder->get_color('0000CC'),
|
||||
'showalarms' => isset($prefs[$list_id]['showalarms']) ? $prefs[$list_id]['showalarms'] : $alarms,
|
||||
'editable' => !$readonly,
|
||||
'norename' => $norename,
|
||||
'active' => $folder->is_active(),
|
||||
'parentfolder' => $folder->get_parent(),
|
||||
'default' => $folder->default,
|
||||
'virtual' => $folder->virtual,
|
||||
'children' => true, // TODO: determine if that folder indeed has child folders
|
||||
'subscribed' => (bool)$folder->is_subscribed(),
|
||||
'group' => $folder->get_namespace(),
|
||||
'class' => trim($folder->get_namespace() . ($folder->default ? ' default' : '')),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of available task lists from this source
|
||||
*/
|
||||
public function get_lists()
|
||||
public function get_lists(&$tree = null)
|
||||
{
|
||||
// attempt to create a default list for this user
|
||||
if (empty($this->lists)) {
|
||||
if ($this->create_list(array('name' => 'Tasks', 'color' => '0000CC', 'default' => true)))
|
||||
$prop = array('name' => 'Tasks', 'color' => '0000CC', 'default' => true);
|
||||
if ($this->create_list($prop))
|
||||
$this->_read_lists(true);
|
||||
}
|
||||
|
||||
return $this->lists;
|
||||
$folders = array();
|
||||
foreach ($this->lists as $id => $list) {
|
||||
if (!empty($this->folders[$id])) {
|
||||
$folders[] = $this->folders[$id];
|
||||
}
|
||||
}
|
||||
|
||||
// include virtual folders for a full folder tree
|
||||
if (!is_null($tree)) {
|
||||
$folders = kolab_storage::folder_hierarchy($folders, $tree);
|
||||
}
|
||||
|
||||
$delim = $this->rc->get_storage()->get_hierarchy_delimiter();
|
||||
$prefs = $this->rc->config->get('kolab_tasklists', array());
|
||||
|
||||
$lists = array();
|
||||
foreach ($folders as $folder) {
|
||||
$list_id = $folder->id; #kolab_storage::folder_id($folder->name);
|
||||
$imap_path = explode($delim, $folder->name);
|
||||
|
||||
// find parent
|
||||
do {
|
||||
array_pop($imap_path);
|
||||
$parent_id = kolab_storage::folder_id(join($delim, $imap_path));
|
||||
}
|
||||
while (count($imap_path) > 1 && !$this->folders[$parent_id]);
|
||||
|
||||
// restore "real" parent ID
|
||||
if ($parent_id && !$this->folders[$parent_id]) {
|
||||
$parent_id = kolab_storage::folder_id($folder->get_parent());
|
||||
}
|
||||
|
||||
$fullname = $folder->get_name();
|
||||
$listname = $folder->get_foldername();
|
||||
|
||||
// special handling for virtual folders
|
||||
if ($folder instanceof kolab_storage_folder_user) {
|
||||
$lists[$list_id] = array(
|
||||
'id' => $list_id,
|
||||
'name' => $folder->get_name(),
|
||||
'listname' => $listname,
|
||||
'title' => $folder->get_owner(),
|
||||
'virtual' => true,
|
||||
'editable' => false,
|
||||
'group' => 'other virtual',
|
||||
'class' => 'user',
|
||||
'parent' => $parent_id,
|
||||
);
|
||||
}
|
||||
else if ($folder->virtual) {
|
||||
$lists[$list_id] = array(
|
||||
'id' => $list_id,
|
||||
'name' => kolab_storage::object_name($fullname),
|
||||
'listname' => $listname,
|
||||
'virtual' => true,
|
||||
'editable' => false,
|
||||
'group' => $folder->get_namespace(),
|
||||
'class' => 'folder',
|
||||
'parent' => $parent_id,
|
||||
);
|
||||
}
|
||||
else {
|
||||
if (!$this->lists[$list_id]) {
|
||||
$this->lists[$list_id] = $this->folder_props($folder, $delim, $prefs);
|
||||
$this->folders[$list_id] = $folder;
|
||||
}
|
||||
$this->lists[$list_id]['parent'] = $parent_id;
|
||||
$lists[$list_id] = $this->lists[$list_id];
|
||||
}
|
||||
}
|
||||
|
||||
return $lists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the kolab_calendar instance for the given calendar ID
|
||||
*
|
||||
* @param string List identifier (encoded imap folder name)
|
||||
* @return object kolab_storage_folder Object nor null if list doesn't exist
|
||||
*/
|
||||
protected function get_folder($id)
|
||||
{
|
||||
// create list and folder instance if necesary
|
||||
if (!$this->lists[$id]) {
|
||||
$folder = kolab_storage::get_folder(kolab_storage::id_decode($id));
|
||||
if ($folder->type) {
|
||||
$this->folders[$id] = $folder;
|
||||
$this->lists[$id] = $this->folder_props($folder, $this->rc->get_storage()->get_hierarchy_delimiter(), $this->rc->config->get('kolab_tasklists', array()));
|
||||
}
|
||||
}
|
||||
|
||||
return $this->folders[$id];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new list assigned to the current user
|
||||
*
|
||||
|
@ -215,7 +302,7 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
*/
|
||||
public function edit_list(&$prop)
|
||||
{
|
||||
if ($prop['id'] && ($folder = $this->folders[$prop['id']])) {
|
||||
if ($prop['id'] && ($folder = $this->get_folder($prop['id']))) {
|
||||
$prop['oldname'] = $folder->name;
|
||||
$prop['type'] = 'task';
|
||||
$newfolder = kolab_storage::folder_update($prop);
|
||||
|
@ -254,12 +341,18 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
* @param array Hash array with list properties
|
||||
* id: List Identifier
|
||||
* active: True if list is active, false if not
|
||||
* permanent: True if list is to be subscribed permanently
|
||||
* @return boolean True on success, Fales on failure
|
||||
*/
|
||||
public function subscribe_list($prop)
|
||||
{
|
||||
if ($prop['id'] && ($folder = $this->folders[$prop['id']])) {
|
||||
return $folder->activate($prop['active']);
|
||||
if ($prop['id'] && ($folder = $this->get_folder($prop['id']))) {
|
||||
$ret = false;
|
||||
if (isset($prop['permanent']))
|
||||
$ret |= $folder->subscribe(intval($prop['permanent']));
|
||||
if (isset($prop['active']))
|
||||
$ret |= $folder->activate(intval($prop['active']));
|
||||
return $ret;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -273,7 +366,7 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
*/
|
||||
public function remove_list($prop)
|
||||
{
|
||||
if ($prop['id'] && ($folder = $this->folders[$prop['id']])) {
|
||||
if ($prop['id'] && ($folder = $this->get_folder($prop['id']))) {
|
||||
if (kolab_storage::folder_delete($folder->name))
|
||||
return true;
|
||||
else
|
||||
|
@ -283,6 +376,63 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for shared or otherwise not listed tasklists the user has access
|
||||
*
|
||||
* @param string Search string
|
||||
* @param string Section/source to search
|
||||
* @return array List of tasklists
|
||||
*/
|
||||
public function search_lists($query, $source)
|
||||
{
|
||||
if (!kolab_storage::setup()) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$this->search_more_results = false;
|
||||
$this->lists = $this->folders = array();
|
||||
|
||||
$delim = $this->rc->get_storage()->get_hierarchy_delimiter();
|
||||
|
||||
// find unsubscribed IMAP folders that have "event" type
|
||||
if ($source == 'folders') {
|
||||
foreach ((array)kolab_storage::search_folders('task', $query, array('other')) as $folder) {
|
||||
$this->folders[$folder->id] = $folder;
|
||||
$this->lists[$folder->id] = $this->folder_props($folder, $delim, array());
|
||||
}
|
||||
}
|
||||
// search other user's namespace via LDAP
|
||||
else if ($source == 'users') {
|
||||
$limit = $this->rc->config->get('autocomplete_max', 15) * 2; // we have slightly more space, so display twice the number
|
||||
foreach (kolab_storage::search_users($query, 0, array(), $limit * 10) as $user) {
|
||||
$folders = array();
|
||||
// search for tasks folders shared by this user
|
||||
foreach (kolab_storage::list_user_folders($user, 'task', false) as $foldername) {
|
||||
$folders[] = new kolab_storage_folder($foldername, 'task');
|
||||
}
|
||||
|
||||
if (count($folders)) {
|
||||
$userfolder = new kolab_storage_folder_user($user['kolabtargetfolder'], '', $user);
|
||||
$this->folders[$userfolder->id] = $userfolder;
|
||||
$this->lists[$userfolder->id] = $this->folder_props($userfolder, $delim, array());
|
||||
|
||||
foreach ($folders as $folder) {
|
||||
$this->folders[$folder->id] = $folder;
|
||||
$this->lists[$folder->id] = $this->folder_props($folder, $delim, array());
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($count >= $limit) {
|
||||
$this->search_more_results = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->get_lists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of tasks matching the given filter
|
||||
*
|
||||
|
@ -303,7 +453,9 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
|
||||
$counts = array('all' => 0, 'flagged' => 0, 'today' => 0, 'tomorrow' => 0, 'overdue' => 0, 'nodate' => 0);
|
||||
foreach ($lists as $list_id) {
|
||||
$folder = $this->folders[$list_id];
|
||||
if (!$folder = $this->get_folder($list_id)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($folder->select(array(array('tags','!~','x-complete'))) as $record) {
|
||||
$rec = $this->_to_rcube_task($record);
|
||||
|
||||
|
@ -367,7 +519,9 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
}
|
||||
|
||||
foreach ($lists as $list_id) {
|
||||
$folder = $this->folders[$list_id];
|
||||
if (!$folder = $this->get_folder($list_id)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($folder->select($query) as $record) {
|
||||
$task = $this->_to_rcube_task($record);
|
||||
$task['list'] = $list_id;
|
||||
|
@ -391,11 +545,11 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
{
|
||||
$id = is_array($prop) ? ($prop['uid'] ?: $prop['id']) : $prop;
|
||||
$list_id = is_array($prop) ? $prop['list'] : null;
|
||||
$folders = $list_id ? array($list_id => $this->folders[$list_id]) : $this->folders;
|
||||
$folders = $list_id ? array($list_id => $this->get_folder($list_id)) : $this->folders;
|
||||
|
||||
// find task in the available folders
|
||||
foreach ($folders as $list_id => $folder) {
|
||||
if (is_numeric($list_id))
|
||||
if (is_numeric($list_id) || !$folder)
|
||||
continue;
|
||||
if (!$this->tasks[$id] && ($object = $folder->get_object($id))) {
|
||||
$this->tasks[$id] = $this->_to_rcube_task($object);
|
||||
|
@ -424,7 +578,7 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
$childs = array();
|
||||
$list_id = $prop['list'];
|
||||
$task_ids = array($prop['id']);
|
||||
$folder = $this->folders[$list_id];
|
||||
$folder = $this->get_folder($list_id);
|
||||
|
||||
// query for childs (recursively)
|
||||
while ($folder && !empty($task_ids)) {
|
||||
|
@ -484,7 +638,7 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
if (!$list['showalarms'] || ($lists && !in_array($lid, $lists)))
|
||||
continue;
|
||||
|
||||
$folder = $this->folders[$lid];
|
||||
$folder = $this->get_folder($lid);
|
||||
foreach ($folder->select($query) as $record) {
|
||||
if (!($record['valarms'] || $record['alarms']) || $record['status'] == 'COMPLETED' || $record['complete'] == 100) // don't trust query :-)
|
||||
continue;
|
||||
|
@ -756,11 +910,11 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
public function edit_task($task)
|
||||
{
|
||||
$list_id = $task['list'];
|
||||
if (!$list_id || !($folder = $this->folders[$list_id]))
|
||||
if (!$list_id || !($folder = $this->get_folder($list_id)))
|
||||
return false;
|
||||
|
||||
// moved from another folder
|
||||
if ($task['_fromlist'] && ($fromfolder = $this->folders[$task['_fromlist']])) {
|
||||
if ($task['_fromlist'] && ($fromfolder = $this->get_folder($task['_fromlist']))) {
|
||||
if (!$fromfolder->move($task['id'], $folder->name))
|
||||
return false;
|
||||
|
||||
|
@ -809,11 +963,11 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
public function move_task($task)
|
||||
{
|
||||
$list_id = $task['list'];
|
||||
if (!$list_id || !($folder = $this->folders[$list_id]))
|
||||
if (!$list_id || !($folder = $this->get_folder($list_id)))
|
||||
return false;
|
||||
|
||||
// execute move command
|
||||
if ($task['_fromlist'] && ($fromfolder = $this->folders[$task['_fromlist']])) {
|
||||
if ($task['_fromlist'] && ($fromfolder = $this->get_folder($task['_fromlist']))) {
|
||||
return $fromfolder->move($task['id'], $folder->name);
|
||||
}
|
||||
|
||||
|
@ -831,7 +985,7 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
public function delete_task($task, $force = true)
|
||||
{
|
||||
$list_id = $task['list'];
|
||||
if (!$list_id || !($folder = $this->folders[$list_id]))
|
||||
if (!$list_id || !($folder = $this->get_folder($list_id)))
|
||||
return false;
|
||||
|
||||
return $folder->delete($task['id']);
|
||||
|
@ -892,7 +1046,7 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
*/
|
||||
public function get_attachment_body($id, $task)
|
||||
{
|
||||
if ($storage = $this->folders[$task['list']]) {
|
||||
if ($storage = $this->get_folder($task['list'])) {
|
||||
return $storage->get_attachment($task['id'], $id);
|
||||
}
|
||||
|
||||
|
@ -905,7 +1059,7 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
public function tasklist_edit_form($action, $list, $fieldprop)
|
||||
{
|
||||
if ($list['id'] && ($list = $this->lists[$list['id']])) {
|
||||
$folder_name = $this->folders[$list['id']]->name; // UTF7
|
||||
$folder_name = $this->get_folder($list['id'])->name; // UTF7
|
||||
}
|
||||
else {
|
||||
$folder_name = '';
|
||||
|
|
|
@ -125,6 +125,15 @@ abstract class tasklist_driver
|
|||
*/
|
||||
abstract function remove_list($prop);
|
||||
|
||||
/**
|
||||
* Search for shared or otherwise not listed tasklists the user has access
|
||||
*
|
||||
* @param string Search string
|
||||
* @param string Section/source to search
|
||||
* @return array List of tasklists
|
||||
*/
|
||||
abstract function search_lists($query, $source);
|
||||
|
||||
/**
|
||||
* Get number of tasks matching the given filter
|
||||
*
|
||||
|
|
|
@ -5,6 +5,9 @@ $labels['navtitle'] = 'Tasks';
|
|||
$labels['lists'] = 'Tasklists';
|
||||
$labels['list'] = 'Tasklist';
|
||||
$labels['tags'] = 'Tags';
|
||||
$labels['tasklistsubscribe'] = 'List permanently';
|
||||
$labels['listsearchresults'] = 'Available Tasklists';
|
||||
$labels['findlists'] = 'Find tasklists...';
|
||||
|
||||
$labels['newtask'] = 'New Task';
|
||||
$labels['createnewtask'] = 'Create new Task (e.g. Saturday, Mow the lawn)';
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.9 KiB |
|
@ -74,6 +74,32 @@ body.attachmentwin #topnav .topright {
|
|||
bottom: 0px;
|
||||
}
|
||||
|
||||
#tasklistsbox .boxtitle a.iconbutton.search {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
width: 16px;
|
||||
cursor: pointer;
|
||||
background-position: -2px -317px;
|
||||
}
|
||||
|
||||
#tasklistsbox .listsearchbox {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#tasklistsbox .listsearchbox.expanded {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#tasklistsbox .scroller {
|
||||
top: 34px;
|
||||
}
|
||||
|
||||
#tasklistsbox .listsearchbox.expanded + .scroller {
|
||||
top: 68px;
|
||||
}
|
||||
|
||||
|
||||
#taskselector {
|
||||
margin: -4px 40px 0 0;
|
||||
padding: 0;
|
||||
|
@ -225,32 +251,48 @@ body.attachmentwin #topnav .topright {
|
|||
display: none;
|
||||
}
|
||||
|
||||
#tasklists li {
|
||||
#tasklistsbox .treelist li {
|
||||
margin: 0;
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#tasklistsbox .treelist li div.tasklist {
|
||||
margin: 0;
|
||||
height: 20px;
|
||||
padding: 6px 8px 2px 6px;
|
||||
display: block;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#tasklists li.virtual {
|
||||
height: 12px;
|
||||
#tasklistsbox .treelist li.virtual > div.tasklist {
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
#tasklists li label {
|
||||
#tasklistsbox .treelist ul li > div.tasklist {
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
#tasklistsbox .treelist ul ul li > div.tasklist {
|
||||
margin-left: 32px;
|
||||
}
|
||||
|
||||
#tasklistsbox .treelist ul ul ul li > div.tasklist {
|
||||
margin-left: 48px;
|
||||
}
|
||||
|
||||
#tasklistsbox .treelist li label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#tasklists li span.listname {
|
||||
#tasklistsbox .treelist li span.listname {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
left: 26px;
|
||||
right: 26px;
|
||||
left: 38px;
|
||||
right: 40px;
|
||||
cursor: default;
|
||||
padding-bottom: 2px;
|
||||
padding-right: 30px;
|
||||
padding: 0px 30px 2px 2px;
|
||||
color: #004458;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
@ -258,8 +300,11 @@ body.attachmentwin #topnav .topright {
|
|||
background: url(sprites.png) right 20px no-repeat;
|
||||
}
|
||||
|
||||
#tasklists li span.handle {
|
||||
#tasklistsbox .treelist li span.quickview {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 20px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 4px;
|
||||
|
@ -267,52 +312,76 @@ body.attachmentwin #topnav .topright {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
#tasklists li:hover span.handle {
|
||||
#tasklistsbox .treelist li a.subscribed {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 5px;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
padding: 0;
|
||||
background: url(sprites.png) -100px 0 no-repeat;
|
||||
overflow: hidden;
|
||||
text-indent: -5000px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#tasklistsbox .treelist div:hover > a.subscribed {
|
||||
background-position: -2px -215px;
|
||||
}
|
||||
|
||||
#tasklistsbox .treelist div.subscribed a.subscribed {
|
||||
background-position: -20px -215px;
|
||||
}
|
||||
|
||||
#tasklistsbox .treelist li div:hover > span.quickview {
|
||||
background-position: -20px -101px;
|
||||
}
|
||||
|
||||
#tasklists li.focusview span.handle {
|
||||
#tasklistsbox .treelist li div.focusview > span.quickview {
|
||||
background-position: -2px -101px;
|
||||
}
|
||||
|
||||
#tasklists li.selected span.listname {
|
||||
#tasklistsbox .searchresults .treelist li span.quickview {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#tasklistsbox .treelist li.selected > div > span.listname {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#tasklists li.readonly span.listname {
|
||||
#tasklistsbox .treelist .readonly > span.listname {
|
||||
background-position: right -142px;
|
||||
}
|
||||
|
||||
#tasklists li.other span.listname {
|
||||
#tasklistsbox .treelist .user > span.listname {
|
||||
background-position: right -160px;
|
||||
}
|
||||
|
||||
#tasklists li.other.readonly span.listname {
|
||||
background-position: right -178px;
|
||||
}
|
||||
|
||||
#tasklists li.shared span.listname {
|
||||
background-position: right -196px;
|
||||
}
|
||||
|
||||
#tasklists li.shared.readonly span.listname {
|
||||
background-position: right -214px;
|
||||
}
|
||||
|
||||
#tasklists li.virtual span.listname {
|
||||
#tasklistsbox .treelist .virtual > span.listname {
|
||||
color: #aaa;
|
||||
top: 2px;
|
||||
top: 4px;
|
||||
left: 20px;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
#tasklists li.virtual span.handle {
|
||||
background: none;
|
||||
cursor: default;
|
||||
#tasklistsbox .treelist.flat li span.calname {
|
||||
left: 24px;
|
||||
right: 22px;
|
||||
}
|
||||
|
||||
#tasklists li input {
|
||||
#tasklistsbox .treelist li input {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
left: 18px;
|
||||
}
|
||||
|
||||
#tasklistsbox .treelist li .treetoggle {
|
||||
top: 8px;
|
||||
}
|
||||
|
||||
#tasklistsbox .treelist li.virtual > .treetoggle {
|
||||
top: 6px;
|
||||
}
|
||||
|
||||
#mainview-right {
|
||||
|
|
|
@ -24,9 +24,18 @@
|
|||
</div>
|
||||
|
||||
<div id="tasklistsbox" class="uibox listbox">
|
||||
<h2 class="boxtitle"><roundcube:label name="tasklist.lists" /></h2>
|
||||
<h2 class="boxtitle"><roundcube:label name="tasklist.lists" />
|
||||
<a class="iconbutton search" title="<roundcube:label name='tasklist.findlists' />"></a>
|
||||
</h2>
|
||||
<div class="listsearchbox">
|
||||
<div class="searchbox">
|
||||
<input type="text" name="q" id="tasklistsearch" placeholder="<roundcube:label name='tasklist.findlists' />" />
|
||||
<a class="iconbutton searchicon"></a>
|
||||
<roundcube:button command="reset-listsearch" id="tasklistsearch-reset" class="iconbutton reset" title="resetsearch" content="x" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="scroller withfooter">
|
||||
<roundcube:object name="plugin.tasklists" id="tasklists" class="listing" />
|
||||
<roundcube:object name="plugin.tasklists" id="tasklists" class="treelist listing" />
|
||||
</div>
|
||||
<div class="boxfooter">
|
||||
<roundcube:button command="list-create" type="link" title="tasklist.createlist" class="listbutton add disabled" classAct="listbutton add" innerClass="inner" content="+" /><roundcube:button name="tasklistoptionslink" id="tasklistoptionsmenulink" type="link" title="tasklist.listactions" class="listbutton groupactions" onclick="UI.show_popup('tasklistoptionsmenu', undefined, { above:true });return false" innerClass="inner" content="⚙" />
|
||||
|
@ -171,6 +180,30 @@ $(document).ready(function(e){
|
|||
orientation:'v', relative:true, start:240, min:180, size:12 }).init();
|
||||
new rcube_splitter({ id:'taskviewsplitterv', p1:'#tagsbox', p2:'#tasklistsbox',
|
||||
orientation:'h', relative:true, start:242, min:120, size:12, offset:4 }).init();
|
||||
|
||||
// animation to unfold list search box
|
||||
$('#tasklistsbox .boxtitle a.search').click(function(e){
|
||||
var box = $('#tasklistsbox .listsearchbox'),
|
||||
dir = box.is(':visible') ? -1 : 1;
|
||||
|
||||
box.slideToggle({
|
||||
duration: 160,
|
||||
progress: function(animation, progress) {
|
||||
if (dir < 0) progress = 1 - progress;
|
||||
$('#tasklistsbox .scroller').css('top', (34 + 34 * progress) + 'px');
|
||||
},
|
||||
complete: function() {
|
||||
box.toggleClass('expanded');
|
||||
if (box.is(':visible')) {
|
||||
box.find('input[type=text]').focus();
|
||||
}
|
||||
else {
|
||||
$('#tasklistsearch-reset').click();
|
||||
}
|
||||
// TODO: save state in localStorage
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
|
|
@ -79,6 +79,7 @@ function rcube_tasklist_ui(settings)
|
|||
var scroll_speed = 20;
|
||||
var scroll_sensitivity = 40;
|
||||
var scroll_timer;
|
||||
var tasklists_widget;
|
||||
var me = this;
|
||||
|
||||
// general datepicker settings
|
||||
|
@ -127,18 +128,80 @@ function rcube_tasklist_ui(settings)
|
|||
{
|
||||
// initialize task list selectors
|
||||
for (var id in me.tasklists) {
|
||||
if ((li = rcmail.get_folder_li(id, 'rcmlitasklist'))) {
|
||||
init_tasklist_li(li, id);
|
||||
}
|
||||
|
||||
if (me.tasklists[id].editable && (!me.selected_list || (me.tasklists[id].active && !me.tasklists[me.selected_list].active))) {
|
||||
me.selected_list = id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// initialize treelist widget that controls the tasklists list
|
||||
var widget_class = window.kolab_folderlist || rcube_treelist_widget;
|
||||
tasklists_widget = new widget_class(rcmail.gui_objects.tasklistslist, {
|
||||
id_prefix: 'rcmlitasklist',
|
||||
selectable: true,
|
||||
save_state: true,
|
||||
searchbox: '#tasklistsearch',
|
||||
search_action: 'tasks/tasklist',
|
||||
search_sources: [ 'folders', 'users' ],
|
||||
search_title: rcmail.gettext('listsearchresults','tasklist')
|
||||
});
|
||||
tasklists_widget.addEventListener('select', function(node) {
|
||||
var id = $(this).data('id');
|
||||
rcmail.enable_command('list-edit', 'list-remove', 'list-import', me.tasklists[node.id].editable);
|
||||
me.selected_list = node.id;
|
||||
});
|
||||
tasklists_widget.addEventListener('subscribe', function(p) {
|
||||
var list;
|
||||
if ((list = me.tasklists[p.id])) {
|
||||
list.subscribed = p.subscribed || false;
|
||||
rcmail.http_post('tasklist', { action:'subscribe', l:{ id:p.id, active:list.active?1:0, permanent:list.subscribed?1:0 } });
|
||||
}
|
||||
});
|
||||
tasklists_widget.addEventListener('insert-item', function(p) {
|
||||
var list = p.data;
|
||||
if (list && list.id && !list.virtual) {
|
||||
me.tasklists[list.id] = list;
|
||||
var prop = { id:p.id, active:list.active?1:0 };
|
||||
if (list.subscribed) prop.permanent = 1;
|
||||
rcmail.http_post('tasklist', { action:'subscribe', l:prop });
|
||||
list_tasks();
|
||||
}
|
||||
});
|
||||
|
||||
// init (delegate) event handler on tasklist checkboxes
|
||||
tasklists_widget.container.on('click', 'input[type=checkbox]', function(e){
|
||||
var list, id = this.value;
|
||||
if ((list = me.tasklists[id])) {
|
||||
list.active = this.checked;
|
||||
fetch_counts();
|
||||
if (!this.checked) remove_tasks(id);
|
||||
else list_tasks(null);
|
||||
rcmail.http_post('tasklist', { action:'subscribe', l:{ id:id, active:list.active?1:0 } });
|
||||
|
||||
// disable focusview
|
||||
if (!this.checked && focusview == id) {
|
||||
set_focusview(null);
|
||||
}
|
||||
}
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
// 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)
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
// register dbl-click handler to open calendar edit dialog
|
||||
tasklists_widget.container.on('dblclick', ':not(.virtual) > .tasklist', function(e){
|
||||
var id = $(this).closest('li').attr('id').replace(/^rcmlitasklist/, '');
|
||||
list_edit_dialog(id);
|
||||
});
|
||||
|
||||
if (me.selected_list) {
|
||||
rcmail.enable_command('addtask', true);
|
||||
$(rcmail.get_folder_li(me.selected_list, 'rcmlitasklist')).click();
|
||||
tasklists_widget.select(me.selected_list);
|
||||
}
|
||||
|
||||
// register server callbacks
|
||||
|
@ -1972,7 +2035,7 @@ function rcube_tasklist_ui(settings)
|
|||
me.selected_list = id;
|
||||
|
||||
// click on handle icon toggles focusview
|
||||
if (e.target.className == 'handle') {
|
||||
if (e.target.className == 'quickview') {
|
||||
set_focusview(focusview == id ? null : id)
|
||||
}
|
||||
// disable focusview when selecting another list
|
||||
|
@ -1994,13 +2057,15 @@ function rcube_tasklist_ui(settings)
|
|||
function set_focusview(id)
|
||||
{
|
||||
if (focusview && focusview != id)
|
||||
$(rcmail.get_folder_li(focusview, 'rcmlitasklist')).removeClass('focusview');
|
||||
$(tasklists_widget.get_item(focusview)).find('.tasklist').first().removeClass('focusview');
|
||||
|
||||
focusview = id;
|
||||
|
||||
var li = $(tasklists_widget.get_item(id)).find('.tasklist').first();
|
||||
|
||||
// activate list if necessary
|
||||
if (focusview && !me.tasklists[id].active) {
|
||||
$('input', rcmail.get_folder_li(id, 'rcmlitasklist')).get(0).checked = true;
|
||||
li.find('input[type=checkbox]').get(0).checked = true;
|
||||
me.tasklists[id].active = true;
|
||||
fetch_counts();
|
||||
}
|
||||
|
@ -2009,7 +2074,7 @@ function rcube_tasklist_ui(settings)
|
|||
list_tasks(null);
|
||||
|
||||
if (focusview) {
|
||||
$(rcmail.get_folder_li(focusview, 'rcmlitasklist')).addClass('focusview');
|
||||
li.addClass('focusview');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ class tasklist extends rcube_plugin
|
|||
public $driver;
|
||||
public $timezone;
|
||||
public $ui;
|
||||
public $home; // declare public to be used in other classes
|
||||
|
||||
private $collapsed_tasks = array();
|
||||
|
||||
|
@ -134,8 +135,7 @@ class tasklist extends rcube_plugin
|
|||
}
|
||||
|
||||
if (!$this->rc->output->ajax_call && !$this->rc->output->env['framed']) {
|
||||
require_once($this->home . '/tasklist_ui.php');
|
||||
$this->ui = new tasklist_ui($this);
|
||||
$this->load_ui();
|
||||
$this->ui->init();
|
||||
}
|
||||
|
||||
|
@ -144,6 +144,16 @@ class tasklist extends rcube_plugin
|
|||
$this->add_hook('dismiss_alarms', array($this, 'dismiss_alarms'));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function load_ui()
|
||||
{
|
||||
if (!$this->ui) {
|
||||
require_once($this->home . '/tasklist_ui.php');
|
||||
$this->ui = new tasklist_ui($this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to load the backend driver according to local config
|
||||
|
@ -619,6 +629,30 @@ class tasklist extends rcube_plugin
|
|||
if (($success = $this->driver->remove_list($list)))
|
||||
$this->rc->output->command('plugin.destroy_tasklist', $list);
|
||||
break;
|
||||
|
||||
case 'search':
|
||||
$this->load_ui();
|
||||
$results = array();
|
||||
foreach ((array)$this->driver->search_lists(get_input_value('q', RCUBE_INPUT_GPC), get_input_value('source', RCUBE_INPUT_GPC)) as $id => $prop) {
|
||||
$editname = $prop['editname'];
|
||||
unset($prop['editname']); // force full name to be displayed
|
||||
$prop['active'] = false;
|
||||
|
||||
// let the UI generate HTML and CSS representation for this calendar
|
||||
$html = $this->ui->tasklist_list_item($id, $prop, $jsenv);
|
||||
$prop += (array)$jsenv[$id];
|
||||
$prop['editname'] = $editname;
|
||||
$prop['html'] = $html;
|
||||
|
||||
$results[] = $prop;
|
||||
}
|
||||
// report more results available
|
||||
if ($this->driver->search_more_results) {
|
||||
$this->rc->output->show_message('autocompletemore', 'info');
|
||||
}
|
||||
|
||||
$this->rc->output->command('multi_thread_http_response', $results, get_input_value('_reqid', RCUBE_INPUT_GPC));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($success)
|
||||
|
@ -875,6 +909,13 @@ class tasklist extends rcube_plugin
|
|||
{
|
||||
$this->ui->init();
|
||||
$this->ui->init_templates();
|
||||
|
||||
// set autocompletion env
|
||||
$this->rc->output->set_env('autocomplete_threads', (int)$this->rc->config->get('autocomplete_threads', 0));
|
||||
$this->rc->output->set_env('autocomplete_max', (int)$this->rc->config->get('autocomplete_max', 15));
|
||||
$this->rc->output->set_env('autocomplete_min_length', $this->rc->config->get('autocomplete_min_length'));
|
||||
$this->rc->output->add_label('autocompletechars', 'autocompletemore');
|
||||
|
||||
$this->rc->output->set_pagetitle($this->gettext('navtitle'));
|
||||
$this->rc->output->send('tasklist.mainview');
|
||||
}
|
||||
|
|
|
@ -81,6 +81,12 @@ class tasklist_ui
|
|||
|
||||
$this->plugin->include_script('jquery.tagedit.js');
|
||||
$this->plugin->include_script('tasklist.js');
|
||||
$this->rc->output->include_script('treelist.js');
|
||||
|
||||
// include kolab folderlist widget if available
|
||||
if (is_readable($this->plugin->api->dir . 'libkolab/js/folderlist.js')) {
|
||||
$this->plugin->api->include_script('libkolab/js/folderlist.js');
|
||||
}
|
||||
|
||||
$this->plugin->include_stylesheet($this->plugin->local_skin_path() . '/tagedit.css');
|
||||
}
|
||||
|
@ -88,45 +94,110 @@ class tasklist_ui
|
|||
/**
|
||||
*
|
||||
*/
|
||||
function tasklists($attrib = array())
|
||||
public function tasklists($attrib = array())
|
||||
{
|
||||
$lists = $this->plugin->driver->get_lists();
|
||||
$tree = true;
|
||||
$jsenv = array();
|
||||
$lists = $this->plugin->driver->get_lists($tree);
|
||||
|
||||
$li = '';
|
||||
foreach ((array)$lists as $id => $prop) {
|
||||
if ($attrib['activeonly'] && !$prop['active'])
|
||||
continue;
|
||||
// walk folder tree
|
||||
if (is_object($tree)) {
|
||||
$html = $this->list_tree_html($tree, $lists, $jsenv, $attrib);
|
||||
}
|
||||
else {
|
||||
// fall-back to flat folder listing
|
||||
$attrib['class'] .= ' flat';
|
||||
|
||||
$html = '';
|
||||
foreach ((array)$lists as $id => $prop) {
|
||||
if ($attrib['activeonly'] && !$prop['active'])
|
||||
continue;
|
||||
|
||||
$html .= html::tag('li', array(
|
||||
'id' => 'rcmlitasklist' . rcube_utils::html_identifier($id),
|
||||
'class' => $prop['group'],
|
||||
),
|
||||
$this->tasklist_list_item($id, $prop, $jsenv, $attrib['activeonly'])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->rc->output->set_env('tasklists', $jsenv);
|
||||
$this->rc->output->add_gui_object('tasklistslist', $attrib['id']);
|
||||
|
||||
return html::tag('ul', $attrib, $html, html::$common_attrib);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return html for a structured list <ul> for the folder tree
|
||||
*/
|
||||
public function list_tree_html($node, $data, &$jsenv, $attrib)
|
||||
{
|
||||
$out = '';
|
||||
foreach ($node->children as $folder) {
|
||||
$id = $folder->id;
|
||||
$prop = $data[$id];
|
||||
$is_collapsed = false; // TODO: determine this somehow?
|
||||
|
||||
$content = $this->tasklist_list_item($id, $prop, $jsenv, $attrib['activeonly']);
|
||||
|
||||
if (!empty($folder->children)) {
|
||||
$content .= html::tag('ul', array('style' => ($is_collapsed ? "display:none;" : null)),
|
||||
$this->list_tree_html($folder, $data, $jsenv, $attrib));
|
||||
}
|
||||
|
||||
if (strlen($content)) {
|
||||
$out .= html::tag('li', array(
|
||||
'id' => 'rcmlitasklist' . rcube_utils::html_identifier($id),
|
||||
'class' => $prop['group'] . ($prop['virtual'] ? ' virtual' : ''),
|
||||
),
|
||||
$content);
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to build a tasklist item (HTML content and js data)
|
||||
*/
|
||||
public function tasklist_list_item($id, $prop, &$jsenv, $activeonly = false)
|
||||
{
|
||||
// enrich list properties with settings from the driver
|
||||
if (!$prop['virtual']) {
|
||||
unset($prop['user_id']);
|
||||
$prop['alarms'] = $this->plugin->driver->alarms;
|
||||
$prop['undelete'] = $this->plugin->driver->undelete;
|
||||
$prop['sortable'] = $this->plugin->driver->sortable;
|
||||
$prop['attachments'] = $this->plugin->driver->attachments;
|
||||
|
||||
if (!$prop['virtual'])
|
||||
$jsenv[$id] = $prop;
|
||||
|
||||
$html_id = html_identifier($id);
|
||||
$class = 'tasks-' . asciiwords($id, true);
|
||||
$title = $prop['name'] != $prop['listname'] ? html_entity_decode($prop['name'], ENT_COMPAT, RCMAIL_CHARSET) : '';
|
||||
|
||||
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),
|
||||
($prop['virtual'] ? '' : html::tag('input', array('type' => 'checkbox', 'name' => '_list[]', 'value' => $id, 'checked' => $prop['active']))) .
|
||||
html::span(array('class' => 'handle', 'title' => $this->plugin->gettext('focusview')), ' ') .
|
||||
html::span(array('class' => 'listname', 'title' => $title), $prop['listname']));
|
||||
$jsenv[$id] = $prop;
|
||||
}
|
||||
|
||||
$this->rc->output->set_env('tasklists', $jsenv);
|
||||
$this->rc->output->add_gui_object('folderlist', $attrib['id']);
|
||||
$classes = array('tasklist');
|
||||
$title = $prop['title'] ?: ($prop['name'] != $prop['listname'] || strlen($prop['name']) > 25 ?
|
||||
html_entity_decode($prop['name'], ENT_COMPAT, RCMAIL_CHARSET) : '');
|
||||
|
||||
return html::tag('ul', $attrib, $li, html::$common_attrib);
|
||||
if ($prop['virtual'])
|
||||
$classes[] = 'virtual';
|
||||
else if (!$prop['editable'])
|
||||
$classes[] = 'readonly';
|
||||
if ($prop['subscribed'])
|
||||
$classes[] = 'subscribed';
|
||||
if ($prop['class'])
|
||||
$classes[] = $prop['class'];
|
||||
|
||||
if (!$activeonly || $prop['active']) {
|
||||
return html::div(join(' ', $classes),
|
||||
html::span(array('class' => 'listname', 'title' => $title), $prop['listname']) .
|
||||
($prop['virtual'] ? '' :
|
||||
html::tag('input', array('type' => 'checkbox', 'name' => '_list[]', 'value' => $id, 'checked' => $prop['active'])) .
|
||||
html::span(array('class' => 'quickview', 'title' => $this->plugin->gettext('focusview')), ' ') .
|
||||
(isset($prop['subscribed']) ? html::a(array('href' => '#', 'class' => 'subscribed', 'title' => $this->plugin->gettext('tasklistsubscribe')), ' ') : '')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue