diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php index 0c2708d5..ef989679 100644 --- a/plugins/calendar/calendar.php +++ b/plugins/calendar/calendar.php @@ -293,6 +293,7 @@ class calendar extends rcube_plugin $this->ui->init_templates(); $this->rc->output->add_label('lowest','low','normal','high','highest','delete','cancel','uploading','noemailwarning','close'); + $this->rc->output->add_label('libcalendaring.itipaccepted','libcalendaring.itiptentative','libcalendaring.itipdeclined','libcalendaring.itipdelegated'); // initialize attendees autocompletion rcube_autocomplete_init(); diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js index ff741656..44f84798 100644 --- a/plugins/calendar/calendar_ui.js +++ b/plugins/calendar/calendar_ui.js @@ -451,7 +451,7 @@ function rcube_calendar_ui(settings) return (j - k); }); - var data, dispname, tooltip, organizer = false, rsvp = false, line, morelink, html = '',overflow = ''; + var data, dispname, tooltip, organizer = false, rsvp = false, mystatus = null, line, morelink, html = '',overflow = ''; for (var j=0; j < event.attendees.length; j++) { data = event.attendees[j]; dispname = Q(data.name || data.email); @@ -461,8 +461,11 @@ function rcube_calendar_ui(settings) dispname = '' + dispname + ''; if (data.role == 'ORGANIZER') organizer = true; - else if ((data.status == 'NEEDS-ACTION' || data.status == 'TENTATIVE' || data.rsvp) && settings.identity.emails.indexOf(';'+data.email) >= 0) - rsvp = data.status.toLowerCase(); + else if (settings.identity.emails.indexOf(';'+data.email) >= 0) { + mystatus = data.status.toLowerCase(); + if (data.status == 'NEEDS-ACTION' || data.status == 'TENTATIVE' || data.rsvp) + rsvp = mystatus; + } } if (data['delegated-to']) @@ -502,9 +505,17 @@ function rcube_calendar_ui(settings) }) } } - + + if (mystatus && !rsvp) { + $('#event-partstat').show().children('.changersvp') + .removeClass('accepted tentative declined delegated needs-action') + .addClass(mystatus) + .children('.event-text') + .html(Q(rcmail.gettext('itip' + mystatus, 'libcalendaring'))); + } + $('#event-rsvp')[(rsvp && !is_organizer(event) && event.status != 'CANCELLED' ? 'show' : 'hide')](); - $('#event-rsvp .rsvp-buttons input').prop('disabled', false).filter('input[rel='+rsvp+']').prop('disabled', true); + $('#event-rsvp .rsvp-buttons input').prop('disabled', false).filter('input[rel='+mystatus+']').prop('disabled', true); $('#event-rsvp a.reply-comment-toggle').show(); $('#event-rsvp .itip-reply-comment textarea').hide().val(''); @@ -3416,10 +3427,18 @@ function rcube_calendar_ui(settings) $('').appendTo('head'); }); - $('#event-rsvp input.button').click(function(){ + $('#event-rsvp input.button').click(function(e) { event_rsvp($(this).attr('rel')) }); + $('#eventshow .changersvp').click(function(e) { + var d = $('#eventshow'), + h = $('#event-rsvp').show().height(); + h -= $(this).closest('.event-line').toggle().height(); + me.dialog_resize(d.get(0), d.height() + h, d.outerWidth() - 50); + return false; + }) + $('#agenda-listrange').change(function(e){ settings['agenda_range'] = parseInt($(this).val()); fc.fullCalendar('option', 'listRange', settings['agenda_range']).fullCalendar('render'); diff --git a/plugins/calendar/localization/en_US.inc b/plugins/calendar/localization/en_US.inc index 8f4bff6e..8b3f4165 100644 --- a/plugins/calendar/localization/en_US.inc +++ b/plugins/calendar/localization/en_US.inc @@ -63,6 +63,7 @@ $labels['free'] = 'Free'; $labels['busy'] = 'Busy'; $labels['outofoffice'] = 'Out of Office'; $labels['tentative'] = 'Tentative'; +$labels['mystatus'] = 'My status'; $labels['status'] = 'Status'; $labels['confirmed'] = 'Confirmed'; $labels['cancelled'] = 'Cancelled'; @@ -97,6 +98,7 @@ $labels['nrcalendarsfound'] = '$nr calendars found'; $labels['quickview'] = 'View only this calendar'; $labels['invitationspending'] = 'Pending invitations'; $labels['invitationsdeclined'] = 'Declined invitations'; +$labels['changepartstat'] = 'Change participant status'; // agenda view $labels['listrange'] = 'Range to display:'; diff --git a/plugins/calendar/skins/classic/calendar.css b/plugins/calendar/skins/classic/calendar.css index 5ec806c6..880b3b4f 100644 --- a/plugins/calendar/skins/classic/calendar.css +++ b/plugins/calendar/skins/classic/calendar.css @@ -568,6 +568,41 @@ a.miniColors-trigger { margin-bottom: 0.3em; } +#event-rsvp .itip-reply-controls { + margin-top: 0.5em; +} + +#eventshow .itip-reply-controls label { + font-size: 1em; + color: #333; +} + +#event-partstat .changersvp { + cursor: pointer; + color: #333; + text-decoration: none; +} + +#event-partstat:hover .changersvp { + text-decoration: underline; +} + +#event-partstat .changersvp.accepted { + color: #589b1e; +} + +#event-partstat .changersvp.tentative { + color: #f0bb1d; +} + +#event-partstat .changersvp.declined { + color: #ea0000; +} + +#event-partstat .changersvp.delegated { + color: #018be9; +} + #eventedit { position: relative; padding: 0.5em 0.1em; @@ -1412,6 +1447,21 @@ span.spacer { padding-right: 0.6em; } +.fc-event-vert.fc-invitation-needs-action, +.fc-event-hori.fc-invitation-needs-action { + border: 1px dashed #5757c7 !important; +} + +.fc-event-vert.fc-invitation-tentative, +.fc-event-hori.fc-invitation-tentative { + border: 1px dashed #eb8900 !important; +} + +.fc-event-vert.fc-invitation-declined, +.fc-event-hori.fc-invitation-declined { + border: 1px dashed #c00 !important; +} + .fc-grid .fc-event-time { font-weight: normal !important; padding-right: 0.3em; diff --git a/plugins/calendar/skins/classic/templates/calendar.html b/plugins/calendar/skins/classic/templates/calendar.html index 219fd831..07839f05 100644 --- a/plugins/calendar/skins/classic/templates/calendar.html +++ b/plugins/calendar/skins/classic/templates/calendar.html @@ -81,6 +81,12 @@