diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php index afcc0526..9c0a8929 100644 --- a/plugins/calendar/calendar.php +++ b/plugins/calendar/calendar.php @@ -309,10 +309,13 @@ class calendar extends rcube_plugin $view = get_input_value('view', RCUBE_INPUT_GPC); if (in_array($view, array('agendaWeek', 'agendaDay', 'month', 'table'))) $this->rc->output->set_env('view', $view); - + if ($date = get_input_value('date', RCUBE_INPUT_GPC)) $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"); } @@ -1122,6 +1125,43 @@ class calendar extends rcube_plugin 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 * 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->mime_id . ':' . $idx, '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) { + $metadata['calendar'] = $event['calendar']; $metadata['nosave'] = $dontsave; $metadata['rsvp'] = intval($metadata['rsvp']); $metadata['after_action'] = $this->rc->config->get('calendar_itip_after_action', $this->defaults['calendar_itip_after_action']); diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js index 558a0145..ef409380 100644 --- a/plugins/calendar/calendar_ui.js +++ b/plugins/calendar/calendar_ui.js @@ -599,7 +599,7 @@ function rcube_calendar_ui(settings) me.dialog_resize($dialog.get(0), $dialog.height(), 420); // add link for "more options" drop-down - if (!temp) { + if (!temp && !event.temporary) { $('') .attr('href', '#') .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() }), 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 }); } else { @@ -3089,6 +3101,25 @@ function rcube_calendar_ui(settings) 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 this.reload_view = function() { @@ -3462,7 +3493,20 @@ function rcube_calendar_ui(settings) var viewdate = new Date(); if (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 var fc = $('#calendar').fullCalendar($.extend({}, fullcalendar_defaults, { 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.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.itip_message_processed', function(data){ cal.itip_message_processed(data); }); rcmail.addEventListener('requestrefresh', function(q){ return cal.before_refresh(q); }); // let's go diff --git a/plugins/calendar/localization/en_US.inc b/plugins/calendar/localization/en_US.inc index e52f62ac..6023366e 100644 --- a/plugins/calendar/localization/en_US.inc +++ b/plugins/calendar/localization/en_US.inc @@ -201,6 +201,7 @@ $labels['eventcancelled'] = 'The event has been cancelled'; $labels['saveincalendar'] = 'save in'; $labels['updatemycopy'] = 'Update in my calendar'; $labels['savetocalendar'] = 'Save to calendar'; +$labels['openpreview'] = 'Check Calendar'; // resources $labels['resource'] = 'Resource'; diff --git a/plugins/calendar/skins/classic/templates/calendar.html b/plugins/calendar/skins/classic/templates/calendar.html index 516cf589..5f006d2f 100644 --- a/plugins/calendar/skins/classic/templates/calendar.html +++ b/plugins/calendar/skins/classic/templates/calendar.html @@ -6,7 +6,7 @@ - + diff --git a/plugins/calendar/skins/larry/calendar.css b/plugins/calendar/skins/larry/calendar.css index ca439ff7..5e8c09de 100644 --- a/plugins/calendar/skins/larry/calendar.css +++ b/plugins/calendar/skins/larry/calendar.css @@ -1,7 +1,7 @@ /** * Roundcube Calendar plugin styles for skin "Larry" * - * Copyright (c) 2012, Kolab Systems AG + * Copyright (c) 2012-2014, Kolab Systems AG * Screendesign by FLINT / Büro für Gestaltung, bueroflint.com * * The contents are subject to the Creative Commons Attribution-ShareAlike @@ -2016,9 +2016,15 @@ div.calendar-invitebox input.button { margin-right: 0.5em; } +div.calendar-invitebox input.button.preview { + margin-left: 1em; + margin-right: 0; +} + div.calendar-invitebox .folder-select { font-weight: 10px; margin-left: 1em; + white-space: nowrap; } div.calendar-invitebox .rsvp-status { diff --git a/plugins/calendar/skins/larry/templates/calendar.html b/plugins/calendar/skins/larry/templates/calendar.html index c607c876..1df1748d 100644 --- a/plugins/calendar/skins/larry/templates/calendar.html +++ b/plugins/calendar/skins/larry/templates/calendar.html @@ -5,7 +5,7 @@ - + diff --git a/plugins/libcalendaring/lib/libcalendaring_itip.php b/plugins/libcalendaring/lib/libcalendaring_itip.php index ce686557..a5b056f7 100644 --- a/plugins/libcalendaring/lib/libcalendaring_itip.php +++ b/plugins/libcalendaring/lib/libcalendaring_itip.php @@ -361,6 +361,7 @@ class libcalendaring_itip return array( 'uid' => $event['uid'], 'id' => asciiwords($event['uid'], true), + 'existing' => $existing ? true : false, 'saved' => $existing ? true : false, 'latest' => $latest, 'status' => $status, @@ -372,7 +373,7 @@ class libcalendaring_itip /** * 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(); $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 $update_button = html::tag('input', array( 'type' => 'button', diff --git a/plugins/libcalendaring/libcalendaring.js b/plugins/libcalendaring/libcalendaring.js index cd06827a..b23a3fee 100644 --- a/plugins/libcalendaring/libcalendaring.js +++ b/plugins/libcalendaring/libcalendaring.js @@ -892,6 +892,7 @@ rcube_libcalendaring.fetch_itip_object_status = function(p) rcube_libcalendaring.update_itip_object_status = function(p) { rcmail.env.rsvp_saved = p.saved; + rcmail.env.itip_existing = p.existing; // hide all elements first $('#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 (function($){ diff --git a/plugins/libcalendaring/localization/en_US.inc b/plugins/libcalendaring/localization/en_US.inc index 82fb7a8d..9c3507cc 100644 --- a/plugins/libcalendaring/localization/en_US.inc +++ b/plugins/libcalendaring/localization/en_US.inc @@ -134,6 +134,7 @@ $labels['outdatedinvitation'] = 'This invitation has been replaced by a newer ve $labels['importtocalendar'] = 'Save to my calendar'; $labels['removefromcalendar'] = 'Remove from my calendar'; $labels['updatemycopy'] = 'Update my copy'; +$labels['openpreview'] = 'Open Preview'; $labels['deleteobjectconfirm'] = 'Do you really want to delete this object?'; $labels['declinedeleteconfirm'] = 'Do you also want to delete this declined object from your account?';