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 @@
+
+ + + + +
Default diff --git a/plugins/calendar/skins/larry/calendar.css b/plugins/calendar/skins/larry/calendar.css index 72915094..affd199f 100644 --- a/plugins/calendar/skins/larry/calendar.css +++ b/plugins/calendar/skins/larry/calendar.css @@ -705,6 +705,26 @@ a.miniColors-trigger { margin-bottom: 0.3em; } +#eventshow div.event-line a.iconbutton { + margin-left: 0.5em; + line-height: 17px; +} + +#event-partstat .changersvp { + cursor: pointer; + color: #333; + text-decoration: none; +} + +#event-partstat .iconbutton { + visibility: hidden; +} + +#event-partstat .changersvp:focus .iconbutton, +#event-partstat:hover .iconbutton { + visibility: visible; +} + #eventedit { position: relative; top: -1.5em; @@ -1832,6 +1852,7 @@ div.calendar-invitebox .rsvp-status.hint { font-style: italic; } +#event-partstat .changersvp, div.calendar-invitebox .rsvp-status.declined, div.calendar-invitebox .rsvp-status.tentative, div.calendar-invitebox .rsvp-status.accepted, @@ -1841,18 +1862,22 @@ div.calendar-invitebox .rsvp-status.needs-action { background: url(images/attendee-status.png) 2px -20px no-repeat; } +#event-partstat .changersvp.declined, div.calendar-invitebox .rsvp-status.declined { background-position: 2px -40px; } +#event-partstat .changersvp.tentative, div.calendar-invitebox .rsvp-status.tentative { background-position: 2px -60px; } +#event-partstat .changersvp.delegated, div.calendar-invitebox .rsvp-status.delegated { background-position: 2px -180px; } +#event-partstat .changersvp.needs-action, div.calendar-invitebox .rsvp-status.needs-action { background-position: 2px 0; } diff --git a/plugins/calendar/skins/larry/templates/calendar.html b/plugins/calendar/skins/larry/templates/calendar.html index d6081573..0b8350c4 100644 --- a/plugins/calendar/skins/larry/templates/calendar.html +++ b/plugins/calendar/skins/larry/templates/calendar.html @@ -101,6 +101,13 @@
+
+ + + + + +
Default