')
.addClass(String(data.role).toLowerCase())
@@ -1372,6 +1397,24 @@ function rcube_calendar_ui(settings)
event_attendees = $.grep(event_attendees, function(data){ return (data.name != id && data.email != id) });
};
+ // when the user accepts or declines an event invitation
+ var event_rsvp = function(response)
+ {
+ if (me.selected_event && me.selected_event.attendees && response) {
+ // update attendee status
+ for (var data, i=0; i < me.selected_event.attendees.length; i++) {
+ data = me.selected_event.attendees[i];
+ if (settings.identity.emails.indexOf(';'+data.email) >= 0)
+ data.status = response.toUpperCase();
+ }
+ event_show_dialog(me.selected_event);
+
+ // submit status change to server
+ me.saving_lock = rcmail.set_busy(true, 'calendar.savingdata');
+ rcmail.http_post('event', { action:'rsvp', e:me.selected_event, status:response });
+ }
+ }
+
// post the given event data to server
var update_event = function(action, data)
{
@@ -1413,14 +1456,20 @@ function rcube_calendar_ui(settings)
var update_event_confirm = function(action, event, data)
{
if (!data) data = event;
- var html = '';
+ var notify = false, html = '';
// event has attendees, ask whether to notify them
if (has_attendees(event)) {
- html += '' +
- '
';
+ if (is_organizer(event)) {
+ notify = true;
+ html += '' +
+ '
';
+ }
+ else {
+ html += '' + rcmail.gettext('localchangeswarning', 'calendar') + '
';
+ }
}
// recurring event: user needs to select the savemode
@@ -1442,7 +1491,7 @@ function rcube_calendar_ui(settings)
$dialog.find('a.button').button().click(function(e){
data.savemode = String(this.href).replace(/.+#/, '');
if ($dialog.find('input.confirm-attendees-donotify').get(0))
- data.notify = $dialog.find('input.confirm-attendees-donotify').get(0).checked ? 1 : 0;
+ data.notify = notify && $dialog.find('input.confirm-attendees-donotify').get(0).checked ? 1 : 0;
update_event(action, data);
$dialog.dialog("destroy").hide();
return false;
@@ -1459,7 +1508,7 @@ function rcube_calendar_ui(settings)
buttons.push({
text: rcmail.gettext((action == 'remove' ? 'remove' : 'save'), 'calendar'),
click: function() {
- data.notify = $dialog.find('input.confirm-attendees-donotify').get(0).checked ? 1 : 0;
+ data.notify = notify && $dialog.find('input.confirm-attendees-donotify').get(0).checked ? 1 : 0;
update_event(action, data);
$(this).dialog("close");
}
@@ -1814,6 +1863,9 @@ function rcube_calendar_ui(settings)
if (settings.default_calendar && this.calendars[settings.default_calendar] && !this.calendars[settings.default_calendar].readonly)
this.selected_calendar = settings.default_calendar;
+ var viewdate = new Date();
+ if (rcmail.env.date)
+ viewdate.setTime(fromunixtime(rcmail.env.date));
// initalize the fullCalendar plugin
var fc = $('#calendar').fullCalendar({
@@ -1823,6 +1875,9 @@ function rcube_calendar_ui(settings)
right: 'agendaDay,agendaWeek,month,table'
},
aspectRatio: 1,
+ date: viewdate.getDate(),
+ month: viewdate.getMonth(),
+ year: viewdate.getFullYear(),
ignoreTimezone: true, // will treat the given date strings as in local (browser's) timezone
height: $('#main').height(),
eventSources: event_sources,
@@ -1856,7 +1911,7 @@ function rcube_calendar_ui(settings)
listPage: 1, // advance one day in agenda view
listRange: settings['agenda_range'],
tableCols: ['handle', 'date', 'time', 'title', 'location'],
- defaultView: settings['default_view'],
+ defaultView: rcmail.env.view || settings['default_view'],
allDayText: rcmail.gettext('all-day', 'calendar'),
buttonText: {
prev: (bw.ie6 ? ' << ' : ' ◄ '),
@@ -2104,7 +2159,7 @@ function rcube_calendar_ui(settings)
update_freebusy_status(me.selected_event);
// add current user as organizer if non added yet
if (!event_attendees.length)
- add_attendee($.extend({ role:'ORGANIZER' }, settings.event_owner));
+ add_attendee($.extend({ role:'ORGANIZER' }, settings.identity));
}
}
});
@@ -2198,6 +2253,10 @@ function rcube_calendar_ui(settings)
if (this.checked)
$('').appendTo('head');
});
+
+ $('#event-rsvp input.button').click(function(){
+ event_rsvp($(this).attr('rel'))
+ })
// hide event dialog when clicking somewhere into document
$(document).bind('mousedown', dialog_check);
diff --git a/plugins/calendar/drivers/calendar_driver.php b/plugins/calendar/drivers/calendar_driver.php
index b1cd580c..77501fd3 100644
--- a/plugins/calendar/drivers/calendar_driver.php
+++ b/plugins/calendar/drivers/calendar_driver.php
@@ -61,10 +61,11 @@
* 'id' => 'Attachment identifier'
* ),
* 'deleted_attachments' => array(), // array of attachment identifiers to delete when event is updated
+ * 'organizer' => array('name' => 'Organizer name', 'email' => ''),
* 'attendees' => array( // List of event participants
* 'name' => 'Participant name',
* 'email' => 'Participant e-mail address', // used as identifier
- * 'role' => 'ORGANIZER|REQ-PARTICIPANT|OPT-PARTICIPANT|CHAIR',
+ * 'role' => 'REQ-PARTICIPANT|OPT-PARTICIPANT|CHAIR',
* 'status' => 'NEEDS-ACTION|UNKNOWN|ACCEPTED|TENTATIVE|DECLINED'
* 'rsvp' => true|false,
* ),
diff --git a/plugins/calendar/lib/calendar_ical.php b/plugins/calendar/lib/calendar_ical.php
index e31d4ae3..372958d7 100644
--- a/plugins/calendar/lib/calendar_ical.php
+++ b/plugins/calendar/lib/calendar_ical.php
@@ -181,6 +181,10 @@ class calendar_ical
$event['recurrence_id'] = $this->_date2time($attr['value']);
break;
+ case 'SEQUENCE':
+ $event['sequence'] = intval($attr['value']);
+ break;
+
case 'DESCRIPTION':
case 'LOCATION':
$event[strtolower($attr['name'])] = $attr['value'];
diff --git a/plugins/calendar/lib/calendar_ui.php b/plugins/calendar/lib/calendar_ui.php
index 25c48daa..c0015f45 100644
--- a/plugins/calendar/lib/calendar_ui.php
+++ b/plugins/calendar/lib/calendar_ui.php
@@ -627,5 +627,22 @@ class calendar_ui
return $table->show($attrib);
}
+
+
+ function event_rsvp_buttons($attrib = array())
+ {
+ foreach (array('accepted','tentative','declined') as $method) {
+ $buttons .= html::tag('input', array(
+ 'type' => 'button',
+ 'class' => 'button',
+ 'rel' => $method,
+ 'value' => $this->calendar->gettext('itip' . $method),
+ ));
+ }
+
+ return html::div($attrib,
+ html::div('label', $this->calendar->gettext('acceptinvitation')) .
+ html::div('rsvp-buttons', $buttons));
+ }
}
diff --git a/plugins/calendar/localization/en_US.inc b/plugins/calendar/localization/en_US.inc
index 26f7949c..c31fb6b0 100644
--- a/plugins/calendar/localization/en_US.inc
+++ b/plugins/calendar/localization/en_US.inc
@@ -122,9 +122,22 @@ $labels['eventcancelsubject'] = '"$title" has been canceled';
$labels['eventcancelmailbody'] = "*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees\n\nThe event has been cancelled by \$organizer.\n\nPlease find attached an iCalendar file with the updated event details.";
// invitation handling
-$labels['itipreply'] = 'Reply to ';
+$labels['itipinvitation'] = 'Invitation to';
+$labels['itipupdate'] = 'Update of';
+$labels['itipcancellation'] = 'Cancelled:';
+$labels['itipreply'] = 'Reply to';
+$labels['itipaccepted'] = 'Accept';
+$labels['itiptentative'] = 'Maybe';
+$labels['itipdeclined'] = 'Decline';
+$labels['itipsubjectaccepted'] = '"$title" has been accepted by $name';
+$labels['itipsubjecttentative'] = '"$title" has been tentatively accepted by $name';
+$labels['itipsubjectdeclined'] = '"$title" has been declined by $name';
+$labels['itipmailbodyaccepted'] = "\$sender has accepted the invitation to the following event:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees";
+$labels['itipmailbodytentative'] = "\$sender has tentatively accepted the invitation to the following event:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees";
+$labels['itipmailbodydeclined'] = "\$sender has declined the invitation to the following event:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees";
$labels['importtocalendar'] = 'Save to my calendar';
$labels['updateattendeestatus'] = 'Update the participant\'s status';
+$labels['acceptinvitation'] = 'Do you accept this invitation?';
// event dialog tabs
$labels['tabsummary'] = 'Summary';
@@ -149,6 +162,9 @@ $labels['newerversionexists'] = 'A newer version of this event already exists! A
$labels['nowritecalendarfound'] = 'No calendar found to save the event';
$labels['importedsuccessfully'] = 'The event was successfully added to \'$calendar\'';
$labels['attendeupdateesuccess'] = 'Successfully updated the participant\'s status';
+$labels['itipresponseerror'] = 'Failed to send the response to this event invitation';
+$labels['sentresponseto'] = 'Successfully sent invitation response to $mailto';
+$labels['localchangeswarning'] = 'You are about to make changes that will only be reflected on your personal calendar';
// recurrence form
$labels['repeat'] = 'Repeat';
diff --git a/plugins/calendar/skins/default/calendar.css b/plugins/calendar/skins/default/calendar.css
index 3de7a7f8..210936c7 100644
--- a/plugins/calendar/skins/default/calendar.css
+++ b/plugins/calendar/skins/default/calendar.css
@@ -527,6 +527,7 @@ td.topalign {
min-width: 5em;
}
+#event-rsvp,
#edit-attendees-notify {
margin: 0.3em 0;
padding: 0.5em;
@@ -1091,15 +1092,31 @@ fieldset #calendarcategories div {
/* Invitation UI in mail */
-p.calendar-invitebox {
+div.calendar-invitebox {
min-height: 20px;
margin: 5px 8px;
- padding: 6px 6px 6px 34px;
+ padding: 3px 6px 6px 34px;
border: 1px solid #C2D071;
- background: url('images/calendar.png') 6px 3px no-repeat #F7FDCB;
+ background: url('images/calendar.png') 6px 5px no-repeat #F7FDCB;
}
-p.calendar-invitebox input.button {
- margin-left: 1em;
- font-size: 11px;
+div.calendar-invitebox td.ititle {
+ font-weight: bold;
+ padding-right: 0.5em;
+}
+
+div.calendar-invitebox td.label {
+ color: #666;
+ padding-right: 1em;
+}
+
+#event-rsvp .rsvp-buttons,
+div.calendar-invitebox .rsvp-buttons {
+ margin-top: 0.5em;
+}
+
+#event-rsvp input.button,
+div.calendar-invitebox input.button {
+ font-size: 11px;
+ margin-right: 0.5em;
}
diff --git a/plugins/calendar/skins/default/templates/calendar.html b/plugins/calendar/skins/default/templates/calendar.html
index 4dfb01be..87253b72 100644
--- a/plugins/calendar/skins/default/templates/calendar.html
+++ b/plugins/calendar/skins/default/templates/calendar.html
@@ -83,6 +83,8 @@
+
+