Show RSVP buttons for assigned tasks which require a response

This commit is contained in:
Thomas Bruederli 2014-08-01 11:16:57 +02:00
parent e48f0dbf15
commit 8fe64d7400
7 changed files with 109 additions and 16 deletions

View file

@ -457,7 +457,7 @@ class tasklist_kolab_driver extends tasklist_driver
$tomorrow_date = new DateTime('now + 1 day', $this->plugin->timezone);
$tomorrow = $tomorrow_date->format('Y-m-d');
$counts = array('all' => 0, 'flagged' => 0, 'today' => 0, 'tomorrow' => 0, 'overdue' => 0, 'nodate' => 0);
$counts = array('all' => 0, 'flagged' => 0, 'today' => 0, 'tomorrow' => 0, 'overdue' => 0, 'nodate' => 0, 'mytasks' => 0);
foreach ($lists as $list_id) {
if (!$folder = $this->get_folder($list_id)) {
continue;
@ -479,6 +479,8 @@ class tasklist_kolab_driver extends tasklist_driver
$counts['tomorrow']++;
else if ($rec['date'] < $today)
$counts['overdue']++;
if ($this->plugin->is_attendee($rec) !== false)
$counts['mytasks']++;
}
}

View file

@ -146,6 +146,7 @@ $labels['attendeedelegated'] = 'Assignee has delegated to $delegatedto';
$labels['attendeein-process'] = 'Assignee is in-process';
$labels['attendeecompleted'] = 'Assignee has completed';
$labels['acceptinvitation'] = 'Do you accept this assignment?';
$labels['itipdeclinetask'] = 'Decline your assignment to this task to the organizer';
$labels['declinedeleteconfirm'] = 'Do you also want to delete this declined task from your tasks list?';
$labels['itipcomment'] = 'Invitation/notification comment';

View file

@ -1132,12 +1132,18 @@ div.tasklist-invitebox td.label {
padding-right: 1em;
}
#event-rsvp .rsvp-buttons,
#task-rsvp .rsvp-buttons,
#task-rsvp .itip-reply-controls,
div.tasklist-invitebox .itip-buttons div {
margin-top: 0.5em;
}
#event-rsvp input.button,
#task-rsvp .itip-reply-controls a,
#task-rsvp .itip-reply-controls label {
color: #333;
}
#task-rsvp input.button,
div.tasklist-invitebox input.button {
font-weight: bold;
margin-right: 0.5em;
@ -1164,7 +1170,7 @@ div.tasklist-invitebox .rsvp-status.hint {
font-style: italic;
}
#event-partstat .changersvp,
#task-partstat .changersvp,
.edit-attendees-table td.confirmstate span,
div.tasklist-invitebox .rsvp-status.declined,
div.tasklist-invitebox .rsvp-status.tentative,
@ -1177,37 +1183,37 @@ div.tasklist-invitebox .rsvp-status.needs-action {
background: url(images/attendee-status.png) 2px -20px no-repeat;
}
#event-partstat .changersvp.declined,
#task-partstat .changersvp.declined,
div.tasklist-invitebox .rsvp-status.declined,
.edit-attendees-table td.confirmstate span.declined {
background-position: 2px -40px;
}
#event-partstat .changersvp.tentative,
#task-partstat .changersvp.tentative,
div.tasklist-invitebox .rsvp-status.tentative,
.edit-attendees-table td.confirmstate span.tentative {
background-position: 2px -60px;
}
#event-partstat .changersvp.delegated,
#task-partstat .changersvp.delegated,
div.tasklist-invitebox .rsvp-status.delegated,
.edit-attendees-table td.confirmstate span.delegated {
background-position: 2px -180px;
}
#event-partstat .changersvp.needs-action,
#task-partstat .changersvp.needs-action,
div.tasklist-invitebox .rsvp-status.needs-action,
.edit-attendees-table td.confirmstate span.needs-action {
background-position: 2px 0;
}
#event-partstat .changersvp.in-process,
#task-partstat .changersvp.in-process,
div.tasklist-invitebox .rsvp-status.in-process,
.edit-attendees-table td.confirmstate span.in-process {
background-position: 2px -200px;
}
#event-partstat .changersvp.accepted,
#task-partstat .changersvp.accepted,
div.tasklist-invitebox .rsvp-status.accepted,
.edit-attendees-table td.confirmstate span.accepted {
background-position: 2px -220px;

View file

@ -90,7 +90,7 @@
<li class="later" role="radio" aria-checked="false" aria-labelledby="aria-radio-later"><a href="#later" id="aria-radio-later"><roundcube:label name="tasklist.later" /></a></li>
<li class="nodate" role="radio" aria-checked="false" aria-labelledby="aria-radio-nodate"><a href="#nodate" id="aria-radio-nodate"><roundcube:label name="tasklist.nodate" ucfirst="true" /></a></li>
<roundcube:if condition="env:tasklist_driver == 'kolab'" />
<li class="mytasks" role="radio" aria-checked="false" aria-labelledby="aria-radio-mytasks"><a href="#mytasks" id="aria-radio-mytasks" title="<roundcube:label name='tasklist.mytaskstitle'/>"><roundcube:label name="tasklist.mytasks" /></a></li>
<li class="mytasks" role="radio" aria-checked="false" aria-labelledby="aria-radio-mytasks"><a href="#mytasks" id="aria-radio-mytasks" title="<roundcube:label name='tasklist.mytaskstitle'/>"><roundcube:label name="tasklist.mytasks" /><span class="count"></span></a></li>
<li class="assigned" role="radio" aria-checked="false" aria-labelledby="aria-radio-assigned"><a href="#assigned" id="aria-radio-assigned" title="<roundcube:label name='tasklist.assignedtitle'/>"><roundcube:label name="tasklist.assigned" /></a></li>
<roundcube:endif />
<li class="complete" role="radio" aria-checked="false" aria-labelledby="aria-radio-complete"><a href="#complete" id="aria-radio-complete"><roundcube:label name="tasklist.complete" /><span class="count"></span></a></li>
@ -195,6 +195,18 @@
<label><roundcube:label name="attachments" /></label>
<div class="task-text"></div>
</div>
<div id="task-created-changed" class="form-section">
<label><roundcube:label name="tasklist.created" /></label>
<span class="task-text task-created"></span>
<label><roundcube:label name="tasklist.changed" /></label>
<span class="task-text task-changed"></span>
</div>
<div id="task-rsvp-comment" class="form-section">
<label><roundcube:label name="tasklist.rsvpcomment" /></label>
<span class="task-text"></span>
</div>
<roundcube:object name="plugin.task_rsvp_buttons" id="task-rsvp" class="task-dialog-message" style="display:none" />
</div>
<roundcube:include file="/templates/taskedit.html" />

View file

@ -502,6 +502,35 @@ function rcube_tasklist_ui(settings)
}
});
// init RSVP widget
$('#task-rsvp input.button').click(function(e) {
var response = $(this).attr('rel');
if (me.selected_task && me.selected_task.attendees && response) {
// update attendee status
for (var data, i=0; i < me.selected_task.attendees.length; i++) {
data = me.selected_task.attendees[i];
if (settings.identity.emails.indexOf(';'+String(data.email).toLowerCase()) >= 0) {
data.status = response.toUpperCase();
delete data.rsvp; // unset RSVP flag
}
}
// submit status change to server
saving_lock = rcmail.set_busy(true, 'tasklist.savingdata');
rcmail.http_post('tasks/task', {
action: 'rsvp',
t: me.selected_task,
filter: filtermask,
status: response,
noreply: $('#noreply-task-rsvp').prop('checked') ? 1 : 0,
comment: $('#reply-comment-task-rsvp').val()
});
task_show_dialog(me.selected_task.id);
}
});
// handle global document clicks: close popup menus
$(document.body).click(clear_popups);
@ -1613,7 +1642,7 @@ function rcube_tasklist_ui(settings)
$('#task-completeness .task-text').html(((rec.complete || 0) * 100) + '%');
$('#task-status')[(rec.status ? 'show' : 'hide')]().children('.task-text').html(rcmail.gettext('status-'+String(rec.status).toLowerCase(),'tasklist'));
$('#task-list .task-text').html(Q(me.tasklists[rec.list] ? me.tasklists[rec.list].name : ''));
$('#task-attendees, #task-organizer').hide();
$('#task-attendees, #task-organizer, #task-created-changed, #task-rsvp-comment').hide();
var itags = get_inherited_tags(rec);
var taglist = $('#task-tags')[(rec.tags && rec.tags.length || itags.length ? 'show' : 'hide')]().children('.task-text').empty();
@ -1657,7 +1686,6 @@ function rcube_tasklist_ui(settings)
// list task attendees
if (list.attendees && rec.attendees) {
console.log(rec.attendees)
/*
// sort resources to the end
rec.attendees.sort(function(a,b) {
@ -1720,13 +1748,16 @@ function rcube_tasklist_ui(settings)
.children('.task-text')
.html(Q(rcmail.gettext('itip' + mystatus, 'libcalendaring')));
}
$('#task-rsvp')[(rsvp && !is_organizer(event) && rec.status != 'CANCELLED' ? 'show' : 'hide')]();
*/
var show_rsvp = rsvp && !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);
if (show_rsvp && rec.comment) {
$('#task-rsvp-comment').show().children('.task-text').html(Q(rec.comment));
}
$('#task-rsvp a.reply-comment-toggle').show();
$('#task-rsvp .itip-reply-comment textarea').hide().val('');
*/
if (rec.organizer && !organizer) {
$('#task-organizer').show().children('.task-text').html(task_attendee_html(rec.organizer));

View file

@ -321,6 +321,22 @@ class tasklist extends rcube_plugin
$this->rc->user->save_prefs(array('tasklist_collapsed_tasks' => join(',', array_unique($this->collapsed_tasks))));
return; // avoid further actions
case 'rsvp':
$status = get_input_value('status', RCUBE_INPUT_GPC);
$task = $this->driver->get_task($rec);
$task['attendees'] = $rec['attendees'];
$rec = $task;
if ($success = $this->driver->edit_task($rec)) {
$noreply = intval(get_input_value('noreply', RCUBE_INPUT_GPC)) || $status == 'needs-action';
if (!$noreply) {
// let the reply clause further down send the iTip message
$rec['_reportpartstat'] = $status;
}
}
break;
}
if ($success) {
@ -354,6 +370,9 @@ class tasklist extends rcube_plugin
$sender = $task['attendees'][$idx];
$status = strtolower($sender['status']);
if (!empty($_POST['comment']))
$task['comment'] = get_input_value('comment', RCUBE_INPUT_POST);
$itip = $this->load_itip();
$itip->set_sender_email($sender['email']);
@ -1862,4 +1881,25 @@ class tasklist extends rcube_plugin
$this->load_driver();
return $this->driver->user_delete($args);
}
/**
* Magic getter for public access to protected members
*/
public function __get($name)
{
switch ($name) {
case 'ical':
return $this->get_ical();
case 'itip':
return $this->load_itip();
case 'driver':
$this->load_driver();
return $this->driver;
}
return null;
}
}

View file

@ -129,6 +129,7 @@ class tasklist_ui
$this->plugin->register_handler('plugin.attendees_form', array($this, 'attendees_form'));
$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->include_script('jquery.tagedit.js');
$this->plugin->include_script('tasklist.js');