Implement iTip delegation functionality for calendar/mail view (#3860)
This commit is contained in:
parent
17f8ec0d04
commit
4a150a2139
8 changed files with 272 additions and 13 deletions
|
@ -150,6 +150,7 @@ class calendar extends rcube_plugin
|
|||
$this->register_action('itip-status', array($this, 'event_itip_status'));
|
||||
$this->register_action('itip-remove', array($this, 'event_itip_remove'));
|
||||
$this->register_action('itip-decline-reply', array($this, 'mail_itip_decline_reply'));
|
||||
$this->register_action('itip-delegate', array($this, 'mail_itip_delegate'));
|
||||
$this->register_action('resources-list', array($this, 'resources_list'));
|
||||
$this->register_action('resources-owner', array($this, 'resources_owner'));
|
||||
$this->register_action('resources-calendar', array($this, 'resources_calendar'));
|
||||
|
@ -239,7 +240,7 @@ class calendar extends rcube_plugin
|
|||
$this->itip = new calendar_itip($this);
|
||||
|
||||
if ($this->rc->config->get('kolab_invitation_calendars'))
|
||||
$this->itip->set_rsvp_actions(array('accepted','tentative','declined','needs-action'));
|
||||
$this->itip->set_rsvp_actions(array('accepted','tentative','declined','delegated','needs-action'));
|
||||
}
|
||||
|
||||
return $this->itip;
|
||||
|
@ -957,6 +958,16 @@ class calendar extends rcube_plugin
|
|||
|
||||
$ev = $this->driver->get_event($event);
|
||||
$ev['attendees'] = $event['attendees'];
|
||||
|
||||
// send invitation to delegatee + add it as attendee
|
||||
if ($status == 'delegated' && $event['to']) {
|
||||
$itip = $this->load_itip();
|
||||
if ($itip->delegate_to($ev, $event['to'], (bool)$event['rsvp'])) {
|
||||
$this->rc->output->show_message('calendar.itipsendsuccess', 'confirmation');
|
||||
$noreply = false;
|
||||
}
|
||||
}
|
||||
|
||||
$event = $ev;
|
||||
|
||||
if ($success = $this->driver->edit_rsvp($event, $status)) {
|
||||
|
@ -974,6 +985,7 @@ class calendar extends rcube_plugin
|
|||
$reply_sender = $attendee['email'];
|
||||
}
|
||||
}
|
||||
|
||||
if (!$noreply) {
|
||||
$itip = $this->load_itip();
|
||||
$itip->set_sender_email($reply_sender);
|
||||
|
@ -2567,9 +2579,36 @@ class calendar extends rcube_plugin
|
|||
|
||||
$error_msg = $this->gettext('errorimportingevent');
|
||||
$success = false;
|
||||
$delegate = null;
|
||||
|
||||
if ($status == 'delegated') {
|
||||
$delegates = rcube_mime::decode_address_list(rcube_utils::get_input_value('_to', rcube_utils::INPUT_POST, true), 1, false);
|
||||
$delegate = reset($delegates);
|
||||
|
||||
if (empty($delegate) || empty($delegate['mailto'])) {
|
||||
$this->rc->output->command('display_message', $this->gettext('libcalendaring.delegateinvalidaddress'), 'error');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// successfully parsed events?
|
||||
if ($event = $this->lib->mail_get_itip_object($mbox, $uid, $mime_id, 'event')) {
|
||||
// forward iTip request to delegatee
|
||||
if ($delegate) {
|
||||
$rsvpme = intval(rcube_utils::get_input_value('_rsvp', rcube_utils::INPUT_POST));
|
||||
|
||||
$itip = $this->load_itip();
|
||||
if ($itip->delegate_to($event, $delegate, $rsvpme ? true : false)) {
|
||||
$this->rc->output->show_message('calendar.itipsendsuccess', 'confirmation');
|
||||
}
|
||||
else {
|
||||
$this->rc->output->command('display_message', $this->gettext('itipresponseerror'), 'error');
|
||||
}
|
||||
|
||||
// the delegator is set to non-participant, thus save as non-blocking
|
||||
$event['free_busy'] = 'free';
|
||||
}
|
||||
|
||||
// find writeable calendar to store event
|
||||
$cal_id = !empty($_REQUEST['_folder']) ? rcube_utils::get_input_value('_folder', rcube_utils::INPUT_POST) : null;
|
||||
$dontsave = ($_REQUEST['_folder'] === '' && $event['_method'] == 'REQUEST');
|
||||
|
@ -2692,14 +2731,14 @@ class calendar extends rcube_plugin
|
|||
if ($event['_method'] == 'CANCEL')
|
||||
$event['status'] = 'CANCELLED';
|
||||
// show me as free when declined (#1670)
|
||||
if ($status == 'declined' || $event['status'] == 'CANCELLED')
|
||||
if ($status == 'declined' || $event['status'] == 'CANCELLED' || $event_attendee['role'] == 'NON-PARTICIPANT')
|
||||
$event['free_busy'] = 'free';
|
||||
|
||||
$success = $this->driver->edit_event($event);
|
||||
}
|
||||
else if (!empty($status)) {
|
||||
$existing['attendees'] = $event['attendees'];
|
||||
if ($status == 'declined') // show me as free when declined (#1670)
|
||||
if ($status == 'declined' || $event_attendee['role'] == 'NON-PARTICIPANT') // show me as free when declined (#1670)
|
||||
$existing['free_busy'] = 'free';
|
||||
$success = $this->driver->edit_event($existing);
|
||||
}
|
||||
|
@ -2780,6 +2819,16 @@ class calendar extends rcube_plugin
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for calendar/itip-delegate requests
|
||||
*/
|
||||
function mail_itip_delegate()
|
||||
{
|
||||
// forward request to mail_import_itip() with the right status
|
||||
$_POST['_status'] = $_REQUEST['_status'] = 'delegated';
|
||||
$this->mail_import_itip();
|
||||
}
|
||||
|
||||
/**
|
||||
* Import the full payload from a mail message attachment
|
||||
*/
|
||||
|
|
|
@ -2323,20 +2323,41 @@ function rcube_calendar_ui(settings)
|
|||
}
|
||||
|
||||
// when the user accepts or declines an event invitation
|
||||
var event_rsvp = function(response)
|
||||
var event_rsvp = function(response, delegate)
|
||||
{
|
||||
if (me.selected_event && me.selected_event.attendees && response) {
|
||||
// bring up delegation dialog
|
||||
if (response == 'delegated' && !delegate) {
|
||||
rcube_libcalendaring.itip_delegate_dialog(function(data) {
|
||||
data.rsvp = data.rsvp ? 1 : '';
|
||||
event_rsvp('delegated', data);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 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(';'+String(data.email).toLowerCase()) >= 0) {
|
||||
data.status = response.toUpperCase();
|
||||
delete data.rsvp; // unset RSVP flag
|
||||
|
||||
if (data.status == 'DELEGATED') {
|
||||
data['delegated-to'] = delegate.to;
|
||||
}
|
||||
else {
|
||||
delete data.rsvp; // unset RSVP flag
|
||||
|
||||
if (data['delegated-to']) {
|
||||
delete data['delegated-to'];
|
||||
if (data.role == 'NON-PARTICIPANT' && status != 'DECLINED')
|
||||
data.role = 'REQ-PARTICIPANT';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// submit status change to server
|
||||
var submit_data = $.extend({}, me.selected_event, { source:null, comment:$('#reply-comment-event-rsvp').val() }),
|
||||
var submit_data = $.extend({}, me.selected_event, { source:null, comment:$('#reply-comment-event-rsvp').val() }, (delegate || {})),
|
||||
noreply = $('#noreply-event-rsvp:checked').length ? 1 : 0;
|
||||
|
||||
// import event from mail (temporary iTip event)
|
||||
|
@ -2347,6 +2368,8 @@ function rcube_calendar_ui(settings)
|
|||
_uid: submit_data._uid,
|
||||
_part: submit_data._part,
|
||||
_status: response,
|
||||
_to: (delegate ? delegate.to : null),
|
||||
_rsvp: (delegate && delegate.rsvp) ? 1 : 0,
|
||||
_noreply: noreply,
|
||||
_comment: submit_data.comment
|
||||
});
|
||||
|
|
|
@ -886,7 +886,7 @@ class calendar_ui
|
|||
|
||||
function event_rsvp_buttons($attrib = array())
|
||||
{
|
||||
return $this->cal->itip->itip_rsvp_buttons($attrib, array('accepted','tentative','declined'));
|
||||
return $this->cal->itip->itip_rsvp_buttons($attrib, array('accepted','tentative','declined','delegated'));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -190,6 +190,8 @@ $labels['itipmailbodyaccepted'] = "\$sender has accepted the invitation to the f
|
|||
$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['itipmailbodycancel'] = "\$sender has rejected your participation in the following event:\n\n*\$title*\n\nWhen: \$date";
|
||||
$labels['itipmailbodydelegated'] = "\$sender has delegated the participation in the following event:\n\n*\$title*\n\nWhen: \$date";
|
||||
$labels['itipmailbodydelegatedto'] = "\$sender has delegated the participation in the following event to you:\n\n*\$title*\n\nWhen: \$date";
|
||||
|
||||
$labels['itipdeclineevent'] = 'Do you want to decline your invitation to this event?';
|
||||
$labels['declinedeleteconfirm'] = 'Do you also want to delete this declined event from your calendar?';
|
||||
|
|
|
@ -30,7 +30,7 @@ class libcalendaring_itip
|
|||
protected $sender;
|
||||
protected $domain;
|
||||
protected $itip_send = false;
|
||||
protected $rsvp_actions = array('accepted','tentative','declined');
|
||||
protected $rsvp_actions = array('accepted','tentative','declined','delegated');
|
||||
protected $rsvp_status = array('accepted','tentative','declined','delegated');
|
||||
|
||||
function __construct($plugin, $domain = 'libcalendaring')
|
||||
|
@ -257,6 +257,61 @@ class libcalendaring_itip
|
|||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward the given iTip event as delegation to another person
|
||||
*
|
||||
* @param array Event object to delegate
|
||||
* @param mixed Delegatee as string or hash array with keys 'name' and 'mailto'
|
||||
* @return boolean True on success, False on failure
|
||||
*/
|
||||
public function delegate_to(&$event, $delegate, $rsvp = false)
|
||||
{
|
||||
if (is_string($delegate)) {
|
||||
$delegates = rcube_mime::decode_address_list($delegate, 1, false);
|
||||
if (count($delegates) > 0) {
|
||||
$delegate = reset($delegates);
|
||||
}
|
||||
}
|
||||
|
||||
$emails = $this->lib->get_user_emails();
|
||||
$me = $this->rc->user->get_identity();
|
||||
|
||||
// find/create the delegate attendee
|
||||
$delegate_attendee = array(
|
||||
'email' => $delegate['mailto'],
|
||||
'name' => $delegate['name'],
|
||||
'role' => 'REQ-PARTICIPANT',
|
||||
);
|
||||
$delegate_index = count($event['attendees']);
|
||||
|
||||
foreach ($event['attendees'] as $i => $attendee) {
|
||||
// set myself the DELEGATED-TO parameter
|
||||
if ($attendee['email'] && in_array(strtolower($attendee['email']), $emails)) {
|
||||
$event['attendees'][$i]['delegated-to'] = $delegate['mailto'];
|
||||
$event['attendees'][$i]['status'] = 'DELEGATED';
|
||||
$event['attendees'][$i]['role'] = 'NON-PARTICIPANT';
|
||||
$event['attendees'][$i]['rsvp'] = $rsvp;
|
||||
|
||||
$me['email'] = $attendee['email'];
|
||||
$delegate_attendee['role'] = $attendee['role'];
|
||||
}
|
||||
// the disired delegatee is already listed as an attendee
|
||||
else if (stripos($delegate['mailto'], $attendee['email']) !== false && $attendee['role'] != 'ORGANIZER') {
|
||||
$delegate_attendee = $attendee;
|
||||
$delegate_index = $i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// set/add delegate attendee with RSVP=TRUE and DELEGATED-FROM parameter
|
||||
$delegate_attendee['rsvp'] = true;
|
||||
$delegate_attendee['status'] = 'NEEDS-ACTION';
|
||||
$delegate_attendee['delegated-from'] = $me['email'];
|
||||
$event['attendees'][$delegate_index] = $delegate_attendee;
|
||||
|
||||
$this->set_sender_email($me['email']);
|
||||
return $this->send_itip_message($event, 'REQUEST', $delegate_attendee, 'itipsubjectdelegatedto', 'itipmailbodydelegatedto');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for calendar/itip-status requests
|
||||
|
@ -332,7 +387,7 @@ class libcalendaring_itip
|
|||
$html = html::div('rsvp-status ' . $status_lc, $this->gettext(array(
|
||||
'name' => 'attendee' . $status_lc,
|
||||
'vars' => array(
|
||||
'delegatedto' => Q($attendee['delegated-to'] ?: '?'),
|
||||
'delegatedto' => Q($event['delegated-to'] ?: ($attendee['delegated-to'] ?: '?')),
|
||||
)
|
||||
)));
|
||||
}
|
||||
|
@ -400,6 +455,8 @@ class libcalendaring_itip
|
|||
if (!empty($attendee['email']) && $attendee['role'] != 'ORGANIZER') {
|
||||
$metadata['attendee'] = $attendee['email'];
|
||||
$rsvp_status = strtoupper($attendee['status']);
|
||||
if ($attendee['delegated-to'])
|
||||
$metadata['delegated-to'] = $attendee['delegated-to'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -498,6 +555,11 @@ class libcalendaring_itip
|
|||
|
||||
$buttons[] = html::div(array('id' => 'rsvp-'.$dom_id, 'class' => 'rsvp-buttons', 'style' => 'display:none'), $rsvp_buttons);
|
||||
$buttons[] = html::div(array('id' => 'update-'.$dom_id, 'style' => 'display:none'), $update_button);
|
||||
|
||||
// prepare autocompletion for delegation dialog
|
||||
if (in_array('delegated', $this->rsvp_actions)) {
|
||||
$this->rc->autocomplete_init();
|
||||
}
|
||||
}
|
||||
// for CANCEL messages, we can:
|
||||
else if ($method == 'CANCEL') {
|
||||
|
@ -530,8 +592,6 @@ class libcalendaring_itip
|
|||
$buttons[] = html::div(array('id' => 'import-'.$dom_id, 'style' => 'display:none'), $import_button);
|
||||
}
|
||||
|
||||
// TODO: add option/checkbox to delete this message after update
|
||||
|
||||
// pass some metadata about the event and trigger the asynchronous status check
|
||||
$metadata['fallback'] = $rsvp_status;
|
||||
$metadata['rsvp'] = intval($metadata['rsvp']);
|
||||
|
@ -539,7 +599,9 @@ class libcalendaring_itip
|
|||
$this->rc->output->add_script("rcube_libcalendaring.fetch_itip_object_status(" . json_serialize($metadata) . ")", 'docready');
|
||||
|
||||
// get localized texts from the right domain
|
||||
foreach (array('savingdata','deleteobjectconfirm','declinedeleteconfirm','declineattendee','declineattendeeconfirm','cancel') as $label) {
|
||||
foreach (array('savingdata','deleteobjectconfirm','declinedeleteconfirm','declineattendee',
|
||||
'cancel','itipdelegated','declineattendeeconfirm','itipcomment','delegateinvitation',
|
||||
'delegateto','delegatersvpme','delegateinvalidaddress') as $label) {
|
||||
$this->rc->output->command('add_label', "itip.$label", $this->gettext($label));
|
||||
}
|
||||
|
||||
|
@ -570,6 +632,14 @@ class libcalendaring_itip
|
|||
|
||||
$buttons .= html::div('itip-reply-controls', $this->itip_rsvp_options_ui($attrib['id']));
|
||||
|
||||
// add localized texts for the delegation dialog
|
||||
if (in_array('delegated', $actions)) {
|
||||
foreach (array('itipdelegated','itipcomment','delegateinvitation',
|
||||
'delegateto','delegatersvpme','delegateinvalidaddress') as $label) {
|
||||
$this->rc->output->command('add_label', "itip.$label", $this->gettext($label));
|
||||
}
|
||||
}
|
||||
|
||||
return html::div($attrib,
|
||||
html::div('label', $this->gettext('acceptinvitation')) .
|
||||
html::div('rsvp-buttons', $buttons));
|
||||
|
|
|
@ -803,6 +803,22 @@ rcube_libcalendaring.add_from_itip_mail = function(mime_id, task, status, dom_id
|
|||
del = confirm(rcmail.gettext('itip.declinedeleteconfirm'));
|
||||
}
|
||||
|
||||
// open dialog for iTip delegation
|
||||
if (status == 'delegated') {
|
||||
rcube_libcalendaring.itip_delegate_dialog(function(data) {
|
||||
rcmail.http_post(task + '/itip-delegate', {
|
||||
_uid: rcmail.env.uid,
|
||||
_mbox: rcmail.env.mailbox,
|
||||
_part: mime_id,
|
||||
_to: data.to,
|
||||
_rsvp: data.rsvp ? 1 : 0,
|
||||
_comment: data.comment,
|
||||
_folder: data.target
|
||||
}, rcmail.set_busy(true, 'itip.savingdata'));
|
||||
}, $('#rsvp-'+dom_id+' .folder-select'));
|
||||
return false;
|
||||
}
|
||||
|
||||
var noreply = 0, comment = '';
|
||||
if (dom_id) {
|
||||
noreply = $('#noreply-'+dom_id+':checked').length ? 1 : 0;
|
||||
|
@ -824,6 +840,90 @@ rcube_libcalendaring.add_from_itip_mail = function(mime_id, task, status, dom_id
|
|||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to render the iTip delegation dialog
|
||||
* and trigger a callback function when submitted.
|
||||
*/
|
||||
rcube_libcalendaring.itip_delegate_dialog = function(callback, selector)
|
||||
{
|
||||
// show dialog for entering the delegatee address and comment
|
||||
var html = '<form class="itip-dialog-form" action="javascript:void()">' +
|
||||
'<div class="form-section">' +
|
||||
'<label for="itip-delegate-to">' + rcmail.gettext('itip.delegateto') + '</label><br/>' +
|
||||
'<input type="text" id="itip-delegate-to" class="text" size="40" value="" />' +
|
||||
'</div>' +
|
||||
'<div class="form-section">' +
|
||||
'<label for="itip-delegate-rsvp">' +
|
||||
'<input type="checkbox" id="itip-delegate-rsvp" class="checkbox" size="40" value="" />' +
|
||||
rcmail.gettext('itip.delegatersvpme') +
|
||||
'</label>' +
|
||||
'</div>' +
|
||||
'<div class="form-section">' +
|
||||
'<textarea id="itip-delegate-comment" class="itip-comment" cols="40" rows="8" placeholder="' +
|
||||
rcmail.gettext('itip.itipcomment') + '"></textarea>' +
|
||||
'</div>' +
|
||||
'<div class="form-section">' +
|
||||
(selector ? selector.html() : '') +
|
||||
'</div>' +
|
||||
'</form>';
|
||||
|
||||
var dialog, buttons = [];
|
||||
buttons.push({
|
||||
text: rcmail.gettext('itipdelegated', 'itip'),
|
||||
click: function() {
|
||||
var doc = window.parent.document,
|
||||
delegatee = String($('#itip-delegate-to', doc).val()).replace(/(^\s+)|(\s+$)/, '');
|
||||
|
||||
if (delegatee != '' && rcube_check_email(delegatee, true)) {
|
||||
callback({
|
||||
to: delegatee,
|
||||
rsvp: $('#itip-delegate-rsvp', doc).prop('checked'),
|
||||
comment: $('#itip-delegate-comment', doc).val(),
|
||||
target: $('#itip-saveto', doc).val()
|
||||
});
|
||||
|
||||
setTimeout(function() { dialog.dialog("close"); }, 500);
|
||||
}
|
||||
else {
|
||||
alert(rcmail.gettext('itip.delegateinvalidaddress'));
|
||||
$('#itip-delegate-to', doc).focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
buttons.push({
|
||||
text: rcmail.gettext('cancel', 'itip'),
|
||||
click: function() {
|
||||
dialog.dialog('close');
|
||||
}
|
||||
});
|
||||
|
||||
dialog = rcmail.show_popup_dialog(html, rcmail.gettext('delegateinvitation', 'itip'), buttons, {
|
||||
width: 460,
|
||||
open: function(event, ui) {
|
||||
$(this).parent().find('.ui-button:not(.ui-dialog-titlebar-close)').first().addClass('mainaction');
|
||||
$(this).find('#itip-saveto').val('');
|
||||
|
||||
// initialize autocompletion
|
||||
var ac_props, rcm = rcmail.is_framed() ? parent.rcmail : rcmail;
|
||||
if (rcmail.env.autocomplete_threads > 0) {
|
||||
ac_props = {
|
||||
threads: rcmail.env.autocomplete_threads,
|
||||
sources: rcmail.env.autocomplete_sources
|
||||
};
|
||||
}
|
||||
rcm.init_address_input_events($(this).find('#itip-delegate-to').focus(), ac_props);
|
||||
rcm.env.recipients_delimiter = '';
|
||||
},
|
||||
close: function(event, ui) {
|
||||
rcmail.ksearch_blur();
|
||||
$(this).remove();
|
||||
}
|
||||
});
|
||||
|
||||
return dialog;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -870,7 +970,7 @@ rcube_libcalendaring.decline_attendee_reply = function(mime_id, task)
|
|||
dialog = rcmail.show_popup_dialog(html, rcmail.gettext('declineattendee', 'itip'), buttons, {
|
||||
width: 460,
|
||||
open: function() {
|
||||
$(this).parent().find('.ui-button').first().addClass('mainaction');
|
||||
$(this).parent().find('.ui-button:not(.ui-dialog-titlebar-close)').first().addClass('mainaction');
|
||||
$('#itip-decline-comment').focus();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -98,6 +98,8 @@ $labels['itipsubjectdeclined'] = '"$title" has been declined by $name';
|
|||
$labels['itipsubjectin-process'] = '"$title" is in-process by $name';
|
||||
$labels['itipsubjectcompleted'] = '"$title" was completed by $name';
|
||||
$labels['itipsubjectcancel'] = 'Your participation in "$title" has been cancelled';
|
||||
$labels['itipsubjectdelegated'] = '"$title" has been delegated by $name';
|
||||
$labels['itipsubjectdelegatedto'] = '"$title" has been delegated to you by $name';
|
||||
|
||||
$labels['itipnewattendee'] = 'This is a reply from a new participant';
|
||||
$labels['updateattendeestatus'] = 'Update the participant\'s status';
|
||||
|
@ -139,6 +141,11 @@ $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?';
|
||||
|
||||
$labels['delegateinvitation'] = 'Delegate Invitation';
|
||||
$labels['delegateto'] = 'Delegate to';
|
||||
$labels['delegatersvpme'] = 'Keep me informed about updates of this incidence';
|
||||
$labels['delegateinvalidaddress'] = 'Please enter a valid email address for the delegate';
|
||||
|
||||
$labels['savingdata'] = 'Saving data...';
|
||||
|
||||
// attendees labels
|
||||
|
|
|
@ -156,3 +156,11 @@ label.noreply-toggle + a.reply-comment-toggle {
|
|||
margin-top: -1.4em;
|
||||
}
|
||||
|
||||
.itip-dialog-form input.text {
|
||||
width: 98%;
|
||||
}
|
||||
|
||||
.itip-dialog-form label > input.checkbox {
|
||||
margin-left: 0;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue