Display object history for tasks (#3271)
This commit is contained in:
parent
dcb60dbee1
commit
548d1d93b7
8 changed files with 827 additions and 27 deletions
|
@ -38,6 +38,7 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
private $folders = array();
|
||||
private $tasks = array();
|
||||
private $tags = array();
|
||||
private $bonnie_api = false;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -55,6 +56,11 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
// tasklist use fully encoded identifiers
|
||||
kolab_storage::$encode_ids = true;
|
||||
|
||||
// get configuration for the Bonnie API
|
||||
if ($bonnie_config = $this->rc->config->get('kolab_bonnie_api', false)) {
|
||||
$this->bonnie_api = new kolab_bonnie_api($bonnie_config);
|
||||
}
|
||||
|
||||
$this->_read_lists();
|
||||
|
||||
$this->plugin->register_action('folder-acl', array($this, 'folder_acl'));
|
||||
|
@ -152,6 +158,7 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
'group' => $folder->default ? 'default' : $folder->get_namespace(),
|
||||
'class' => trim($folder->get_namespace() . ($folder->default ? ' default' : '')),
|
||||
'caldavuid' => $folder->get_uid(),
|
||||
'history' => !empty($this->bonnie_api),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -658,6 +665,250 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
return $childs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a list of revisions for the given task
|
||||
*
|
||||
* @param array $task Hash array with task properties
|
||||
* @return array List of changes, each as a hash array
|
||||
* @see tasklist_driver::get_task_changelog()
|
||||
*/
|
||||
public function get_task_changelog($prop)
|
||||
{
|
||||
if (empty($this->bonnie_api)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
list($uid, $mailbox, $msguid) = $this->_resolve_task_identity($prop);
|
||||
|
||||
$result = $uid && $mailbox ? $this->bonnie_api->changelog('task', $uid, $mailbox, $msguid) : null;
|
||||
if (is_array($result) && $result['uid'] == $uid) {
|
||||
return $result['changes'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return full data of a specific revision of an event
|
||||
*
|
||||
* @param mixed $task UID string or hash array with task properties
|
||||
* @param mixed $rev Revision number
|
||||
*
|
||||
* @return array Task object as hash array
|
||||
* @see tasklist_driver::get_task_revision()
|
||||
*/
|
||||
public function get_task_revison($prop, $rev)
|
||||
{
|
||||
if (empty($this->bonnie_api)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->_parse_id($prop);
|
||||
$uid = $prop['uid'];
|
||||
$list_id = $prop['list'];
|
||||
list($uid, $mailbox, $msguid) = $this->_resolve_task_identity($prop);
|
||||
|
||||
// call Bonnie API
|
||||
$result = $this->bonnie_api->get('task', $uid, $rev, $mailbox, $msguid);
|
||||
if (is_array($result) && $result['uid'] == $uid && !empty($result['xml'])) {
|
||||
$format = kolab_format::factory('task');
|
||||
$format->load($result['xml']);
|
||||
$rec = $format->to_array();
|
||||
$format->get_attachments($rec, true);
|
||||
|
||||
if ($format->is_valid()) {
|
||||
$rec['rev'] = $result['rev'];
|
||||
return self::_to_rcube_task($rec, $list_id, false);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Command the backend to restore a certain revision of a task.
|
||||
* This shall replace the current object with an older version.
|
||||
*
|
||||
* @param mixed $task UID string or hash array with task properties
|
||||
* @param mixed $rev Revision number
|
||||
*
|
||||
* @return boolean True on success, False on failure
|
||||
* @see tasklist_driver::restore_task_revision()
|
||||
*/
|
||||
public function restore_task_revision($prop, $rev)
|
||||
{
|
||||
if (empty($this->bonnie_api)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->_parse_id($prop);
|
||||
$uid = $prop['uid'];
|
||||
$list_id = $prop['list'];
|
||||
list($uid, $mailbox, $msguid) = $this->_resolve_task_identity($prop);
|
||||
|
||||
$folder = $this->get_folder($list_id);
|
||||
$success = false;
|
||||
|
||||
if ($folder && ($raw_msg = $this->bonnie_api->rawdata('task', $uid, $rev, $mailbox))) {
|
||||
$imap = $this->rc->get_storage();
|
||||
|
||||
// insert $raw_msg as new message
|
||||
if ($imap->save_message($folder->name, $raw_msg, null, false)) {
|
||||
$success = true;
|
||||
|
||||
// delete old revision from imap and cache
|
||||
$imap->delete_message($msguid, $folder->name);
|
||||
$folder->cache->set($msguid, false);
|
||||
}
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of property changes beteen two revisions of a task object
|
||||
*
|
||||
* @param array $task Hash array with task properties
|
||||
* @param mixed $rev Revisions: "from:to"
|
||||
*
|
||||
* @return array List of property changes, each as a hash array
|
||||
* @see tasklist_driver::get_task_diff()
|
||||
*/
|
||||
public function get_task_diff($prop, $rev1, $rev2)
|
||||
{
|
||||
$this->_parse_id($prop);
|
||||
$uid = $prop['uid'];
|
||||
$list_id = $prop['list'];
|
||||
list($uid, $mailbox, $msguid) = $this->_resolve_task_identity($prop);
|
||||
|
||||
// call Bonnie API
|
||||
$result = $this->bonnie_api->diff('task', $uid, $rev1, $rev2, $mailbox, $msguid, $instance_id);
|
||||
if (is_array($result) && $result['uid'] == $uid) {
|
||||
$result['rev1'] = $rev1;
|
||||
$result['rev2'] = $rev2;
|
||||
|
||||
$keymap = array(
|
||||
'start' => 'start',
|
||||
'due' => 'date',
|
||||
'dstamp' => 'changed',
|
||||
'summary' => 'title',
|
||||
'alarm' => 'alarms',
|
||||
'attendee' => 'attendees',
|
||||
'attach' => 'attachments',
|
||||
'rrule' => 'recurrence',
|
||||
'percent-complete' => 'complete',
|
||||
'lastmodified-date' => 'changed',
|
||||
);
|
||||
$prop_keymaps = array(
|
||||
'attachments' => array('fmttype' => 'mimetype', 'label' => 'name'),
|
||||
'attendees' => array('partstat' => 'status'),
|
||||
);
|
||||
$special_changes = array();
|
||||
|
||||
// map kolab event properties to keys the client expects
|
||||
array_walk($result['changes'], function(&$change, $i) use ($keymap, $prop_keymaps, $special_changes) {
|
||||
if (array_key_exists($change['property'], $keymap)) {
|
||||
$change['property'] = $keymap[$change['property']];
|
||||
}
|
||||
if ($change['property'] == 'priority') {
|
||||
$change['property'] = 'flagged';
|
||||
$change['old'] = $change['old'] == 1 ? $this->plugin->gettext('yes') : null;
|
||||
$change['new'] = $change['new'] == 1 ? $this->plugin->gettext('yes') : null;
|
||||
}
|
||||
// map alarms trigger value
|
||||
if ($change['property'] == 'alarms') {
|
||||
if (is_array($change['old']) && is_array($change['old']['trigger']))
|
||||
$change['old']['trigger'] = $change['old']['trigger']['value'];
|
||||
if (is_array($change['new']) && is_array($change['new']['trigger']))
|
||||
$change['new']['trigger'] = $change['new']['trigger']['value'];
|
||||
}
|
||||
// make all property keys uppercase
|
||||
if ($change['property'] == 'recurrence') {
|
||||
$special_changes['recurrence'] = $i;
|
||||
foreach (array('old','new') as $m) {
|
||||
if (is_array($change[$m])) {
|
||||
$props = array();
|
||||
foreach ($change[$m] as $k => $v) {
|
||||
$props[strtoupper($k)] = $v;
|
||||
}
|
||||
$change[$m] = $props;
|
||||
}
|
||||
}
|
||||
}
|
||||
// map property keys names
|
||||
if (is_array($prop_keymaps[$change['property']])) {
|
||||
foreach ($prop_keymaps[$change['property']] as $k => $dest) {
|
||||
if (is_array($change['old']) && array_key_exists($k, $change['old'])) {
|
||||
$change['old'][$dest] = $change['old'][$k];
|
||||
unset($change['old'][$k]);
|
||||
}
|
||||
if (is_array($change['new']) && array_key_exists($k, $change['new'])) {
|
||||
$change['new'][$dest] = $change['new'][$k];
|
||||
unset($change['new'][$k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($change['property'] == 'exdate') {
|
||||
$special_changes['exdate'] = $i;
|
||||
}
|
||||
else if ($change['property'] == 'rdate') {
|
||||
$special_changes['rdate'] = $i;
|
||||
}
|
||||
});
|
||||
|
||||
// merge some recurrence changes
|
||||
foreach (array('exdate','rdate') as $prop) {
|
||||
if (array_key_exists($prop, $special_changes)) {
|
||||
$exdate = $result['changes'][$special_changes[$prop]];
|
||||
if (array_key_exists('recurrence', $special_changes)) {
|
||||
$recurrence = &$result['changes'][$special_changes['recurrence']];
|
||||
}
|
||||
else {
|
||||
$i = count($result['changes']);
|
||||
$result['changes'][$i] = array('property' => 'recurrence', 'old' => array(), 'new' => array());
|
||||
$recurrence = &$result['changes'][$i]['recurrence'];
|
||||
}
|
||||
$key = strtoupper($prop);
|
||||
$recurrence['old'][$key] = $exdate['old'];
|
||||
$recurrence['new'][$key] = $exdate['new'];
|
||||
unset($result['changes'][$special_changes[$prop]]);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to resolved the given task identifier into uid and folder
|
||||
*
|
||||
* @return array (uid,folder,msguid) tuple
|
||||
*/
|
||||
private function _resolve_task_identity($prop)
|
||||
{
|
||||
$mailbox = $msguid = null;
|
||||
|
||||
$this->_parse_id($prop);
|
||||
$uid = $prop['uid'];
|
||||
$list_id = $prop['list'];
|
||||
|
||||
if ($folder = $this->get_folder($list_id)) {
|
||||
$mailbox = $folder->get_mailbox_id();
|
||||
|
||||
// get task object from storage in order to get the real object uid an msguid
|
||||
if ($rec = $folder->get_object($uid)) {
|
||||
$msguid = $rec['_msguid'];
|
||||
$uid = $rec['uid'];
|
||||
}
|
||||
}
|
||||
|
||||
return array($uid, $mailbox, $msguid);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a list of pending alarms to be displayed to the user
|
||||
*
|
||||
|
@ -1232,6 +1483,7 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
* @param array $task Hash array with event properties:
|
||||
* id: Task identifier
|
||||
* list: List identifier
|
||||
* rev: Revision (optional)
|
||||
*
|
||||
* @return array Hash array with attachment properties:
|
||||
* id: Attachment identifier
|
||||
|
@ -1241,7 +1493,13 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
*/
|
||||
public function get_attachment($id, $task)
|
||||
{
|
||||
$task = $this->get_task($task);
|
||||
// get old revision of the object
|
||||
if ($task['rev']) {
|
||||
$task = $this->get_task_revison($task, $task['rev']);
|
||||
}
|
||||
else {
|
||||
$task = $this->get_task($task);
|
||||
}
|
||||
|
||||
if ($task && !empty($task['attachments'])) {
|
||||
foreach ($task['attachments'] as $att) {
|
||||
|
@ -1260,12 +1518,38 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
* @param array $task Hash array with event properties:
|
||||
* id: Task identifier
|
||||
* list: List identifier
|
||||
* rev: Revision (optional)
|
||||
*
|
||||
* @return string Attachment body
|
||||
*/
|
||||
public function get_attachment_body($id, $task)
|
||||
{
|
||||
$this->_parse_id($task);
|
||||
|
||||
// get old revision of event
|
||||
if ($task['rev']) {
|
||||
if (empty($this->bonnie_api)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cid = substr($id, 4);
|
||||
|
||||
// call Bonnie API and get the raw mime message
|
||||
list($uid, $mailbox, $msguid) = $this->_resolve_task_identity($task);
|
||||
if ($msg_raw = $this->bonnie_api->rawdata('task', $uid, $task['rev'], $mailbox, $msguid)) {
|
||||
// parse the message and find the part with the matching content-id
|
||||
$message = rcube_mime::parse_message($msg_raw);
|
||||
foreach ((array)$message->parts as $part) {
|
||||
if ($part->headers['content-id'] && trim($part->headers['content-id'], '<>') == $cid) {
|
||||
return $part->body;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if ($storage = $this->get_folder($task['list'])) {
|
||||
return $storage->get_attachment($task['uid'], $id);
|
||||
}
|
||||
|
|
|
@ -242,6 +242,7 @@ abstract class tasklist_driver
|
|||
*
|
||||
* @param array Hash array with task properties:
|
||||
* id: Task identifier
|
||||
* list: Tasklist identifer
|
||||
* @param boolean Remove record irreversible (mark as deleted otherwise, if supported by the backend)
|
||||
* @return boolean True on success, False on error
|
||||
*/
|
||||
|
@ -266,6 +267,7 @@ abstract class tasklist_driver
|
|||
* @param array $task Hash array with event properties:
|
||||
* id: Task identifier
|
||||
* list: List identifier
|
||||
* rev: Revision (optional)
|
||||
*
|
||||
* @return array Hash array with attachment properties:
|
||||
* id: Attachment identifier
|
||||
|
@ -282,6 +284,7 @@ abstract class tasklist_driver
|
|||
* @param array $task Hash array with event properties:
|
||||
* id: Task identifier
|
||||
* list: List identifier
|
||||
* rev: Revision (optional)
|
||||
*
|
||||
* @return string Attachment body
|
||||
*/
|
||||
|
@ -319,7 +322,7 @@ abstract class tasklist_driver
|
|||
/**
|
||||
* Helper method to determine whether the given task is considered "complete"
|
||||
*
|
||||
* @param array $task Hash array with event properties:
|
||||
* @param array $task Hash array with event properties
|
||||
* @return boolean True if complete, False otherwiese
|
||||
*/
|
||||
public function is_complete($task)
|
||||
|
@ -328,13 +331,74 @@ abstract class tasklist_driver
|
|||
}
|
||||
|
||||
/**
|
||||
* List availabale categories
|
||||
* The default implementation reads them from config/user prefs
|
||||
* Provide a list of revisions for the given task
|
||||
*
|
||||
* @param array $task Hash array with task properties:
|
||||
* id: Task identifier
|
||||
* list: List identifier
|
||||
*
|
||||
* @return array List of changes, each as a hash array:
|
||||
* rev: Revision number
|
||||
* type: Type of the change (create, update, move, delete)
|
||||
* date: Change date
|
||||
* user: The user who executed the change
|
||||
* ip: Client IP
|
||||
* mailbox: Destination list for 'move' type
|
||||
*/
|
||||
public function list_categories()
|
||||
public function get_task_changelog($task)
|
||||
{
|
||||
$rcmail = rcube::get_instance();
|
||||
return $rcmail->config->get('tasklist_categories', array());
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of property changes beteen two revisions of a task object
|
||||
*
|
||||
* @param array $task Hash array with task properties:
|
||||
* id: Task identifier
|
||||
* list: List identifier
|
||||
* @param mixed $rev1 Old Revision
|
||||
* @param mixed $rev2 New Revision
|
||||
*
|
||||
* @return array List of property changes, each as a hash array:
|
||||
* property: Revision number
|
||||
* old: Old property value
|
||||
* new: Updated property value
|
||||
*/
|
||||
public function get_task_diff($task, $rev1, $rev2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return full data of a specific revision of an event
|
||||
*
|
||||
* @param mixed $task UID string or hash array with task properties:
|
||||
* id: Task identifier
|
||||
* list: List identifier
|
||||
* @param mixed $rev Revision number
|
||||
*
|
||||
* @return array Task object as hash array
|
||||
* @see self::get_task()
|
||||
*/
|
||||
public function get_task_revison($task, $rev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Command the backend to restore a certain revision of a task.
|
||||
* This shall replace the current object with an older version.
|
||||
*
|
||||
* @param mixed $task UID string or hash array with task properties:
|
||||
* id: Task identifier
|
||||
* list: List identifier
|
||||
* @param mixed $rev Revision number
|
||||
*
|
||||
* @return boolean True on success, False on failure
|
||||
*/
|
||||
public function restore_task_revision($task, $rev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -50,6 +50,9 @@ $labels['status-cancelled'] = 'Cancelled';
|
|||
$labels['assignedto'] = 'Assigned to';
|
||||
$labels['created'] = 'Created';
|
||||
$labels['changed'] = 'Last Modified';
|
||||
$labels['taskoptions'] = 'Options';
|
||||
$labels['taskhistory'] = 'History';
|
||||
$labels['compare'] = 'Compare';
|
||||
|
||||
$labels['all'] = 'All';
|
||||
$labels['flagged'] = 'Flagged';
|
||||
|
@ -101,6 +104,7 @@ $labels['on'] = 'on';
|
|||
$labels['at'] = 'at';
|
||||
$labels['this'] = 'this';
|
||||
$labels['next'] = 'next';
|
||||
$labels['yes'] = 'yes';
|
||||
|
||||
// messages
|
||||
$labels['savingdata'] = 'Saving data...';
|
||||
|
@ -150,6 +154,24 @@ $labels['itipcancelsubject'] = '"$title" has been canceled';
|
|||
$labels['itipcancelmailbody'] = "*\$title*\n\nDue: \$date\n\nAssignees: \$attendees\n\nThe task has been cancelled by \$organizer.\n\nPlease find attached an iCalendar file with the updated task details.";
|
||||
$labels['saveintasklist'] = 'save in ';
|
||||
|
||||
// history dialog
|
||||
$labels['objectchangelog'] = 'Change History';
|
||||
$labels['objectdiff'] = 'Changes from $rev1 to $rev2';
|
||||
|
||||
$labels['actionappend'] = 'Saved';
|
||||
$labels['actionmove'] = 'Moved';
|
||||
$labels['actiondelete'] = 'Deleted';
|
||||
$labels['compare'] = 'Compare';
|
||||
$labels['showrevision'] = 'Show this version';
|
||||
$labels['restore'] = 'Restore this version';
|
||||
|
||||
$labels['objectnotfound'] = 'Failed to load task data';
|
||||
$labels['objectchangelognotavailable'] = 'Change history is not available for this task';
|
||||
$labels['objectdiffnotavailable'] = 'No comparison possible for the selected revisions';
|
||||
$labels['revisionrestoreconfirm'] = 'Do you really want to restore revision $rev of this task? This will replace the current task with the old version.';
|
||||
$labels['objectrestoresuccess'] = 'Revision $rev successfully restored';
|
||||
$labels['objectrestoreerror'] = 'Failed to restore the old revision';
|
||||
|
||||
// invitation handling (overrides labels from libcalendaring)
|
||||
$labels['itipobjectnotfound'] = 'The task referred by this message was not found in your tasks list.';
|
||||
|
||||
|
|
|
@ -642,7 +642,8 @@ ul.toolbarmenu li span.icon.taskadd,
|
|||
font-size: 12px;
|
||||
}
|
||||
|
||||
.taskhead .flagged {
|
||||
.taskhead .flagged,
|
||||
.taskshow.status-flagged h2:after {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
|
@ -657,7 +658,8 @@ ul.toolbarmenu li span.icon.taskadd,
|
|||
background-position: -2px -3px;
|
||||
}
|
||||
|
||||
.taskhead.flagged .flagged {
|
||||
.taskhead.flagged .flagged,
|
||||
.taskshow.status-flagged h2:after {
|
||||
background-position: -2px -23px;
|
||||
}
|
||||
|
||||
|
@ -839,8 +841,9 @@ ul.toolbarmenu .sortcol.by-auto a {
|
|||
/*** task edit form ***/
|
||||
|
||||
#taskedit,
|
||||
#taskshow {
|
||||
display:none;
|
||||
#taskshow,
|
||||
#taskdiff {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#taskedit {
|
||||
|
@ -850,15 +853,32 @@ ul.toolbarmenu .sortcol.by-auto a {
|
|||
margin: 0 -0.2em;
|
||||
}
|
||||
|
||||
#taskshow h2 {
|
||||
.taskshow h2 {
|
||||
margin-top: -0.5em;
|
||||
}
|
||||
|
||||
#taskshow label {
|
||||
#taskdiff h2 {
|
||||
font-size: 18px;
|
||||
margin: -0.3em 0 0.4em 0;
|
||||
}
|
||||
|
||||
.taskshow.status-completed h2 {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.taskshow.status-flagged h2:after {
|
||||
content: " ";
|
||||
position: relative;
|
||||
margin-left: 0.6em;
|
||||
top: 1px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.taskshow label {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
#taskshow.status-cancelled {
|
||||
.taskshow.status-cancelled {
|
||||
background: url(images/badge_cancelled.png) top right no-repeat;
|
||||
}
|
||||
|
||||
|
@ -1048,10 +1068,33 @@ label.block {
|
|||
margin-bottom: 0.3em;
|
||||
}
|
||||
|
||||
#task-description {
|
||||
.task-description {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.taskshow .task-text-old,
|
||||
.taskshow .task-text-new,
|
||||
.taskshow .task-text-diff {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.taskshow .task-text-diff del,
|
||||
.taskshow .task-text-diff ins {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.taskshow .task-text-old,
|
||||
.taskshow .task-text-diff del {
|
||||
background-color: #fdd;
|
||||
/* text-decoration: line-through; */
|
||||
}
|
||||
|
||||
.taskshow .task-text-new,
|
||||
.taskshow .task-text-diff ins {
|
||||
background-color: #dfd;
|
||||
}
|
||||
|
||||
#taskedit-completeness-slider {
|
||||
display: inline-block;
|
||||
margin-left: 2em;
|
||||
|
|
|
@ -149,6 +149,9 @@
|
|||
<li role="menuitem"><roundcube:button name="edit" type="link" onclick="rctasks.edit_task(rctasks.selected_task.id, 'edit'); return false" label="edit" class="icon active" innerclass="icon edit" /></li>
|
||||
<li role="menuitem"><roundcube:button name="delete" type="link" onclick="rctasks.delete_task(rctasks.selected_task.id); return false" label="delete" class="icon active" innerclass="icon delete" /></li>
|
||||
<li role="menuitem"><roundcube:button name="addchild" type="link" onclick="rctasks.add_childtask(rctasks.selected_task.id); return false" label="tasklist.addsubtask" class="icon active" innerclass="icon add" /></li>
|
||||
<roundcube:if condition="env:tasklist_driver == 'kolab' && config:kolab_bonnie_api" />
|
||||
<li role="menuitem"><roundcube:button command="task-history" type="link" label="tasklist.taskhistory" class="icon" classAct="icon active" innerclass="icon history" /></li>
|
||||
<roundcube:endif />
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
@ -159,12 +162,12 @@
|
|||
<roundcube:object name="message" id="messagestack" />
|
||||
|
||||
|
||||
<div id="taskshow">
|
||||
<div id="taskshow" class="taskshow">
|
||||
<div class="form-section" id="task-parent-title"></div>
|
||||
<div class="form-section">
|
||||
<h2 id="task-title"></h2>
|
||||
</div>
|
||||
<div id="task-description" class="form-section">
|
||||
<div id="task-description" class="form-section task-description">
|
||||
</div>
|
||||
<div id="task-tags" class="form-section">
|
||||
<label><roundcube:label name="tasklist.tags" /></label>
|
||||
|
@ -239,6 +242,78 @@
|
|||
<roundcube:object name="plugin.task_rsvp_buttons" id="task-rsvp" class="task-dialog-message" style="display:none" />
|
||||
</div>
|
||||
|
||||
<roundcube:if condition="env:tasklist_driver == 'kolab' && config:kolab_bonnie_api" />
|
||||
<div id="taskhistory" class="uidialog" aria-hidden="true">
|
||||
<roundcube:object name="plugin.object_changelog_table" class="records-table changelog-table" domain="calendar" />
|
||||
<div class="compare-button"><input type="button" class="button" value="↳ <roundcube:label name='tasklist.compare' />" /></div>
|
||||
</div>
|
||||
|
||||
<div id="taskdiff" class="uidialog taskshow" aria-hidden="true">
|
||||
<h2 class="task-title">Task Title</h2>
|
||||
<h2 class="task-title-new task-text-new"></h2>
|
||||
<div class="form-section task-description">
|
||||
<label><roundcube:label name="calendar.description" /></label>
|
||||
<div class="task-text-diff" style="white-space:pre-wrap"></div>
|
||||
<div class="task-text-old"></div>
|
||||
<div class="task-text-new"></div>
|
||||
</div>
|
||||
<div class="form-section task-flagged">
|
||||
<label><roundcube:label name="tasklist.flagged" /></label>
|
||||
<span class="task-text-old"></span> ⇢
|
||||
<span class="task-text-new"></span>
|
||||
</div>
|
||||
<div class="form-section task-start">
|
||||
<label><roundcube:label name="tasklist.start" /></label>
|
||||
<span class="task-text-old"></span> ⇢
|
||||
<span class="task-text-new"></span>
|
||||
</div>
|
||||
<div class="form-section task-date">
|
||||
<label><roundcube:label name="tasklist.datetime" /></label>
|
||||
<span class="task-text-old"></span> ⇢
|
||||
<span class="task-text-new"></span>
|
||||
</div>
|
||||
<div class="form-section task-recurrence">
|
||||
<label><roundcube:label name="tasklist.repeat" /></label>
|
||||
<span class="task-text-old"></span> ⇢
|
||||
<span class="task-text-new"></span>
|
||||
</div>
|
||||
<div class="form-section task-alarms">
|
||||
<label><roundcube:label name="tasklist.alarms" /></label>
|
||||
<span class="task-text-old"></span> ⇢
|
||||
<span class="task-text-new"></span>
|
||||
</div>
|
||||
<div class="form-section task-attendees">
|
||||
<label><roundcube:label name="tasklist.assignedto" /></label>
|
||||
<span class="task-text-old"></span> ⇢
|
||||
<span class="task-text-new"></span>
|
||||
</div>
|
||||
<div class="form-section task-organizer">
|
||||
<label><roundcube:label name="tasklist.roleorganizer" /></label>
|
||||
<span class="task-text-old"></span> ⇢
|
||||
<span class="task-text-new"></span>
|
||||
</div>
|
||||
<div class="form-section task-complete">
|
||||
<label><roundcube:label name="tasklist.complete" /></label>
|
||||
<span class="task-text-old"></span> ⇢
|
||||
<span class="task-text-new"></span>
|
||||
</div>
|
||||
<div class="form-section task-status">
|
||||
<label><roundcube:label name="tasklist.status" /></label>
|
||||
<span class="task-text-old"></span> ⇢
|
||||
<span class="task-text-new"></span>
|
||||
</div>
|
||||
<div class="form-section task-links">
|
||||
<label><roundcube:label name="tasklist.links" /></label>
|
||||
<span class="task-text"></span>
|
||||
</div>
|
||||
<div class="form-section task-attachments">
|
||||
<label><roundcube:label name="attachments" /></label>
|
||||
<div class="task-text-old"></div>
|
||||
<div class="task-text-new"></div>
|
||||
</div>
|
||||
</div>
|
||||
<roundcube:endif />
|
||||
|
||||
<roundcube:include file="/templates/taskedit.html" />
|
||||
|
||||
<div id="tasklistform" class="uidialog">
|
||||
|
|
|
@ -282,8 +282,14 @@ function rcube_tasklist_ui(settings)
|
|||
setTimeout(fetch_counts, 200);
|
||||
});
|
||||
|
||||
rcmail.addEventListener('plugin.task_render_changelog', task_render_changelog);
|
||||
rcmail.addEventListener('plugin.task_show_diff', task_show_diff);
|
||||
rcmail.addEventListener('plugin.task_show_revision', function(data){ task_show_dialog(null, data, true); });
|
||||
rcmail.addEventListener('plugin.close_history_dialog', close_history_dialog);
|
||||
|
||||
rcmail.register_command('list-sort', list_set_sort, true);
|
||||
rcmail.register_command('list-order', list_set_order, (settings.sort_col || 'auto') != 'auto');
|
||||
rcmail.register_command('task-history', task_history_dialog, false);
|
||||
|
||||
$('#taskviewsortmenu .by-' + (settings.sort_col || 'auto')).attr('aria-checked', 'true').addClass('selected');
|
||||
$('#taskviewsortmenu .sortorder.' + (settings.sort_order || 'asc')).attr('aria-checked', 'true').addClass('selected');
|
||||
|
@ -459,6 +465,7 @@ function rcube_tasklist_ui(settings)
|
|||
rcmail.command('menu-close', 'taskitemmenu');
|
||||
}
|
||||
else {
|
||||
rcmail.enable_command('task-history', me.tasklists[rec.list] && !!me.tasklists[rec.list].history);
|
||||
rcmail.command('menu-open', { menu: 'taskitemmenu', show: true }, e.target, e);
|
||||
menu.data('refid', id);
|
||||
me.selected_task = rec;
|
||||
|
@ -1835,7 +1842,7 @@ function rcube_tasklist_ui(settings)
|
|||
/**
|
||||
* Show task details in a dialog
|
||||
*/
|
||||
function task_show_dialog(id)
|
||||
function task_show_dialog(id, data, temp)
|
||||
{
|
||||
var $dialog = $('#taskshow'), rec, list;
|
||||
|
||||
|
@ -1848,7 +1855,7 @@ function rcube_tasklist_ui(settings)
|
|||
return $.grep(oldies, function(cls) { return cls.indexOf('status-') === 0 }).join(' ');
|
||||
});
|
||||
|
||||
if (!(rec = listdata[id]) || (rcmail.menu_stack && rcmail.menu_stack.length > 0))
|
||||
if (!(rec = (data || listdata[id])) || (rcmail.menu_stack && rcmail.menu_stack.length > 0))
|
||||
return;
|
||||
|
||||
me.selected_task = rec;
|
||||
|
@ -1892,6 +1899,10 @@ function rcube_tasklist_ui(settings)
|
|||
$dialog.addClass('status-' + String(rec.status).toLowerCase());
|
||||
}
|
||||
|
||||
if (rec.flagged) {
|
||||
$dialog.addClass('status-flagged');
|
||||
}
|
||||
|
||||
if (rec.recurrence && rec.recurrence_text) {
|
||||
$('#task-recurrence').show().children('.task-text').html(Q(rec.recurrence_text));
|
||||
}
|
||||
|
@ -1986,7 +1997,7 @@ function rcube_tasklist_ui(settings)
|
|||
.html(Q(rcmail.gettext('itip' + mystatus, 'libcalendaring')));
|
||||
}
|
||||
*/
|
||||
var show_rsvp = rsvp && list.editable && !is_organizer(rec) && rec.status != 'CANCELLED';
|
||||
var show_rsvp = !temp && rsvp && list.editable && !is_organizer(rec) && rec.status != 'CANCELLED';
|
||||
$('#task-rsvp')[(show_rsvp ? 'show' : 'hide')]();
|
||||
$('#task-rsvp .rsvp-buttons input').prop('disabled', false).filter('input[rel='+mystatus+']').prop('disabled', true);
|
||||
|
||||
|
@ -2036,6 +2047,13 @@ function rcube_tasklist_ui(settings)
|
|||
},
|
||||
close: function() {
|
||||
$dialog.dialog('destroy').appendTo(document.body);
|
||||
$('.libcal-rsvp-replymode').hide();
|
||||
},
|
||||
dragStart: function() {
|
||||
$('.libcal-rsvp-replymode').hide();
|
||||
},
|
||||
resizeStart: function() {
|
||||
$('.libcal-rsvp-replymode').hide();
|
||||
},
|
||||
buttons: buttons,
|
||||
minWidth: 500,
|
||||
|
@ -2064,6 +2082,190 @@ function rcube_tasklist_ui(settings)
|
|||
return '<span class="attendee ' + String(data.role == 'ORGANIZER' ? 'organizer' : data.status).toLowerCase() + '" title="' + Q(tooltip) + '">' + dispname + '</span> ';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function task_history_dialog()
|
||||
{
|
||||
var dialog, rec = me.selected_task;
|
||||
if (!rec || !rec.id || !window.libkolab_audittrail) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// render dialog
|
||||
$dialog = libkolab_audittrail.object_history_dialog({
|
||||
module: 'tasklist',
|
||||
container: '#taskhistory',
|
||||
title: rcmail.gettext('objectchangelog','tasklist') + ' - ' + rec.title,
|
||||
|
||||
// callback function for list actions
|
||||
listfunc: function(action, rev) {
|
||||
var rec = $dialog.data('rec');
|
||||
saving_lock = rcmail.set_busy(true, 'loading', saving_lock);
|
||||
rcmail.http_post('task', { action: action, t: { id: rec.id, list:rec.list, rev: rev } }, saving_lock);
|
||||
},
|
||||
|
||||
// callback function for comparing two object revisions
|
||||
comparefunc: function(rev1, rev2) {
|
||||
var rec = $dialog.data('rec');
|
||||
saving_lock = rcmail.set_busy(true, 'loading', saving_lock);
|
||||
rcmail.http_post('task', { action:'diff', t: { id: rec.id, list: rec.list, rev1: rev1, rev2: rev2 } }, saving_lock);
|
||||
}
|
||||
});
|
||||
|
||||
$dialog.data('rec', rec);
|
||||
|
||||
// fetch changelog data
|
||||
saving_lock = rcmail.set_busy(true, 'loading', saving_lock);
|
||||
rcmail.http_post('task', { action: 'changelog', t: { id: rec.id, list: rec.list } }, saving_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function task_render_changelog(data)
|
||||
{
|
||||
var $dialog = $('#taskhistory'),
|
||||
rec = $dialog.data('rec');
|
||||
|
||||
if (data === false || !data.length || !event) {
|
||||
// display 'unavailable' message
|
||||
$('<div class="notfound-message task-dialog-message warning">' + rcmail.gettext('objectchangelognotavailable','tasklist') + '</div>')
|
||||
.insertBefore($dialog.find('.changelog-table').hide());
|
||||
return;
|
||||
}
|
||||
|
||||
data.module = 'tasklist';
|
||||
libkolab_audittrail.render_changelog(data, rec, me.tasklists[rec.list]);
|
||||
|
||||
// set dialog size according to content
|
||||
me.dialog_resize($dialog.get(0), $dialog.height(), 600);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function task_show_diff(data)
|
||||
{
|
||||
var rec = me.selected_task,
|
||||
$dialog = $("#taskdiff");
|
||||
|
||||
$dialog.find('div.form-section, h2.task-title-new').hide().data('set', false).find('.index').html('');
|
||||
$dialog.find('div.form-section.clone').remove();
|
||||
|
||||
// always show event title and date
|
||||
$('.task-title', $dialog).text(rec.title).removeClass('task-text-old').show();
|
||||
|
||||
// show each property change
|
||||
$.each(data.changes, function(i, change) {
|
||||
var prop = change.property, r2, html = false,
|
||||
row = $('div.task-' + prop, $dialog).first();
|
||||
|
||||
// special case: title
|
||||
if (prop == 'title') {
|
||||
$('.task-title', $dialog).addClass('task-text-old').text(change['old'] || '--');
|
||||
$('.task-title-new', $dialog).text(change['new'] || '--').show();
|
||||
}
|
||||
|
||||
// no display container for this property
|
||||
if (!row.length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// clone row if already exists
|
||||
if (row.data('set')) {
|
||||
r2 = row.clone().addClass('clone').insertAfter(row);
|
||||
row = r2;
|
||||
}
|
||||
|
||||
// render description text
|
||||
if (prop == 'description') {
|
||||
if (!change.diff_ && change['old']) change.old_ = text2html(change['old']);
|
||||
if (!change.diff_ && change['new']) change.new_ = text2html(change['new']);
|
||||
html = true;
|
||||
}
|
||||
// format attendees struct
|
||||
else if (prop == 'attendees') {
|
||||
if (change['old']) change.old_ = task_attendee_html(change['old']);
|
||||
if (change['new']) change.new_ = task_attendee_html($.extend({}, change['old'] || {}, change['new']));
|
||||
html = true;
|
||||
}
|
||||
// localize status
|
||||
else if (prop == 'status') {
|
||||
if (change['old']) change.old_ = rcmail.gettext('status-'+String(change['old']).toLowerCase(), 'tasklist');
|
||||
if (change['new']) change.new_ = rcmail.gettext('status-'+String(change['new']).toLowerCase(), 'tasklist');
|
||||
}
|
||||
|
||||
// format attachments struct
|
||||
if (prop == 'attachments') {
|
||||
if (change['old']) task_show_attachments([change['old']], row.children('.task-text-old'), rec, false);
|
||||
else row.children('.task-text-old').text('--');
|
||||
if (change['new']) task_show_attachments([$.extend({}, change['old'] || {}, change['new'])], row.children('.task-text-new'), rec, false);
|
||||
else row.children('.task-text-new').text('--');
|
||||
// remove click handler in diff view
|
||||
$('.attachmentslist li a', row).unbind('click').removeAttr('href');
|
||||
}
|
||||
else if (change.diff_) {
|
||||
row.children('.task-text-diff').html(change.diff_);
|
||||
row.children('.task-text-old, .task-text-new').hide();
|
||||
}
|
||||
else {
|
||||
if (!html) {
|
||||
// escape HTML characters
|
||||
change.old_ = Q(change.old_ || change['old'] || '--')
|
||||
change.new_ = Q(change.new_ || change['new'] || '--')
|
||||
}
|
||||
row.children('.task-text-old').html(change.old_ || change['old'] || '--').show();
|
||||
row.children('.task-text-new').html(change.new_ || change['new'] || '--').show();
|
||||
}
|
||||
|
||||
// display index number
|
||||
if (typeof change.index != 'undefined') {
|
||||
row.find('.index').html('(' + change.index + ')');
|
||||
}
|
||||
|
||||
row.show().data('set', true);
|
||||
});
|
||||
|
||||
var buttons = {};
|
||||
buttons[rcmail.gettext('close')] = function() {
|
||||
$dialog.dialog('close');
|
||||
};
|
||||
|
||||
// open jquery UI dialog
|
||||
$dialog.dialog({
|
||||
modal: false,
|
||||
resizable: true,
|
||||
closeOnEscape: true,
|
||||
title: rcmail.gettext('objectdiff','tasklist').replace('$rev1', data.rev1).replace('$rev2', data.rev2) + ' - ' + rec.title,
|
||||
open: function() {
|
||||
$dialog.attr('aria-hidden', 'false');
|
||||
setTimeout(function(){
|
||||
$dialog.parent().find('.ui-button:not(.ui-dialog-titlebar-close)').first().focus();
|
||||
}, 5);
|
||||
},
|
||||
close: function() {
|
||||
$dialog.dialog('destroy').attr('aria-hidden', 'true').hide();
|
||||
},
|
||||
buttons: buttons,
|
||||
minWidth: 320,
|
||||
width: 450
|
||||
}).show();
|
||||
|
||||
// set dialog size according to content
|
||||
me.dialog_resize($dialog.get(0), $dialog.height(), 400);
|
||||
}
|
||||
|
||||
// close the event history dialog
|
||||
function close_history_dialog()
|
||||
{
|
||||
$('#taskhistory, #taskdiff').each(function(i, elem) {
|
||||
var $dialog = $(elem);
|
||||
if ($dialog.is(':ui-dialog'))
|
||||
$dialog.dialog('close');
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Opens the dialog to edit a task
|
||||
*/
|
||||
|
@ -2371,17 +2573,22 @@ function rcube_tasklist_ui(settings)
|
|||
if (!rec.id || rec.id < 0)
|
||||
return false;
|
||||
|
||||
var qstring = '_id='+urlencode(att.id)+'&_t='+urlencode(rec.recurrence_id||rec.id)+'&_list='+urlencode(rec.list);
|
||||
var query = { _id: att.id, _t: rec.recurrence_id||rec.id, _list:rec.list, _frame: 1 };
|
||||
if (rec.rev)
|
||||
query._rev = event.rev;
|
||||
|
||||
|
||||
// open attachment in frame if it's of a supported mimetype
|
||||
// similar as in app.js and calendar_ui.js
|
||||
if (att.id && att.mimetype && $.inArray(att.mimetype, settings.mimetypes)>=0) {
|
||||
if (rcmail.open_window(rcmail.env.comm_path+'&_action=get-attachment&'+qstring+'&_frame=1', true, true)) {
|
||||
if (rcmail.open_window(rcmail.url('get-attachment', query), true, true)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rcmail.goto_url('get-attachment', qstring+'&_download=1', false);
|
||||
query._frame = null;
|
||||
query._download = 1;
|
||||
rcmail.goto_url('get-attachment', query, false);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -208,7 +208,7 @@ class tasklist extends rcube_plugin
|
|||
$action = rcube_utils::get_input_value('action', rcube_utils::INPUT_GPC);
|
||||
$rec = rcube_utils::get_input_value('t', rcube_utils::INPUT_POST, true);
|
||||
$oldrec = $rec;
|
||||
$success = $refresh = false;
|
||||
$success = $refresh = $got_msg = false;
|
||||
|
||||
// force notify if hidden + active
|
||||
$itip_send_option = (int)$this->rc->config->get('calendar_itip_send_option', 3);
|
||||
|
@ -385,13 +385,115 @@ class tasklist extends rcube_plugin
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'changelog':
|
||||
$data = $this->driver->get_task_changelog($rec);
|
||||
if (is_array($data) && !empty($data)) {
|
||||
$lib = $this->lib;
|
||||
$dtformat = $this->rc->config->get('date_format') . ' ' . $this->rc->config->get('time_format');
|
||||
array_walk($data, function(&$change) use ($lib, $dtformat) {
|
||||
if ($change['date']) {
|
||||
$dt = $lib->adjust_timezone($change['date']);
|
||||
if ($dt instanceof DateTime)
|
||||
$change['date'] = $this->rc->format_date($dt, $dtformat, false);
|
||||
}
|
||||
});
|
||||
$this->rc->output->command('plugin.task_render_changelog', $data);
|
||||
}
|
||||
else {
|
||||
$this->rc->output->command('plugin.task_render_changelog', false);
|
||||
}
|
||||
$got_msg = true;
|
||||
break;
|
||||
|
||||
case 'diff':
|
||||
$data = $this->driver->get_task_diff($rec, $rec['rev1'], $rec['rev2']);
|
||||
if (is_array($data)) {
|
||||
// convert some properties, similar to self::_client_event()
|
||||
$lib = $this->lib;
|
||||
$date_format = $this->rc->config->get('date_format', 'Y-m-d');
|
||||
$time_format = $this->rc->config->get('time_format', 'H:i');
|
||||
array_walk($data['changes'], function(&$change, $i) use ($lib, $date_format, $time_format) {
|
||||
// convert date cols
|
||||
if (in_array($change['property'], array('date','start','created','changed'))) {
|
||||
if (!empty($change['old'])) {
|
||||
$dtformat = strlen($change['old']) == 10 ? $date_format : $date_format . ' ' . $time_format;
|
||||
$change['old_'] = $lib->adjust_timezone($change['old'], strlen($change['old']) == 10)->format($dtformat);
|
||||
}
|
||||
if (!empty($change['new'])) {
|
||||
$dtformat = strlen($change['new']) == 10 ? $date_format : $date_format . ' ' . $time_format;
|
||||
$change['new_'] = $lib->adjust_timezone($change['new'], strlen($change['new']) == 10)->format($dtformat);
|
||||
}
|
||||
}
|
||||
// create textual representation for alarms and recurrence
|
||||
if ($change['property'] == 'alarms') {
|
||||
if (is_array($change['old']))
|
||||
$change['old_'] = libcalendaring::alarm_text($change['old']);
|
||||
if (is_array($change['new']))
|
||||
$change['new_'] = libcalendaring::alarm_text(array_merge((array)$change['old'], $change['new']));
|
||||
}
|
||||
if ($change['property'] == 'recurrence') {
|
||||
if (is_array($change['old']))
|
||||
$change['old_'] = $lib->recurrence_text($change['old']);
|
||||
if (is_array($change['new']))
|
||||
$change['new_'] = $lib->recurrence_text(array_merge((array)$change['old'], $change['new']));
|
||||
}
|
||||
if ($change['property'] == 'complete') {
|
||||
$change['old_'] = intval($change['old']) . '%';
|
||||
$change['new_'] = intval($change['new']) . '%';
|
||||
}
|
||||
if ($change['property'] == 'attachments') {
|
||||
if (is_array($change['old']))
|
||||
$change['old']['classname'] = rcube_utils::file2class($change['old']['mimetype'], $change['old']['name']);
|
||||
if (is_array($change['new'])) {
|
||||
$change['new'] = array_merge((array)$change['old'], $change['new']);
|
||||
$change['new']['classname'] = rcube_utils::file2class($change['new']['mimetype'], $change['new']['name']);
|
||||
}
|
||||
}
|
||||
// compute a nice diff of description texts
|
||||
if ($change['property'] == 'description') {
|
||||
$change['diff_'] = libkolab::html_diff($change['old'], $change['new']);
|
||||
}
|
||||
});
|
||||
$this->rc->output->command('plugin.task_show_diff', $data);
|
||||
}
|
||||
else {
|
||||
$this->rc->output->command('display_message', $this->gettext('objectdiffnotavailable'), 'error');
|
||||
}
|
||||
$got_msg = true;
|
||||
break;
|
||||
|
||||
case 'show':
|
||||
if ($rec = $this->driver->get_task_revison($rec, $rec['rev'])) {
|
||||
$this->encode_task($rec);
|
||||
$rec['readonly'] = 1;
|
||||
$this->rc->output->command('plugin.task_show_revision', $rec);
|
||||
}
|
||||
else {
|
||||
$this->rc->output->command('display_message', $this->gettext('objectnotfound'), 'error');
|
||||
}
|
||||
$got_msg = true;
|
||||
break;
|
||||
|
||||
case 'restore':
|
||||
if ($success = $this->driver->restore_task_revision($rec, $rec['rev'])) {
|
||||
$refresh = $this->driver->get_task($rec);
|
||||
$this->rc->output->command('display_message', $this->gettext(array('name' => 'objectrestoresuccess', 'vars' => array('rev' => $rec['rev']))), 'confirmation');
|
||||
$this->rc->output->command('plugin.close_history_dialog');
|
||||
}
|
||||
else {
|
||||
$this->rc->output->command('display_message', $this->gettext('objectrestoreerror'), 'error');
|
||||
}
|
||||
$got_msg = true;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if ($success) {
|
||||
$this->rc->output->show_message('successfullysaved', 'confirmation');
|
||||
$this->update_counts($oldrec, $refresh);
|
||||
}
|
||||
else {
|
||||
else if (!$got_msg) {
|
||||
$this->rc->output->show_message('tasklist.errorsaving', 'error');
|
||||
}
|
||||
|
||||
|
@ -1268,7 +1370,7 @@ class tasklist extends rcube_plugin
|
|||
$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', 'delete', 'libcalendaring.expandattendeegroup', 'libcalendaring.expandattendeegroupnodata');
|
||||
$this->rc->output->add_label('autocompletechars', 'autocompletemore', 'delete', 'close', 'libcalendaring.expandattendeegroup', 'libcalendaring.expandattendeegroupnodata');
|
||||
|
||||
$this->rc->output->set_pagetitle($this->gettext('navtitle'));
|
||||
$this->rc->output->send('tasklist.mainview');
|
||||
|
@ -1396,8 +1498,9 @@ class tasklist extends rcube_plugin
|
|||
$task = rcube_utils::get_input_value('_t', rcube_utils::INPUT_GPC);
|
||||
$list = rcube_utils::get_input_value('_list', rcube_utils::INPUT_GPC);
|
||||
$id = rcube_utils::get_input_value('_id', rcube_utils::INPUT_GPC);
|
||||
$rev = rcube_utils::get_input_value('_rev', rcube_utils::INPUT_GPC);
|
||||
|
||||
$task = array('id' => $task, 'list' => $list);
|
||||
$task = array('id' => $task, 'list' => $list, 'rev' => $rev);
|
||||
$attachment = $this->driver->get_attachment($id, $task);
|
||||
|
||||
// show part page
|
||||
|
|
|
@ -156,6 +156,7 @@ class tasklist_ui
|
|||
$this->plugin->register_handler('plugin.identity_select', array($this, 'identity_select'));
|
||||
$this->plugin->register_handler('plugin.edit_attendees_notify', array($this, 'edit_attendees_notify'));
|
||||
$this->plugin->register_handler('plugin.task_rsvp_buttons', array($this->plugin->itip, 'itip_rsvp_buttons'));
|
||||
$this->plugin->register_handler('plugin.object_changelog_table', array('libkolab', 'object_changelog_table'));
|
||||
|
||||
jqueryui::tagedit();
|
||||
|
||||
|
@ -165,6 +166,7 @@ class tasklist_ui
|
|||
// include kolab folderlist widget if available
|
||||
if (in_array('libkolab', $this->plugin->api->loaded_plugins())) {
|
||||
$this->plugin->api->include_script('libkolab/js/folderlist.js');
|
||||
$this->plugin->api->include_script('libkolab/js/audittrail.js');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue