summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php4
-rw-r--r--plugins/tasklist/localization/en_US.inc1
-rw-r--r--plugins/tasklist/skins/larry/tasklist.css24
-rw-r--r--plugins/tasklist/skins/larry/templates/mainview.html14
-rw-r--r--plugins/tasklist/tasklist.js41
-rw-r--r--plugins/tasklist/tasklist.php40
-rw-r--r--plugins/tasklist/tasklist_ui.php1
7 files changed, 109 insertions, 16 deletions
diff --git a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
index 6370301..a3e6181 100644
--- a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
+++ b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
@@ -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']++;
}
}
diff --git a/plugins/tasklist/localization/en_US.inc b/plugins/tasklist/localization/en_US.inc
index 99a11b0..3fd045a 100644
--- a/plugins/tasklist/localization/en_US.inc
+++ b/plugins/tasklist/localization/en_US.inc
@@ -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';
diff --git a/plugins/tasklist/skins/larry/tasklist.css b/plugins/tasklist/skins/larry/tasklist.css
index f627136..ff8ba12 100644
--- a/plugins/tasklist/skins/larry/tasklist.css
+++ b/plugins/tasklist/skins/larry/tasklist.css
@@ -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;
diff --git a/plugins/tasklist/skins/larry/templates/mainview.html b/plugins/tasklist/skins/larry/templates/mainview.html
index ad018eb..5f6831f 100644
--- a/plugins/tasklist/skins/larry/templates/mainview.html
+++ b/plugins/tasklist/skins/larry/templates/mainview.html
@@ -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" />
diff --git a/plugins/tasklist/tasklist.js b/plugins/tasklist/tasklist.js
index ffb0129..0a090e8 100644
--- a/plugins/tasklist/tasklist.js
+++ b/plugins/tasklist/tasklist.js
@@ -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));
diff --git a/plugins/tasklist/tasklist.php b/plugins/tasklist/tasklist.php
index 78bb001..6820384 100644
--- a/plugins/tasklist/tasklist.php
+++ b/plugins/tasklist/tasklist.php
@@ -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;
+ }
}
diff --git a/plugins/tasklist/tasklist_ui.php b/plugins/tasklist/tasklist_ui.php
index 21b322e..7d8f513 100644
--- a/plugins/tasklist/tasklist_ui.php
+++ b/plugins/tasklist/tasklist_ui.php
@@ -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');