- List linked tasks in mail view, like notes
- Deep-links into the tasks view opening the linked task - Mark tasks as complete directly from mail view
This commit is contained in:
parent
f505abb350
commit
adc41ebf61
8 changed files with 204 additions and 6 deletions
|
@ -1237,6 +1237,25 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
return $this->_convert_message_uri($uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find tasks assigned to a specified message
|
||||
*
|
||||
* @see tasklist_driver::get_message_related_tasks()
|
||||
*/
|
||||
public function get_message_related_tasks($headers, $folder)
|
||||
{
|
||||
$config = kolab_storage_config::get_instance();
|
||||
$result = $config->get_message_relations($headers, $folder, 'task');
|
||||
|
||||
foreach ($result as $idx => $rec) {
|
||||
$task = $this->_to_rcube_task($rec);
|
||||
$task['list'] = kolab_storage::folder_id($rec['_mailbox']);
|
||||
$result[$idx] = $task;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -290,8 +290,8 @@ abstract class tasklist_driver
|
|||
/**
|
||||
* Build a URI representing the given message reference
|
||||
*
|
||||
* @param object rcube_message_header Instance holding the message headers
|
||||
* @param string IMAP folder the message resides in
|
||||
* @param object $headers rcube_message_header instance holding the message headers
|
||||
* @param string $folder IMAP folder the message resides in
|
||||
*
|
||||
* @return string An URI referencing the given IMAP message
|
||||
*/
|
||||
|
@ -301,6 +301,20 @@ abstract class tasklist_driver
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find tasks assigned to a specified message
|
||||
*
|
||||
* @param object $message rcube_message_header instance
|
||||
* @param string $folder IMAP folder the message resides in
|
||||
*
|
||||
* @param array List of linked task objects
|
||||
*/
|
||||
public function get_message_related_tasks($headers, $folder)
|
||||
{
|
||||
// to be implemented by the derived classes
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to determine whether the given task is considered "complete"
|
||||
*
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 3.2 KiB |
|
@ -1337,6 +1337,46 @@ div.tasklist-invitebox .rsvp-status.accepted,
|
|||
background-position: 2px -220px;
|
||||
}
|
||||
|
||||
div.messagetasklinks {
|
||||
margin: 8px 8px;
|
||||
padding: 4px 8px;
|
||||
border: 1px solid #dfdfdf;
|
||||
background: #fafafa;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
div.messagetasklinks span.messagetaskref {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin-right: 1em;
|
||||
padding-right: 24px;
|
||||
}
|
||||
|
||||
div.messagetasklinks a.messagetasklink {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
padding: 3px 0 2px 22px;
|
||||
text-shadow: 0px 1px 1px #fff;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 16em;
|
||||
background: url(buttons.png) -6px -115px no-repeat;
|
||||
}
|
||||
|
||||
div.messagetasklinks span.messagetaskref.complete a.messagetasklink {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
div.messagetasklinks span.messagetaskref input.complete {
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
right: 2px;
|
||||
}
|
||||
|
||||
|
||||
/** Special hacks for IE7 **/
|
||||
/** They need to be in this file to also affect the task-create dialog embedded in mail view **/
|
||||
|
|
|
@ -137,6 +137,11 @@ function rcube_tasklist_ui(settings)
|
|||
{
|
||||
// initialize task list selectors
|
||||
for (var id in me.tasklists) {
|
||||
if (settings.selected_list && me.tasklists[settings.selected_list] && !me.tasklists[settings.selected_list].active) {
|
||||
me.tasklists[settings.selected_list].active = true;
|
||||
me.selected_list = settings.selected_list;
|
||||
$(rcmail.gui_objects.tasklistslist).find("input[value='"+settings.selected_list+"']").prop('checked', true);
|
||||
}
|
||||
if (me.tasklists[id].editable && (!me.selected_list || me.tasklists[id].default || (me.tasklists[id].active && !me.tasklists[me.selected_list].active))) {
|
||||
me.selected_list = id;
|
||||
}
|
||||
|
@ -269,10 +274,9 @@ function rcube_tasklist_ui(settings)
|
|||
$('#taskviewsortmenu .by-' + (settings.sort_col || 'auto')).attr('aria-checked', 'true').addClass('selected');
|
||||
$('#taskviewsortmenu .sortorder.' + (settings.sort_order || 'asc')).attr('aria-checked', 'true').addClass('selected');
|
||||
|
||||
|
||||
// start loading tasks
|
||||
fetch_counts();
|
||||
list_tasks();
|
||||
list_tasks(settings.selected_filter);
|
||||
|
||||
// register event handlers for UI elements
|
||||
$('#taskselector a').click(function(e) {
|
||||
|
@ -769,6 +773,19 @@ function rcube_tasklist_ui(settings)
|
|||
append_tags(response.tags || []);
|
||||
render_tasklist();
|
||||
|
||||
// show selected task dialog
|
||||
if (settings.selected_id) {
|
||||
if (listdata[settings.selected_id]) {
|
||||
task_show_dialog(settings.selected_id);
|
||||
delete settings.selected_id;
|
||||
}
|
||||
|
||||
// remove _id from window location
|
||||
if (window.history.replaceState) {
|
||||
window.history.replaceState({}, document.title, rcmail.url('', { _list: me.selected_list }));
|
||||
}
|
||||
}
|
||||
|
||||
rcmail.set_busy(false, 'loading', ui_loading);
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ class tasklist extends rcube_plugin
|
|||
public $home; // declare public to be used in other classes
|
||||
|
||||
private $collapsed_tasks = array();
|
||||
private $message_tasks = array();
|
||||
private $itip;
|
||||
private $ical;
|
||||
|
||||
|
@ -125,6 +126,9 @@ class tasklist extends rcube_plugin
|
|||
}
|
||||
else if ($args['task'] == 'mail') {
|
||||
if ($args['action'] == 'show' || $args['action'] == 'preview') {
|
||||
if ($this->rc->config->get('tasklist_mail_embed', true)) {
|
||||
$this->add_hook('message_load', array($this, 'mail_message_load'));
|
||||
}
|
||||
$this->add_hook('template_object_messagebody', array($this, 'mail_messagebody_html'));
|
||||
}
|
||||
|
||||
|
@ -204,7 +208,8 @@ class tasklist extends rcube_plugin
|
|||
$success = $refresh = false;
|
||||
|
||||
// force notify if hidden + active
|
||||
if ((int)$this->rc->config->get('calendar_itip_send_option', 3) === 1 && empty($rec['_reportpartstat']))
|
||||
$itip_send_option = (int)$this->rc->config->get('calendar_itip_send_option', 3);
|
||||
if ($itip_send_option === 1 && empty($rec['_reportpartstat']))
|
||||
$rec['_notify'] = 1;
|
||||
|
||||
switch ($action) {
|
||||
|
@ -220,6 +225,24 @@ class tasklist extends rcube_plugin
|
|||
}
|
||||
break;
|
||||
|
||||
case 'complete':
|
||||
$complete = intval(rcube_utils::get_input_value('complete', rcube_utils::INPUT_POST));
|
||||
if (!($rec = $this->driver->get_task($rec))) {
|
||||
break;
|
||||
}
|
||||
|
||||
$rec['status'] = $complete ? 'COMPLETED' : ($rec['complete'] > 0 ? 'IN-PROCESS' : 'NEEDS-ACTION');
|
||||
|
||||
// sent itip notifications if enabled (no user interaction here)
|
||||
if (($itip_send_option & 1)) {
|
||||
if ($this->is_attendee($rec)) {
|
||||
$rec['_reportpartstat'] = $rec['status'];
|
||||
}
|
||||
else if ($this->is_organizer($rec)) {
|
||||
$rec['_notify'] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
case 'edit':
|
||||
$rec = $this->prepare_task($rec);
|
||||
$clone = $this->handle_recurrence($rec, $this->driver->get_task($rec));
|
||||
|
@ -1437,7 +1460,36 @@ class tasklist extends rcube_plugin
|
|||
}
|
||||
}
|
||||
|
||||
// prepend event boxes to message body
|
||||
// list linked tasks
|
||||
$links = array();
|
||||
foreach ($this->message_tasks as $task) {
|
||||
$checkbox = new html_checkbox(array(
|
||||
'name' => 'completed',
|
||||
'class' => 'complete',
|
||||
'title' => $this->gettext('complete'),
|
||||
'data-list' => $task['list'],
|
||||
));
|
||||
$complete = $this->driver->is_complete($task);
|
||||
$links[] = html::span('messagetaskref' . ($complete ? ' complete' : ''),
|
||||
$checkbox->show($complete ? $task['uid'] : null, array('value' => $task['uid'])) . ' ' .
|
||||
html::a(array(
|
||||
'href' => $this->rc->url(array(
|
||||
'task' => 'tasks',
|
||||
'list' => $task['list'],
|
||||
'id' => $task['uid'],
|
||||
'complete' => $complete?1:null,
|
||||
)),
|
||||
'class' => 'messagetasklink',
|
||||
'rel' => $task['uid'] . '@' . $task['list'],
|
||||
'target' => '_blank',
|
||||
), Q($task['title']))
|
||||
);
|
||||
}
|
||||
if (count($links)) {
|
||||
$html .= html::div('messagetasklinks', join("\n", $links));
|
||||
}
|
||||
|
||||
// prepend iTip/relation boxes to message body
|
||||
if ($html) {
|
||||
$this->load_ui();
|
||||
$this->ui->init();
|
||||
|
@ -1465,6 +1517,17 @@ class tasklist extends rcube_plugin
|
|||
return $p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup backend storage and find notes associated with the given message
|
||||
*/
|
||||
public function mail_message_load($p)
|
||||
{
|
||||
if (!$p['object']->headers->others['x-kolab-type']) {
|
||||
$this->load_driver();
|
||||
$this->message_tasks = $this->driver->get_message_related_tasks($p['object']->headers, $p['object']->folder);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load iCalendar functions
|
||||
*/
|
||||
|
|
|
@ -30,6 +30,7 @@ function rcube_tasklist(settings)
|
|||
/* private vars */
|
||||
var ui_loaded = false;
|
||||
var me = this;
|
||||
var mywin = window;
|
||||
|
||||
/* public members */
|
||||
this.ui;
|
||||
|
@ -79,6 +80,18 @@ function rcube_tasklist(settings)
|
|||
function mail2task_dialog(prop)
|
||||
{
|
||||
this.ui.edit_task(null, 'new', prop);
|
||||
rcmail.addEventListener('responseaftertask', refresh_mailview);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload the mail view/preview to update the tasks listing
|
||||
*/
|
||||
function refresh_mailview(e)
|
||||
{
|
||||
var win = rcmail.env.contentframe ? rcmail.get_frame_window(rcmail.env.contentframe) : mywin;
|
||||
if (win && e.response.action == 'task') {
|
||||
win.location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
// handler for attachment-save-tasklist commands
|
||||
|
@ -95,6 +108,21 @@ function rcube_tasklist(settings)
|
|||
}
|
||||
}
|
||||
|
||||
// register event handlers on linked task items in message view
|
||||
// the checkbox allows to mark a task as complete
|
||||
if (rcmail.env.action == 'show' || rcmail.env.action == 'preview') {
|
||||
$('div.messagetasklinks input.complete').click(function(e) {
|
||||
var $this = $(this);
|
||||
$(this).closest('.messagetaskref').toggleClass('complete');
|
||||
|
||||
// submit change to server
|
||||
rcmail.http_post('tasks/task', {
|
||||
action: 'complete',
|
||||
t: { id:this.value, list:$this.attr('data-list') },
|
||||
complete: this.checked?1:0
|
||||
}, rcmail.set_busy(true, 'tasklist.savingdata'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* tasklist plugin initialization (for email task) */
|
||||
|
|
|
@ -92,6 +92,23 @@ class tasklist_ui
|
|||
'emails' => ';' . strtolower(join(';', $identity['emails']))
|
||||
);
|
||||
|
||||
if ($list = rcube_utils::get_input_value('_list', rcube_utils::INPUT_GPC)) {
|
||||
$settings['selected_list'] = $list;
|
||||
}
|
||||
if ($list && ($id = rcube_utils::get_input_value('_id', rcube_utils::INPUT_GPC))) {
|
||||
$settings['selected_id'] = $id;
|
||||
|
||||
// check if the referenced task is completed
|
||||
$task = $this->plugin->driver->get_task(array('id' => $id, 'list' => $list));
|
||||
console($id, $task);
|
||||
if ($task && $this->plugin->driver->is_complete($task)) {
|
||||
$settings['selected_filter'] = 'complete';
|
||||
}
|
||||
}
|
||||
else if ($filter = rcube_utils::get_input_value('_filter', rcube_utils::INPUT_GPC)) {
|
||||
$settings['selected_filter'] = $filter;
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue