Add button to iTip RSVP UI in mail view to open the calendar preview with an option to accept/decline the invitation from there (#3161)

This commit is contained in:
Thomas Bruederli 2014-09-10 10:30:40 +02:00
parent 7161b90e46
commit 09cf967ed5
9 changed files with 128 additions and 9 deletions

View file

@ -313,6 +313,9 @@ class calendar extends rcube_plugin
if ($date = get_input_value('date', RCUBE_INPUT_GPC)) if ($date = get_input_value('date', RCUBE_INPUT_GPC))
$this->rc->output->set_env('date', $date); $this->rc->output->set_env('date', $date);
if ($msgref = get_input_value('itip', RCUBE_INPUT_GPC))
$this->rc->output->set_env('itip_events', $this->itip_events($msgref));
$this->rc->output->send("calendar.calendar"); $this->rc->output->send("calendar.calendar");
} }
@ -1122,6 +1125,43 @@ class calendar extends rcube_plugin
exit; exit;
} }
/**
* Load event data from an iTip message attachment
*/
public function itip_events($msgref)
{
$path = explode('/', $msgref);
$msg = array_pop($path);
$mbox = join('/', $path);
list($uid, $mime_id) = explode('#', $msg);
$events = array();
if ($event = $this->lib->mail_get_itip_object($mbox, $uid, $mime_id, 'event')) {
$partstat = 'NEEDS-ACTION';
/*
$user_emails = $this->lib->get_user_emails();
foreach ($event['attendees'] as $attendee) {
if (in_array($attendee['email'], $user_emails)) {
$partstat = $attendee['status'];
break;
}
}
*/
$event['id'] = $event['uid'];
$event['temporary'] = true;
$event['readonly'] = true;
$event['calendar'] = '--invitation--itip';
$event['className'] = 'fc-invitation-' . strtolower($partstat);
$event['_mbox'] = $mbox;
$event['_uid'] = $uid;
$event['_part'] = $mime_id;
$events[] = $this->_client_event($event, true);
}
return $events;
}
/** /**
* Handler for keep-alive requests * Handler for keep-alive requests
* This will check for updated data in active calendars and sync them to the client * This will check for updated data in active calendars and sync them to the client
@ -2357,7 +2397,8 @@ class calendar extends rcube_plugin
$ical_objects->method, $ical_objects->method,
$ical_objects->mime_id . ':' . $idx, $ical_objects->mime_id . ':' . $idx,
'calendar', 'calendar',
rcube_utils::anytodatetime($ical_objects->message_date) rcube_utils::anytodatetime($ical_objects->message_date),
$this->rc->url(array('task' => 'calendar')) . '&view=agendaDay&date=' . $event['start']->format('U')
) )
); );
} }
@ -2566,6 +2607,7 @@ class calendar extends rcube_plugin
} }
if ($success || $dontsave) { if ($success || $dontsave) {
$metadata['calendar'] = $event['calendar'];
$metadata['nosave'] = $dontsave; $metadata['nosave'] = $dontsave;
$metadata['rsvp'] = intval($metadata['rsvp']); $metadata['rsvp'] = intval($metadata['rsvp']);
$metadata['after_action'] = $this->rc->config->get('calendar_itip_after_action', $this->defaults['calendar_itip_after_action']); $metadata['after_action'] = $this->rc->config->get('calendar_itip_after_action', $this->defaults['calendar_itip_after_action']);

View file

@ -599,7 +599,7 @@ function rcube_calendar_ui(settings)
me.dialog_resize($dialog.get(0), $dialog.height(), 420); me.dialog_resize($dialog.get(0), $dialog.height(), 420);
// add link for "more options" drop-down // add link for "more options" drop-down
if (!temp) { if (!temp && !event.temporary) {
$('<a>') $('<a>')
.attr('href', '#') .attr('href', '#')
.html(rcmail.gettext('eventoptions','calendar')) .html(rcmail.gettext('eventoptions','calendar'))
@ -2339,7 +2339,19 @@ function rcube_calendar_ui(settings)
var submit_data = $.extend({}, me.selected_event, { source:null, comment:$('#reply-comment-event-rsvp').val() }), var submit_data = $.extend({}, me.selected_event, { source:null, comment:$('#reply-comment-event-rsvp').val() }),
noreply = $('#noreply-event-rsvp:checked').length ? 1 : 0; noreply = $('#noreply-event-rsvp:checked').length ? 1 : 0;
if (settings.invitation_calendars) { // import event from mail (temporary iTip event)
if (submit_data._mbox && submit_data._uid) {
me.saving_lock = rcmail.set_busy(true, 'calendar.savingdata');
rcmail.http_post('mailimportitip', {
_mbox: submit_data._mbox,
_uid: submit_data._uid,
_part: submit_data._part,
_status: response,
_noreply: noreply,
_comment: submit_data.comment
});
}
else if (settings.invitation_calendars) {
update_event('rsvp', submit_data, { status:response, noreply:noreply }); update_event('rsvp', submit_data, { status:response, noreply:noreply });
} }
else { else {
@ -3089,6 +3101,25 @@ function rcube_calendar_ui(settings)
return query; return query;
}; };
// callback after an iTip message event was imported
this.itip_message_processed = function(data)
{
// remove temporary iTip source
fc.fullCalendar('removeEventSource', this.calendars['--invitation--itip']);
$('#eventshow:ui-dialog').dialog('close');
this.selected_event = null;
// refresh destination calendar source
this.refresh({ source:data.calendar, refetch:true });
this.unlock_saving();
// process 'after_action' in mail task
if (window.opener && window.opener.rcube_libcalendaring)
window.opener.rcube_libcalendaring.itip_message_processed(data);
};
// reload the calendar view by keeping the current date/view selection // reload the calendar view by keeping the current date/view selection
this.reload_view = function() this.reload_view = function()
{ {
@ -3463,6 +3494,19 @@ function rcube_calendar_ui(settings)
if (rcmail.env.date) if (rcmail.env.date)
viewdate.setTime(fromunixtime(rcmail.env.date)); viewdate.setTime(fromunixtime(rcmail.env.date));
// add source with iTip event data for rendering
if (rcmail.env.itip_events && rcmail.env.itip_events.length) {
me.calendars['--invitation--itip'] = {
events: rcmail.env.itip_events,
className: 'fc-event-cal---invitation--itip',
color: '#fff',
textColor: '#333',
editable: false,
attendees: true
};
event_sources.push(me.calendars['--invitation--itip']);
}
// initalize the fullCalendar plugin // initalize the fullCalendar plugin
var fc = $('#calendar').fullCalendar($.extend({}, fullcalendar_defaults, { var fc = $('#calendar').fullCalendar($.extend({}, fullcalendar_defaults, {
header: { header: {
@ -3940,6 +3984,7 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
rcmail.addEventListener('plugin.render_event_changelog', function(data){ cal.render_event_changelog(data); }); rcmail.addEventListener('plugin.render_event_changelog', function(data){ cal.render_event_changelog(data); });
rcmail.addEventListener('plugin.event_show_diff', function(data){ cal.event_show_diff(data); }); rcmail.addEventListener('plugin.event_show_diff', function(data){ cal.event_show_diff(data); });
rcmail.addEventListener('plugin.event_show_revision', function(data){ cal.event_show_dialog(data, null, true); }); rcmail.addEventListener('plugin.event_show_revision', function(data){ cal.event_show_dialog(data, null, true); });
rcmail.addEventListener('plugin.itip_message_processed', function(data){ cal.itip_message_processed(data); });
rcmail.addEventListener('requestrefresh', function(q){ return cal.before_refresh(q); }); rcmail.addEventListener('requestrefresh', function(q){ return cal.before_refresh(q); });
// let's go // let's go

View file

@ -201,6 +201,7 @@ $labels['eventcancelled'] = 'The event has been cancelled';
$labels['saveincalendar'] = 'save in'; $labels['saveincalendar'] = 'save in';
$labels['updatemycopy'] = 'Update in my calendar'; $labels['updatemycopy'] = 'Update in my calendar';
$labels['savetocalendar'] = 'Save to calendar'; $labels['savetocalendar'] = 'Save to calendar';
$labels['openpreview'] = 'Check Calendar';
// resources // resources
$labels['resource'] = 'Resource'; $labels['resource'] = 'Resource';

View file

@ -6,7 +6,7 @@
<script type="text/javascript" src="/functions.js"></script> <script type="text/javascript" src="/functions.js"></script>
<!--[if lte IE 7]><link rel="stylesheet" type="text/css" href="./plugins/calendar/skins/classic/iehacks.css" /><![endif]--> <!--[if lte IE 7]><link rel="stylesheet" type="text/css" href="./plugins/calendar/skins/classic/iehacks.css" /><![endif]-->
</head> </head>
<body class="calendarmain"> <roundcube:if condition="env:extwin" /><body class="calendarmain extwin"><roundcube:else /><body class="calendarmain"><roundcube:endif />
<roundcube:include file="/includes/taskbar.html" /> <roundcube:include file="/includes/taskbar.html" />
<roundcube:include file="/includes/header.html" /> <roundcube:include file="/includes/header.html" />

View file

@ -1,7 +1,7 @@
/** /**
* Roundcube Calendar plugin styles for skin "Larry" * Roundcube Calendar plugin styles for skin "Larry"
* *
* Copyright (c) 2012, Kolab Systems AG <contact@kolabsys.com> * Copyright (c) 2012-2014, Kolab Systems AG <contact@kolabsys.com>
* Screendesign by FLINT / Büro für Gestaltung, bueroflint.com * Screendesign by FLINT / Büro für Gestaltung, bueroflint.com
* *
* The contents are subject to the Creative Commons Attribution-ShareAlike * The contents are subject to the Creative Commons Attribution-ShareAlike
@ -2016,9 +2016,15 @@ div.calendar-invitebox input.button {
margin-right: 0.5em; margin-right: 0.5em;
} }
div.calendar-invitebox input.button.preview {
margin-left: 1em;
margin-right: 0;
}
div.calendar-invitebox .folder-select { div.calendar-invitebox .folder-select {
font-weight: 10px; font-weight: 10px;
margin-left: 1em; margin-left: 1em;
white-space: nowrap;
} }
div.calendar-invitebox .rsvp-status { div.calendar-invitebox .rsvp-status {

View file

@ -5,7 +5,7 @@
<roundcube:include file="/includes/links.html" /> <roundcube:include file="/includes/links.html" />
<!--[if lte IE 7]><link rel="stylesheet" type="text/css" href="/this/iehacks.css" /><![endif]--> <!--[if lte IE 7]><link rel="stylesheet" type="text/css" href="/this/iehacks.css" /><![endif]-->
</head> </head>
<body class="calendarmain"> <roundcube:if condition="env:extwin" /><body class="calendarmain extwin"><roundcube:else /><body class="calendarmain"><roundcube:endif />
<roundcube:include file="/includes/header.html" /> <roundcube:include file="/includes/header.html" />

View file

@ -361,6 +361,7 @@ class libcalendaring_itip
return array( return array(
'uid' => $event['uid'], 'uid' => $event['uid'],
'id' => asciiwords($event['uid'], true), 'id' => asciiwords($event['uid'], true),
'existing' => $existing ? true : false,
'saved' => $existing ? true : false, 'saved' => $existing ? true : false,
'latest' => $latest, 'latest' => $latest,
'status' => $status, 'status' => $status,
@ -372,7 +373,7 @@ class libcalendaring_itip
/** /**
* Build inline UI elements for iTip messages * Build inline UI elements for iTip messages
*/ */
public function mail_itip_inline_ui($event, $method, $mime_id, $task, $message_date = null) public function mail_itip_inline_ui($event, $method, $mime_id, $task, $message_date = null, $preview_url = null)
{ {
$buttons = array(); $buttons = array();
$dom_id = asciiwords($event['uid'], true); $dom_id = asciiwords($event['uid'], true);
@ -450,6 +451,17 @@ class libcalendaring_itip
)); ));
} }
// add button to open calendar/preview
if (!empty($preview_url)) {
$msgref = $this->lib->ical_message->folder . '/' . $this->lib->ical_message->uid . '#' . $mime_id;
$rsvp_buttons .= html::tag('input', array(
'type' => 'button',
'class' => "button preview",
'onclick' => "rcube_libcalendaring.open_itip_preview('" . JQ($preview_url) . "', '" . JQ($msgref) . "')",
'value' => $this->gettext('openpreview'),
));
}
// 2. update the local copy with minor changes // 2. update the local copy with minor changes
$update_button = html::tag('input', array( $update_button = html::tag('input', array(
'type' => 'button', 'type' => 'button',

View file

@ -892,6 +892,7 @@ rcube_libcalendaring.fetch_itip_object_status = function(p)
rcube_libcalendaring.update_itip_object_status = function(p) rcube_libcalendaring.update_itip_object_status = function(p)
{ {
rcmail.env.rsvp_saved = p.saved; rcmail.env.rsvp_saved = p.saved;
rcmail.env.itip_existing = p.existing;
// hide all elements first // hide all elements first
$('#itip-buttons-'+p.id+' > div').hide(); $('#itip-buttons-'+p.id+' > div').hide();
@ -953,6 +954,17 @@ rcube_libcalendaring.itip_after_action = function(action)
} }
}; };
/**
* Open the calendar preview for the current iTip event
*/
rcube_libcalendaring.open_itip_preview = function(url, msgref)
{
if (!rcmail.env.itip_existing)
url += '&itip=' + escape(msgref);
var win = rcmail.open_window(url);
};
// extend jQuery // extend jQuery
(function($){ (function($){

View file

@ -134,6 +134,7 @@ $labels['outdatedinvitation'] = 'This invitation has been replaced by a newer ve
$labels['importtocalendar'] = 'Save to my calendar'; $labels['importtocalendar'] = 'Save to my calendar';
$labels['removefromcalendar'] = 'Remove from my calendar'; $labels['removefromcalendar'] = 'Remove from my calendar';
$labels['updatemycopy'] = 'Update my copy'; $labels['updatemycopy'] = 'Update my copy';
$labels['openpreview'] = 'Open Preview';
$labels['deleteobjectconfirm'] = 'Do you really want to delete this object?'; $labels['deleteobjectconfirm'] = 'Do you really want to delete this object?';
$labels['declinedeleteconfirm'] = 'Do you also want to delete this declined object from your account?'; $labels['declinedeleteconfirm'] = 'Do you also want to delete this declined object from your account?';