Add feature to create events from mails (#403)

This commit is contained in:
Thomas 2011-09-23 14:07:40 +02:00
parent e0951a334f
commit 4d5a7f4307
12 changed files with 327 additions and 134 deletions

View file

@ -135,6 +135,9 @@ class calendar extends rcube_plugin
$this->register_action('randomdata', array($this, 'generate_randomdata'));
$this->register_action('print', array($this,'print_view'));
$this->register_action('mailimportevent', array($this, 'mail_import_event'));
$this->register_action('mailtoevent', array($this, 'mail_message2event'));
$this->register_action('inlineui', array($this, 'get_inline_ui'));
$this->register_action('check-recent', array($this, 'check_recent'));
// remove undo information...
if ($undo = $_SESSION['calendar_event_undo']) {
@ -158,6 +161,19 @@ class calendar extends rcube_plugin
$this->add_hook('message_load', array($this, 'mail_message_load'));
$this->add_hook('template_object_messagebody', array($this, 'mail_messagebody_html'));
}
// add 'Create event' item to message menu
if ($this->api->output->type == 'html') {
$this->api->add_content(html::tag('li', null,
$this->api->output->button(array(
'command' => 'calendar-create-from-mail',
'label' => 'calendar.createfrommail',
'type' => 'link',
'classact' => 'calendarlink active',
'class' => 'calendarlink',
))),
'messagemenu');
}
}
// add hook to display alarms
@ -227,27 +243,7 @@ class calendar extends rcube_plugin
// Add JS files to the page header
$this->ui->addJS();
$this->register_handler('plugin.calendar_css', array($this->ui, 'calendar_css'));
$this->register_handler('plugin.calendar_list', array($this->ui, 'calendar_list'));
$this->register_handler('plugin.calendar_select', array($this->ui, 'calendar_select'));
$this->register_handler('plugin.category_select', array($this->ui, 'category_select'));
$this->register_handler('plugin.freebusy_select', array($this->ui, 'freebusy_select'));
$this->register_handler('plugin.priority_select', array($this->ui, 'priority_select'));
$this->register_handler('plugin.sensitivity_select', array($this->ui, 'sensitivity_select'));
$this->register_handler('plugin.alarm_select', array($this->ui, 'alarm_select'));
$this->register_handler('plugin.snooze_select', array($this->ui, 'snooze_select'));
$this->register_handler('plugin.recurrence_form', array($this->ui, 'recurrence_form'));
$this->register_handler('plugin.attachments_form', array($this->ui, 'attachments_form'));
$this->register_handler('plugin.attachments_list', array($this->ui, 'attachments_list'));
$this->register_handler('plugin.attendees_list', array($this->ui, 'attendees_list'));
$this->register_handler('plugin.attendees_form', array($this->ui, 'attendees_form'));
$this->register_handler('plugin.attendees_freebusy_table', array($this->ui, 'attendees_freebusy_table'));
$this->register_handler('plugin.edit_attendees_notify', array($this->ui, 'edit_attendees_notify'));
$this->register_handler('plugin.edit_recurring_warning', array($this->ui, 'recurring_event_warning'));
$this->register_handler('plugin.event_rsvp_buttons', array($this->ui, 'event_rsvp_buttons'));
$this->register_handler('plugin.angenda_options', array($this->ui, 'angenda_options'));
$this->register_handler('plugin.searchform', array($this->rc->output, 'search_form')); // use generic method from rcube_template
$this->ui->init_templates();
$this->rc->output->add_label('low','normal','high','delete','cancel','uploading','noemailwarning');
// initialize attendees autocompletion
@ -798,6 +794,15 @@ class calendar extends rcube_plugin
}
}
/**
* Handler for check-recent requests which are accidentally sent to calendar taks
*/
function check_recent()
{
// NOP
$this->rc->output->send();
}
/**
* Construct the ics file for exporting events to iCalendar format;
*/
@ -1230,7 +1235,7 @@ class calendar extends rcube_plugin
$calendar = get_input_value('calendar', RCUBE_INPUT_GPC);
$uploadid = get_input_value('_uploadid', RCUBE_INPUT_GPC);
$eventid = $calendar.':'.$event;
$eventid = 'cal:'.$event;
if (!is_array($_SESSION['event_session']) || $_SESSION['event_session']['id'] != $eventid) {
$_SESSION['event_session'] = array();
@ -1442,7 +1447,7 @@ class calendar extends rcube_plugin
*/
private function prepare_event(&$event, $action)
{
$eventid = $event['calendar'].':'.$event['id'];
$eventid = 'cal:'.$event['id'];
$attachments = array();
if (is_array($_SESSION['event_session']) && $_SESSION['event_session']['id'] == $eventid) {
@ -1487,6 +1492,7 @@ class calendar extends rcube_plugin
private function cleanup_event(&$event)
{
// remove temp. attachment files
$eventid = 'cal:'.$event['id'];
if (!empty($_SESSION['event_session']) && ($eventid = $_SESSION['event_session']['id'])) {
$this->rc->plugins->exec_hook('attachments_cleanup', array('group' => $eventid));
unset($_SESSION['event_session']);
@ -1697,6 +1703,29 @@ class calendar extends rcube_plugin
$this->rc->output->send("calendar.print");
}
/**
*
*/
public function get_inline_ui()
{
foreach (array('save','cancel','savingdata') as $label)
$texts['calendar.'.$label] = $this->gettext($label);
$texts['calendar.new_event'] = $this->gettext('createfrommail');
$this->ui->init_templates();
$this->ui->calendar_list(); # set env['calendars']
echo $this->api->output->parse('calendar.eventedit', false, false);
echo html::tag('script', array('type' => 'text/javascript'),
"rcmail.set_env('calendars', " . json_encode($this->api->output->env['calendars']) . ");\n".
"rcmail.set_env('deleteicon', '" . $this->api->output->env['deleteicon'] . "');\n".
"rcmail.set_env('cancelicon', '" . $this->api->output->env['cancelicon'] . "');\n".
"rcmail.set_env('loadingicon', '" . $this->api->output->env['loadingicon'] . "');\n".
"rcmail.add_label(" . json_encode($texts) . ");\n"
);
exit;
}
/**
* Compare two event objects and return differing properties
*
@ -2078,6 +2107,67 @@ class calendar extends rcube_plugin
}
/**
* Read email message and return contents for a new event based on that message
*/
public function mail_message2event()
{
$uid = get_input_value('_uid', RCUBE_INPUT_POST);
$mbox = get_input_value('_mbox', RCUBE_INPUT_POST);
$event = array();
// establish imap connection
$this->rc->imap_connect();
$this->rc->imap->set_mailbox($mbox);
$message = new rcube_message($uid);
if ($message->headers) {
$event['title'] = trim($message->subject);
$event['description'] = trim($message->first_text_part());
// copy mail attachments to event
if ($message->attachments) {
$eventid = 'cal:';
if (!is_array($_SESSION['event_session']) || $_SESSION['event_session']['id'] != $eventid) {
$_SESSION['event_session'] = array();
$_SESSION['event_session']['id'] = $eventid;
$_SESSION['event_session']['attachments'] = array();
}
foreach ((array)$message->attachments as $part) {
$attachment = array(
'data' => $this->rc->imap->get_message_part($uid, $part->mime_id, $part),
'size' => $part->size,
'name' => $part->filename,
'mimetype' => $part->mimetype,
'group' => $eventid,
);
$attachment = $this->rc->plugins->exec_hook('attachment_save', $attachment);
if ($attachment['status'] && !$attachment['abort']) {
$id = $attachment['id'];
// store new attachment in session
unset($attachment['status'], $attachment['abort'], $attachment['data']);
$_SESSION['event_session']['attachments'][$id] = $attachment;
$attachment['id'] = 'rcmfile' . $attachment['id']; # add prefix to consider it 'new'
$event['attachments'][] = $attachment;
}
}
}
$this->rc->output->command('plugin.mail2event_dialog', $event);
}
else {
$this->rc->output->command('display_message', $this->gettext('messageopenerror'), 'error');
}
$this->rc->output->send();
}
/**
* Checks if specified message part is a vcalendar data
*

View file

@ -18,6 +18,8 @@
function rcube_calendar(settings)
{
// member vars
this.ui;
this.ui_loaded = false;
this.settings = settings;
this.alarm_ids = [];
this.alarm_dialog = null;
@ -156,6 +158,49 @@ function rcube_calendar(settings)
this.dismiss_link = null;
};
// create new event from current mail message
this.create_from_mail = function()
{
var uid;
if ((uid = rcmail.get_single_uid())) {
// load calendar UI (scripts and edit dialog template)
if (!this.ui_loaded) {
$.when(
$.getScript('./plugins/calendar/calendar_ui.js'),
$.get(rcmail.url('calendar/inlineui'), function(html){ $(document.body).append(html); }, 'html')
).then(function() {
// register attachments form
rcmail.gui_object('attachmentlist', 'attachmentlist');
// disable attendees feature (autocompletion and stuff is not initialized)
for (var c in rcmail.env.calendars)
rcmail.env.calendars[c].attendees = false;
me.ui_loaded = true;
me.ui = new rcube_calendar_ui(me.settings);
me.create_from_mail(); // start over
});
return;
}
else {
// get message contents for event dialog
var lock = rcmail.set_busy(true, 'loading');
rcmail.http_post('calendar/mailtoevent', {
'_mbox': rcmail.env.mailbox,
'_uid': uid
}, lock);
}
}
};
// callback function triggered from server with contents for the new event
this.mail2event_dialog = function(event)
{
if (event.title) {
this.ui.add_event(event);
rcmail.message_list.blur();
}
};
}
// static methods
@ -222,6 +267,23 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
$('#'+p.action+'-'+p.id).show();
});
// register create-from-mail command to message_commands array
if (rcmail.env.task == 'mail') {
// place link above 'view source'
$('#messagemenu a.calendarlink').parent().insertBefore($('#messagemenu a.sourcelink').parent());
rcmail.register_command('calendar-create-from-mail', function() { cal.create_from_mail() });
rcmail.addEventListener('plugin.mail2event_dialog', function(p){ cal.mail2event_dialog(p) });
rcmail.addEventListener('plugin.unlock_saving', function(p){ rcmail.set_busy(false, null, cal.ui.saving_lock); });
if (rcmail.env.action != 'show') {
rcmail.env.message_commands.push('calendar-create-from-mail');
rcmail.add_element($('<a>'));
}
else
rcmail.enable_command('calendar-create-from-mail', true);
}
}
rcmail.addEventListener('plugin.ping_url', function(p){

View file

@ -724,6 +724,10 @@ function rcube_calendar_ui(settings)
// activate the first tab
$('#eventtabs').tabs('select', 0);
// hack: set task to 'calendar' to make all dialog actions work correctly
var comm_path_before = rcmail.env.comm_path;
rcmail.env.comm_path = comm_path_before.replace(/_task=[a-z]+/, '_task=calendar');
var editform = $("#eventedit");
// open jquery UI dialog
@ -738,6 +742,7 @@ function rcube_calendar_ui(settings)
rcmail.ksearch_blur();
rcmail.ksearch_destroy();
freebusy_data = {};
rcmail.env.comm_path = comm_path_before; // restore comm_path
},
buttons: buttons,
minWidth: 500,
@ -1494,7 +1499,7 @@ function rcube_calendar_ui(settings)
var update_event = function(action, data)
{
me.saving_lock = rcmail.set_busy(true, 'calendar.savingdata');
rcmail.http_post('event', { action:action, e:data });
rcmail.http_post('calendar/event', { action:action, e:data });
// render event temporarily into the calendar
if ((data.start && data.end) || data.id) {
@ -1771,15 +1776,17 @@ function rcube_calendar_ui(settings)
};
// public method to bring up the new event dialog
this.add_event = function() {
this.add_event = function(templ) {
if (this.selected_calendar) {
var now = new Date();
var date = fc.fullCalendar('getDate') || now;
var date = fc.fullCalendar('getDate');
if (typeof date != 'Date')
date = now;
date.setHours(now.getHours()+1);
date.setMinutes(0);
var end = new Date(date.getTime());
end.setHours(date.getHours()+1);
event_edit_dialog('new', { start:date, end:end, allDay:false, calendar:this.selected_calendar });
event_edit_dialog('new', $.extend({ start:date, end:end, allDay:false, calendar:this.selected_calendar }, templ || {}));
}
};
@ -2391,7 +2398,7 @@ function rcube_calendar_ui(settings)
},
beforeShowDay: function(date) {
var view = fc.fullCalendar('getView');
var active = date.getTime() >= view.visStart.getTime() && date.getTime() < view.visEnd.getTime();
var active = view.visStart && date.getTime() >= view.visStart.getTime() && date.getTime() < view.visEnd.getTime();
return [ true, (active ? 'ui-datepicker-activerange ui-datepicker-active-' + view.name : ''), ''];
}
})) // set event handler for clicks on calendar week cell of the datepicker widget

View file

@ -64,6 +64,33 @@ class calendar_ui
$this->ready = true;
}
/**
* Register handler methods for the template engine
*/
public function init_templates()
{
$this->cal->register_handler('plugin.calendar_css', array($this, 'calendar_css'));
$this->cal->register_handler('plugin.calendar_list', array($this, 'calendar_list'));
$this->cal->register_handler('plugin.calendar_select', array($this, 'calendar_select'));
$this->cal->register_handler('plugin.category_select', array($this, 'category_select'));
$this->cal->register_handler('plugin.freebusy_select', array($this, 'freebusy_select'));
$this->cal->register_handler('plugin.priority_select', array($this, 'priority_select'));
$this->cal->register_handler('plugin.sensitivity_select', array($this, 'sensitivity_select'));
$this->cal->register_handler('plugin.alarm_select', array($this, 'alarm_select'));
$this->cal->register_handler('plugin.snooze_select', array($this, 'snooze_select'));
$this->cal->register_handler('plugin.recurrence_form', array($this, 'recurrence_form'));
$this->cal->register_handler('plugin.attachments_form', array($this, 'attachments_form'));
$this->cal->register_handler('plugin.attachments_list', array($this, 'attachments_list'));
$this->cal->register_handler('plugin.attendees_list', array($this, 'attendees_list'));
$this->cal->register_handler('plugin.attendees_form', array($this, 'attendees_form'));
$this->cal->register_handler('plugin.attendees_freebusy_table', array($this, 'attendees_freebusy_table'));
$this->cal->register_handler('plugin.edit_attendees_notify', array($this, 'edit_attendees_notify'));
$this->cal->register_handler('plugin.edit_recurring_warning', array($this, 'recurring_event_warning'));
$this->cal->register_handler('plugin.event_rsvp_buttons', array($this, 'event_rsvp_buttons'));
$this->cal->register_handler('plugin.angenda_options', array($this, 'angenda_options'));
$this->cal->register_handler('plugin.searchform', array($this->rc->output, 'search_form')); // use generic method from rcube_template
}
/**
* Adds CSS stylesheets to the page header
*/

View file

@ -67,6 +67,7 @@ $labels['searchlaterdates'] = 'Spätere Termine suchen »';
$labels['andnmore'] = '$nr weitere...';
$labels['showmore'] = 'Mehr anzeigen...';
$labels['togglerole'] = 'Klick zum Ändern der Rolle';
$labels['createfrommail'] = 'Als Termin speichern';
// agenda view
$labels['listrange'] = 'Angezeigter Bereich:';

View file

@ -67,6 +67,7 @@ $labels['searchlaterdates'] = 'Spätere Termine suchen »';
$labels['andnmore'] = '$nr weitere...';
$labels['showmore'] = 'Mehr anzeigen...';
$labels['togglerole'] = 'Klick zum Ändern der Rolle';
$labels['createfrommail'] = 'Als Termin speichern';
// agenda view
$labels['listrange'] = 'Angezeigter Bereich:';

View file

@ -67,6 +67,7 @@ $labels['searchlaterdates'] = 'Search for later events »';
$labels['andnmore'] = '$nr more...';
$labels['showmore'] = 'Show more...';
$labels['togglerole'] = 'Click to toggle role';
$labels['createfrommail'] = 'Save as event';
// agenda view
$labels['listrange'] = 'Range to display:';

View file

@ -1162,9 +1162,12 @@ fieldset #calendarcategories div {
margin-bottom: 0.3em;
}
/* Invitation UI in mail */
#messagemenu li a.calendarlink {
background: url(images/calendars.png) 7px -109px no-repeat;
}
div.calendar-invitebox {
min-height: 20px;
margin: 5px 8px;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -89,109 +89,7 @@
<roundcube:object name="plugin.event_rsvp_buttons" id="event-rsvp" style="display:none" />
</div>
<div id="eventedit" class="uidialog">
<form id="eventtabs" action="#" method="post" enctype="multipart/form-data">
<ul>
<li><a href="#event-tab-1"><roundcube:label name="calendar.tabsummary" /></a></li>
<li id="edit-tab-recurrence"><a href="#event-tab-2"><roundcube:label name="calendar.tabrecurrence" /></a></li>
<li id="edit-tab-attendees"><a href="#event-tab-3"><roundcube:label name="calendar.tabattendees" /></a></li>
<li id="edit-tab-attachments"><a href="#event-tab-4"><roundcube:label name="calendar.tabattachments" /></a></li>
</ul>
<!-- basic info -->
<div id="event-tab-1">
<div class="event-section">
<label for="edit-title"><roundcube:label name="calendar.title" /></label>
<br />
<input type="text" class="text" name="title" id="edit-title" size="40" />
</div>
<div class="event-section">
<label for="edit-location"><roundcube:label name="calendar.location" /></label>
<br />
<input type="text" class="text" name="location" id="edit-location" size="40" />
</div>
<div class="event-section">
<label for="edit-description"><roundcube:label name="calendar.description" /></label>
<br />
<textarea name="description" id="edit-description" class="text" rows="5" cols="40"></textarea>
</div>
<div class="event-section">
<label style="float:right;padding-right:0.5em"><input type="checkbox" name="allday" id="edit-allday" value="1" /><roundcube:label name="calendar.all-day" /></label>
<label for="edit-startdate"><roundcube:label name="calendar.start" /></label>
<input type="text" name="startdate" size="10" id="edit-startdate" /> &nbsp;
<input type="text" name="starttime" size="6" id="edit-starttime" />
</div>
<div class="event-section">
<label for="edit-enddate"><roundcube:label name="calendar.end" /></label>
<input type="text" name="enddate" size="10" id="edit-enddate" /> &nbsp;
<input type="text" name="endtime" size="6" id="edit-endtime" />
</div>
<div class="event-section" id="edit-alarms">
<label for="edit-alarm"><roundcube:label name="calendar.alarms" /></label>
<roundcube:object name="plugin.alarm_select" />
</div>
<div class="event-section" id="calendar-select">
<label for="edit-calendar"><roundcube:label name="calendar.calendar" /></label>
<roundcube:object name="plugin.calendar_select" id="edit-calendar" />
</div>
<div class="event-section">
<label for="edit-categories"><roundcube:label name="calendar.category" /></label>
<roundcube:object name="plugin.category_select" id="edit-categories" />
</div>
<div class="event-section">
<label for="edit-free-busy"><roundcube:label name="calendar.freebusy" /></label>
<roundcube:object name="plugin.freebusy_select" id="edit-free-busy" />
</div>
<div class="event-section">
<label for="edit-priority"><roundcube:label name="calendar.priority" /></label>
<roundcube:object name="plugin.priority_select" id="edit-priority" />
</div>
<div class="event-section">
<label for="edit-sensitivity"><roundcube:label name="calendar.sensitivity" /></label>
<roundcube:object name="plugin.sensitivity_select" id="edit-sensitivity" />
</div>
</div>
<!-- recurrence settings -->
<div id="event-tab-2">
<div class="event-section border-after">
<roundcube:object name="plugin.recurrence_form" part="frequency" />
</div>
<div class="recurrence-form border-after" id="recurrence-form-daily">
<roundcube:object name="plugin.recurrence_form" part="daily" class="event-section" />
</div>
<div class="recurrence-form border-after" id="recurrence-form-weekly">
<roundcube:object name="plugin.recurrence_form" part="weekly" class="event-section" />
</div>
<div class="recurrence-form border-after" id="recurrence-form-monthly">
<roundcube:object name="plugin.recurrence_form" part="monthly" class="event-section" />
</div>
<div class="recurrence-form border-after" id="recurrence-form-yearly">
<roundcube:object name="plugin.recurrence_form" part="yearly" class="event-section" />
</div>
<div class="recurrence-form" id="recurrence-form-until">
<roundcube:object name="plugin.recurrence_form" part="until" class="event-section" />
</div>
</div>
<!-- attendees list -->
<div id="event-tab-3">
<roundcube:object name="plugin.attendees_list" id="edit-attendees-table" cellspacing="0" cellpadding="0" border="0" />
<roundcube:object name="plugin.attendees_form" id="edit-attendees-form" />
<roundcube:include file="/templates/freebusylegend.html" />
</div>
<!-- attachments list (with upload form) -->
<div id="event-tab-4">
<div id="edit-attachments" class="attachments-list">
<roundcube:object name="plugin.attachments_list" id="attachmentlist" deleteIcon="/images/icons/delete.png" cancelIcon="/images/icons/delete.png" loadingIcon="/images/display/loading_blue.gif" />
</div>
<div id="edit-attachments-form">
<roundcube:object name="plugin.attachments_form" id="calendar-attachment-form" attachmentFieldSize="30" />
</div>
</div>
</form>
<roundcube:object name="plugin.edit_attendees_notify" id="edit-attendees-notify" class="event-dialog-message" style="display:none" />
<roundcube:object name="plugin.edit_recurring_warning" class="event-dialog-message edit-recurring-warning" style="display:none" />
<div id="edit-localchanges-warning" class="event-dialog-message" style="display:none"><roundcube:label name="calendar.localchangeswarning" /></div>
</div>
<roundcube:include file="/templates/eventedit.html" />
<div id="eventfreebusy" class="uidialog">
<roundcube:object name="plugin.attendees_freebusy_table" id="attendees-freebusy-table" cellspacing="0" cellpadding="0" border="0" />

View file

@ -0,0 +1,103 @@
<div id="eventedit" class="uidialog">
<form id="eventtabs" action="#" method="post" enctype="multipart/form-data">
<ul>
<li><a href="#event-tab-1"><roundcube:label name="calendar.tabsummary" /></a></li>
<li id="edit-tab-recurrence"><a href="#event-tab-2"><roundcube:label name="calendar.tabrecurrence" /></a></li>
<li id="edit-tab-attendees"><a href="#event-tab-3"><roundcube:label name="calendar.tabattendees" /></a></li>
<li id="edit-tab-attachments"><a href="#event-tab-4"><roundcube:label name="calendar.tabattachments" /></a></li>
</ul>
<!-- basic info -->
<div id="event-tab-1">
<div class="event-section">
<label for="edit-title"><roundcube:label name="calendar.title" /></label>
<br />
<input type="text" class="text" name="title" id="edit-title" size="40" />
</div>
<div class="event-section">
<label for="edit-location"><roundcube:label name="calendar.location" /></label>
<br />
<input type="text" class="text" name="location" id="edit-location" size="40" />
</div>
<div class="event-section">
<label for="edit-description"><roundcube:label name="calendar.description" /></label>
<br />
<textarea name="description" id="edit-description" class="text" rows="5" cols="40"></textarea>
</div>
<div class="event-section">
<label style="float:right;padding-right:0.5em"><input type="checkbox" name="allday" id="edit-allday" value="1" /><roundcube:label name="calendar.all-day" /></label>
<label for="edit-startdate"><roundcube:label name="calendar.start" /></label>
<input type="text" name="startdate" size="10" id="edit-startdate" /> &nbsp;
<input type="text" name="starttime" size="6" id="edit-starttime" />
</div>
<div class="event-section">
<label for="edit-enddate"><roundcube:label name="calendar.end" /></label>
<input type="text" name="enddate" size="10" id="edit-enddate" /> &nbsp;
<input type="text" name="endtime" size="6" id="edit-endtime" />
</div>
<div class="event-section" id="edit-alarms">
<label for="edit-alarm"><roundcube:label name="calendar.alarms" /></label>
<roundcube:object name="plugin.alarm_select" />
</div>
<div class="event-section" id="calendar-select">
<label for="edit-calendar"><roundcube:label name="calendar.calendar" /></label>
<roundcube:object name="plugin.calendar_select" id="edit-calendar" />
</div>
<div class="event-section">
<label for="edit-categories"><roundcube:label name="calendar.category" /></label>
<roundcube:object name="plugin.category_select" id="edit-categories" />
</div>
<div class="event-section">
<label for="edit-free-busy"><roundcube:label name="calendar.freebusy" /></label>
<roundcube:object name="plugin.freebusy_select" id="edit-free-busy" />
</div>
<div class="event-section">
<label for="edit-priority"><roundcube:label name="calendar.priority" /></label>
<roundcube:object name="plugin.priority_select" id="edit-priority" />
</div>
<div class="event-section">
<label for="edit-sensitivity"><roundcube:label name="calendar.sensitivity" /></label>
<roundcube:object name="plugin.sensitivity_select" id="edit-sensitivity" />
</div>
</div>
<!-- recurrence settings -->
<div id="event-tab-2">
<div class="event-section border-after">
<roundcube:object name="plugin.recurrence_form" part="frequency" />
</div>
<div class="recurrence-form border-after" id="recurrence-form-daily">
<roundcube:object name="plugin.recurrence_form" part="daily" class="event-section" />
</div>
<div class="recurrence-form border-after" id="recurrence-form-weekly">
<roundcube:object name="plugin.recurrence_form" part="weekly" class="event-section" />
</div>
<div class="recurrence-form border-after" id="recurrence-form-monthly">
<roundcube:object name="plugin.recurrence_form" part="monthly" class="event-section" />
</div>
<div class="recurrence-form border-after" id="recurrence-form-yearly">
<roundcube:object name="plugin.recurrence_form" part="yearly" class="event-section" />
</div>
<div class="recurrence-form" id="recurrence-form-until">
<roundcube:object name="plugin.recurrence_form" part="until" class="event-section" />
</div>
</div>
<!-- attendees list -->
<div id="event-tab-3">
<roundcube:object name="plugin.attendees_list" id="edit-attendees-table" cellspacing="0" cellpadding="0" border="0" />
<roundcube:object name="plugin.attendees_form" id="edit-attendees-form" />
<roundcube:include file="/templates/freebusylegend.html" />
</div>
<!-- attachments list (with upload form) -->
<div id="event-tab-4">
<div id="edit-attachments" class="attachments-list">
<roundcube:object name="plugin.attachments_list" id="attachmentlist" deleteIcon="/images/icons/delete.png" cancelIcon="/images/icons/delete.png" loadingIcon="/images/display/loading_blue.gif" />
</div>
<div id="edit-attachments-form">
<roundcube:object name="plugin.attachments_form" id="calendar-attachment-form" attachmentFieldSize="30" />
</div>
</div>
</form>
<roundcube:object name="plugin.edit_attendees_notify" id="edit-attendees-notify" class="event-dialog-message" style="display:none" />
<roundcube:object name="plugin.edit_recurring_warning" class="event-dialog-message edit-recurring-warning" style="display:none" />
<div id="edit-localchanges-warning" class="event-dialog-message" style="display:none"><roundcube:label name="calendar.localchangeswarning" /></div>
</div>