From ed6eaac9d09a0135bb41bdfc45822f64b5afd9ee Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Wed, 27 Aug 2014 14:00:08 +0200 Subject: [PATCH] Add config option to hide iTip sending checkboxes or even disable it entirely (#3483). The default setting remains visible + checked. Set $config['calendar_itip_send_option'] = 1; to hide the checkboxes and implicitly send iTip notifications. --- plugins/calendar/calendar.php | 17 ++++-- plugins/calendar/calendar_ui.js | 52 +++++++++++-------- plugins/calendar/config.inc.php.dist | 23 +++++--- plugins/calendar/lib/calendar_ui.php | 12 +++-- plugins/calendar/skins/classic/calendar.css | 6 +-- plugins/calendar/skins/larry/calendar.css | 6 +-- .../lib/libcalendaring_itip.php | 16 ++++-- plugins/libcalendaring/libcalendaring.js | 2 +- plugins/libcalendaring/skins/larry/libcal.css | 5 +- plugins/tasklist/skins/larry/tasklist.css | 6 +-- plugins/tasklist/tasklist.js | 46 ++++++++++------ plugins/tasklist/tasklist.php | 10 +++- plugins/tasklist/tasklist_ui.php | 10 +++- 13 files changed, 138 insertions(+), 73 deletions(-) diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php index 36947ea1..e26c6dba 100644 --- a/plugins/calendar/calendar.php +++ b/plugins/calendar/calendar.php @@ -54,6 +54,7 @@ class calendar extends rcube_plugin 'calendar_event_coloring' => 0, 'calendar_time_indicator' => true, 'calendar_allow_invite_shared' => false, + 'calendar_itip_send_option' => 3, 'calendar_itip_after_action' => 0, ); @@ -829,7 +830,10 @@ class calendar extends rcube_plugin // don't notify if modifying a recurring instance (really?) if ($event['_savemode'] && $event['_savemode'] != 'all' && $event['_notify']) unset($event['_notify']); - + // force notify if hidden + active + else if ((int)$this->rc->config->get('calendar_itip_send_option', $this->defaults['calendar_itip_send_option']) === 1) + $event['_notify'] = 1; + // read old event data in order to find changes if (($event['_notify'] || $event['decline']) && $action != 'new') $old = $this->driver->get_event($event); @@ -933,6 +937,7 @@ class calendar extends rcube_plugin break; case "rsvp": + $itip_sending = $this->rc->config->get('calendar_itip_send_option', $this->defaults['calendar_itip_send_option']); $status = get_input_value('status', RCUBE_INPUT_GPC); $reply_comment = $event['comment']; $ev = $this->driver->get_event($event); @@ -940,7 +945,7 @@ class calendar extends rcube_plugin $event = $ev; if ($success = $this->driver->edit_rsvp($event, $status)) { - $noreply = intval(get_input_value('noreply', RCUBE_INPUT_GPC)) || $status == 'needs-action'; + $noreply = intval(get_input_value('noreply', RCUBE_INPUT_GPC)) || $status == 'needs-action' || $itip_sending === 0; $reload = $event['calendar'] != $ev['calendar'] ? 2 : 1; $organizer = null; $emails = $this->get_user_emails(); @@ -1475,6 +1480,7 @@ class calendar extends rcube_plugin $settings['time_indicator'] = (int)$this->rc->config->get('calendar_time_indicator', $this->defaults['calendar_time_indicator']); $settings['invite_shared'] = (int)$this->rc->config->get('calendar_allow_invite_shared', $this->defaults['calendar_allow_invite_shared']); $settings['invitation_calendars'] = (bool)$this->rc->config->get('kolab_invitation_calendars', false); + $settings['itip_notify'] = (int)$this->rc->config->get('calendar_itip_send_option', $this->defaults['calendar_itip_send_option']); // get user identity to create default attendee if ($this->ui->screen == 'calendar') { @@ -1771,6 +1777,7 @@ class calendar extends rcube_plugin $itip = $this->load_itip(); $emails = $this->get_user_emails(); + $itip_notify = (int)$this->rc->config->get('calendar_itip_send_option', $this->defaults['calendar_itip_send_option']); // add comment to the iTip attachment $event['comment'] = $comment; @@ -1795,7 +1802,7 @@ class calendar extends rcube_plugin continue; // skip if notification is disabled for this attendee - if ($attendee['noreply']) + if ($attendee['noreply'] && $itip_notify & 2) continue; // which template to use for mail text @@ -2391,12 +2398,14 @@ class calendar extends rcube_plugin */ public function mail_import_itip() { + $itip_sending = $this->rc->config->get('calendar_itip_send_option', $this->defaults['calendar_itip_send_option']); + $uid = get_input_value('_uid', RCUBE_INPUT_POST); $mbox = get_input_value('_mbox', RCUBE_INPUT_POST); $mime_id = get_input_value('_part', RCUBE_INPUT_POST); $status = get_input_value('_status', RCUBE_INPUT_POST); $delete = intval(get_input_value('_del', RCUBE_INPUT_POST)); - $noreply = intval(get_input_value('_noreply', RCUBE_INPUT_POST)) || $status == 'needs-action'; + $noreply = intval(get_input_value('_noreply', RCUBE_INPUT_POST)) || $status == 'needs-action' || $itip_sending === 0; $error_msg = $this->gettext('errorimportingevent'); $success = false; diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js index a9c47e6c..e7bdfa7e 100644 --- a/plugins/calendar/calendar_ui.js +++ b/plugins/calendar/calendar_ui.js @@ -688,8 +688,8 @@ function rcube_calendar_ui(settings) var invite = $('#edit-attendees-invite').get(0); var comment = $('#edit-attendees-comment'); - notify.checked = has_attendees(event); - invite.checked = true; + invite.checked = settings.itip_notify & 1 > 0; + notify.checked = has_attendees(event) && invite.checked; if (event.allDay) { starttime.val("12:00").hide(); @@ -726,7 +726,7 @@ function rcube_calendar_ui(settings) event_attendees = []; attendees_list = $('#edit-attendees-table > tbody').html(''); resources_list = $('#edit-resources-table > tbody').html(''); - $('#edit-attendees-notify')[(notify.checked && allow_invitations ? 'show' : 'hide')](); + $('#edit-attendees-notify')[(allow_invitations && (settings.itip_notify & 2) ? 'show' : 'hide')](); $('#edit-localchanges-warning')[(has_attendees(event) && !(allow_invitations || (calendar.owner && is_organizer(event, calendar.owner))) ? 'show' : 'hide')](); var load_attendees_tab = function() @@ -743,8 +743,7 @@ function rcube_calendar_ui(settings) // make sure comment box is visible if at least one attendee has reply enabled // or global "send invitations" checkbox is checked - if (reply_selected || $('#edit-attendees-invite:checked').length) - $('p.attendees-commentbox').show(); + $('#eventedit .attendees-commentbox')[(reply_selected || invite.checked ? 'show' : 'hide')](); // select the correct organizer identity var identity_id = 0; @@ -840,7 +839,7 @@ function rcube_calendar_ui(settings) need_invitation = true; delete data.attendees[i]['noreply']; } - else { + else if (settings.itip_notify > 0) { data.attendees[i].noreply = 1; } } @@ -849,7 +848,7 @@ function rcube_calendar_ui(settings) // tell server to send notifications if ((data.attendees.length || (event.id && event.attendees.length)) && allow_invitations && (notify.checked || invite.checked || need_invitation)) { - data._notify = 1; + data._notify = settings.itip_notify; data._comment = comment.val(); } @@ -1924,7 +1923,7 @@ function rcube_calendar_ui(settings) // send invitation checkbox var invbox = ''; + + (!data.noreply && settings.itip_notify & 1 ? 'checked="checked" ' : '') + '/>'; if (data['delegated-to']) tooltip = rcmail.gettext('delegatedto', 'calendar') + data['delegated-to']; @@ -1941,7 +1940,7 @@ function rcube_calendar_ui(settings) '' + dispname + '' + '' + '' + Q(data.status || '') + '' + - (data.cutype != 'RESOURCE' ? '' + (organizer || readonly || !invbox ? '' : invbox) + '' : '') + + (data.cutype != 'RESOURCE' ? '' + (organizer || readonly || !invbox ? '' : invbox) + '' : '') + '' + (organizer || readonly ? '' : dellink) + ''; var table = rcmail.env.calendar_resources && data.cutype == 'RESOURCE' ? resources_list : attendees_list; @@ -1959,7 +1958,7 @@ function rcube_calendar_ui(settings) tr.find('a.expandlink').click(data, function(e) { me.expand_attendee_group(e, add_attendee, remove_attendee); }); tr.find('input.edit-attendee-reply').click(function() { var enabled = $('#edit-attendees-invite:checked').length || $('input.edit-attendee-reply:checked').length; - $('p.attendees-commentbox')[enabled ? 'show' : 'hide'](); + $('#eventedit .attendees-commentbox')[enabled ? 'show' : 'hide'](); }); // select organizer identity @@ -2338,7 +2337,7 @@ function rcube_calendar_ui(settings) // submit status change to server var submit_data = $.extend({}, me.selected_event, { source:null, comment:$('#reply-comment-event-rsvp').val() }), - noreply = $('#noreply-event-rsvp').prop('checked') ? 1 : 0; + noreply = $('#noreply-event-rsvp:checked').length ? 1 : 0; if (settings.invitation_calendars) { update_event('rsvp', submit_data, { status:response, noreply:noreply }); @@ -2431,17 +2430,23 @@ function rcube_calendar_ui(settings) // event has attendees, ask whether to notify them if (has_attendees(event)) { + var checked = (settings.itip_notify & 1 ? ' checked="checked"' : ''); if (is_organizer(event)) { notify = true; - html += '
' + - '
'; + if (settings.itip_notify & 2) { + html += '
' + + '
'; + } + else { + data._notify = settings.itip_notify; + } } else if (action == 'remove' && is_attendee(event)) { decline = true; html += '
' + - '
'; } @@ -2466,14 +2471,15 @@ function rcube_calendar_ui(settings) if (html) { var $dialog = $('
').html(html); - $dialog.find('a.button').button().click(function(e){ + $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 = notify && $dialog.find('input.confirm-attendees-donotify').get(0).checked ? 1 : 0; - if (decline && $dialog.find('input.confirm-attendees-decline:checked')) + data._notify = settings.itip_notify; + if ($dialog.find('input.confirm-attendees-donotify').length) + data._notify = $dialog.find('input.confirm-attendees-donotify').get(0).checked ? 1 : 0; + if (decline && $dialog.find('input.confirm-attendees-decline:checked').length) data.decline = 1; update_event(action, data); - $dialog.dialog("destroy").hide(); + $dialog.dialog("close"); return false; }); @@ -2483,7 +2489,7 @@ function rcube_calendar_ui(settings) buttons.push({ text: rcmail.gettext((action == 'remove' ? 'remove' : 'save'), 'calendar'), click: function() { - data._notify = notify && $dialog.find('input.confirm-attendees-donotify').get(0).checked ? 1 : 0; + data._notify = notify && $dialog.find('input.confirm-attendees-donotify:checked').length ? 1 : 0; data.decline = decline && $dialog.find('input.confirm-attendees-decline:checked').length ? 1 : 0; update_event(action, data); $(this).dialog("close"); @@ -3809,7 +3815,7 @@ function rcube_calendar_ui(settings) $('#edit-attendees-invite').change(function() { $('#edit-attendees-donotify,input.edit-attendee-reply').prop('checked', this.checked); // hide/show comment field - $('.attendees-commentbox')[this.checked ? 'show' : 'hide'](); + $('#eventedit .attendees-commentbox')[this.checked ? 'show' : 'hide'](); }); // delegate change event to "send invitations" checkbox diff --git a/plugins/calendar/config.inc.php.dist b/plugins/calendar/config.inc.php.dist index 5ac25f6b..32e1c74a 100644 --- a/plugins/calendar/config.inc.php.dist +++ b/plugins/calendar/config.inc.php.dist @@ -113,6 +113,21 @@ $config['calendar_allow_invite_shared'] = false; // this can be the case if invitations are sent to mailing lists or alias email addresses. $config['calendar_allow_itip_uninvited'] = true; +// controls the visibility/default of the checkbox controlling the sending of iTip invitations +// 0 = hidden + disabled +// 1 = hidden + active +// 2 = visible + unchecked +// 3 = visible + active +$config['calendar_itip_send_option'] = 3; + +// Action taken after iTip request is handled. Possible values: +// 0 - no action +// 1 - move to Trash +// 2 - delete the message +// 3 - flag as deleted +// folder_name - move the message to the specified folder +$config['calendar_itip_after_action'] = 0; + // enable asynchronous free-busy triggering after data changed $config['calendar_freebusy_trigger'] = false; @@ -145,12 +160,4 @@ $config['kolab_invitation_calendars'] = true; // LDAP directory configuration to find avilable resources for events // $config['calendar_resources_directory'] = array(/* ldap_public-like address book configuration */); -// Action taken after iTip request is handled. Possible values: -// 0 - no action -// 1 - move to Trash -// 2 - delete the message -// 3 - flag as deleted -// folder_name - move the message to the specified folder -$config['calendar_itip_after_action'] = 0; - ?> diff --git a/plugins/calendar/lib/calendar_ui.php b/plugins/calendar/lib/calendar_ui.php index 291f365c..e66e5f85 100644 --- a/plugins/calendar/lib/calendar_ui.php +++ b/plugins/calendar/lib/calendar_ui.php @@ -2,12 +2,11 @@ /** * User Interface class for the Calendar plugin * - * @version @package_version@ * @author Lazlo Westerhof * @author Thomas Bruederli * * Copyright (C) 2010, Lazlo Westerhof - * Copyright (C) 2012, Kolab Systems AG + * Copyright (C) 2014, Kolab Systems AG * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -706,11 +705,18 @@ class calendar_ui $table->add_header('availability', $this->cal->gettext('availability')); $table->add_header('confirmstate', $this->cal->gettext('confirmstate')); if ($invitations) { - $table->add_header(array('class' => 'sendmail', 'title' => $this->cal->gettext('sendinvitations')), + $table->add_header(array('class' => 'invite', 'title' => $this->cal->gettext('sendinvitations')), $invite->show(1) . html::label('edit-attendees-invite', $this->cal->gettext('sendinvitations'))); } $table->add_header('options', ''); + // hide invite column if disabled by config + $itip_notify = (int)$this->rc->config->get('calendar_itip_send_option', $this->cal->defaults['calendar_itip_send_option']); + if ($invitations && !($itip_notify & 2)) { + $css = sprintf('#%s td.invite, #%s th.invite { display:none !important }', $attrib['id'], $attrib['id']); + $this->rc->output->add_footer(html::tag('style', array('type' => 'text/css'), $css)); + } + return $table->show($attrib); } diff --git a/plugins/calendar/skins/classic/calendar.css b/plugins/calendar/skins/classic/calendar.css index 3e789001..a4371bfe 100644 --- a/plugins/calendar/skins/classic/calendar.css +++ b/plugins/calendar/skins/classic/calendar.css @@ -836,8 +836,8 @@ td.topalign { padding-right: 4px; } -.edit-attendees-table th.sendmail, -.edit-attendees-table td.sendmail { +.edit-attendees-table th.invite, +.edit-attendees-table td.invite { width: 24px; padding: 2px; white-space: nowrap; @@ -845,7 +845,7 @@ td.topalign { text-overflow: hidden; } -#eventedit .edit-attendees-table th.sendmail label { +#eventedit .edit-attendees-table th.invite label { display: none; } diff --git a/plugins/calendar/skins/larry/calendar.css b/plugins/calendar/skins/larry/calendar.css index 0700455a..17efff5c 100644 --- a/plugins/calendar/skins/larry/calendar.css +++ b/plugins/calendar/skins/larry/calendar.css @@ -978,13 +978,13 @@ td.topalign { padding: 2px 4px; } -#eventedit .edit-attendees-table th.sendmail, -#eventedit .edit-attendees-table td.sendmail { +#eventedit .edit-attendees-table th.invite, +#eventedit .edit-attendees-table td.invite { width: 44px; padding: 2px; } -#eventedit .edit-attendees-table th.sendmail label { +#eventedit .edit-attendees-table th.invite label { display: inline-block; position: relative; top: 4px; diff --git a/plugins/libcalendaring/lib/libcalendaring_itip.php b/plugins/libcalendaring/lib/libcalendaring_itip.php index 6ff1229d..ce686557 100644 --- a/plugins/libcalendaring/lib/libcalendaring_itip.php +++ b/plugins/libcalendaring/lib/libcalendaring_itip.php @@ -563,11 +563,19 @@ class libcalendaring_itip */ public function itip_rsvp_options_ui($dom_id, $disable = false) { + $itip_sending = $this->rc->config->get('calendar_itip_send_option', 3); + + // itip sending is entirely disabled + if ($itip_sending === 0) { + return ''; + } // add checkbox to suppress itip reply message - $rsvp_additions = html::label(array('class' => 'noreply-toggle'), - html::tag('input', array('type' => 'checkbox', 'id' => 'noreply-'.$dom_id, 'value' => 1, 'disabled' => $disable)) - . ' ' . $this->gettext('itipsuppressreply') - ); + else if ($itip_sending >= 2) { + $rsvp_additions = html::label(array('class' => 'noreply-toggle'), + html::tag('input', array('type' => 'checkbox', 'id' => 'noreply-'.$dom_id, 'value' => 1, 'disabled' => $disable, 'checked' => ($itip_sending & 1) == 0)) + . ' ' . $this->gettext('itipsuppressreply') + ); + } // add input field for reply comment $rsvp_additions .= html::a(array('href' => '#toggle', 'class' => 'reply-comment-toggle'), $this->gettext('itipeditresponse')); diff --git a/plugins/libcalendaring/libcalendaring.js b/plugins/libcalendaring/libcalendaring.js index 39b34ae7..cd06827a 100644 --- a/plugins/libcalendaring/libcalendaring.js +++ b/plugins/libcalendaring/libcalendaring.js @@ -805,7 +805,7 @@ rcube_libcalendaring.add_from_itip_mail = function(mime_id, task, status, dom_id var noreply = 0, comment = ''; if (dom_id) { - noreply = $('#noreply-'+dom_id).prop('checked') ? 1 : 0; + noreply = $('#noreply-'+dom_id+':checked').length ? 1 : 0; if (!noreply) comment = $('#reply-comment-'+dom_id).val(); } diff --git a/plugins/libcalendaring/skins/larry/libcal.css b/plugins/libcalendaring/skins/larry/libcal.css index 7cfe630f..89e123ff 100644 --- a/plugins/libcalendaring/skins/larry/libcal.css +++ b/plugins/libcalendaring/skins/larry/libcal.css @@ -59,10 +59,13 @@ span.edit-alarm-set { a.reply-comment-toggle { display: inline-block; - margin-left: 1em; color: #666; } +label.noreply-toggle + a.reply-comment-toggle { + margin-left: 1em; +} + .itip-reply-comment textarea { display: block; width: 90%; diff --git a/plugins/tasklist/skins/larry/tasklist.css b/plugins/tasklist/skins/larry/tasklist.css index 0ffaf966..026067c4 100644 --- a/plugins/tasklist/skins/larry/tasklist.css +++ b/plugins/tasklist/skins/larry/tasklist.css @@ -892,13 +892,13 @@ a.morelink:hover { text-align: right; } -#taskedit .edit-attendees-table th.sendmail, -#taskedit .edit-attendees-table td.sendmail { +#taskedit .edit-attendees-table th.invite, +#taskedit .edit-attendees-table td.invite { width: 48px; padding: 2px; } -#taskedit .edit-attendees-table th.sendmail label { +#taskedit .edit-attendees-table th.invite label { display: inline-block; position: relative; top: 4px; diff --git a/plugins/tasklist/tasklist.js b/plugins/tasklist/tasklist.js index 6b88867e..82dd9c42 100644 --- a/plugins/tasklist/tasklist.js +++ b/plugins/tasklist/tasklist.js @@ -542,7 +542,7 @@ function rcube_tasklist_ui(settings) t: me.selected_task, filter: filtermask, status: response, - noreply: $('#noreply-task-rsvp').prop('checked') ? 1 : 0, + noreply: $('#noreply-task-rsvp:checked').length ? 1 : 0, comment: $('#reply-comment-task-rsvp').val() }); @@ -637,7 +637,7 @@ function rcube_tasklist_ui(settings) $('#edit-attendees-invite').change(function() { $('#edit-attendees-donotify,input.edit-attendee-reply').prop('checked', this.checked); // hide/show comment field - $('.attendees-commentbox')[this.checked ? 'show' : 'hide'](); + $('#taskeditform .attendees-commentbox')[this.checked ? 'show' : 'hide'](); }); // delegate change task to "send invitations" checkbox @@ -1076,17 +1076,28 @@ function rcube_tasklist_ui(settings) var save_task_confirm = function(rec, action, updates) { var data = $.extend({}, rec, updates || {}), - notify = false, partstat = false, html = ''; + notify = false, partstat = false, html = '', + do_confirm = settings.itip_notify & 2; // task has attendees, ask whether to notify them if (has_attendees(rec) && is_organizer(rec)) { notify = true; - html = rcmail.gettext('changeconfirmnotifications', 'tasklist'); + if (do_confirm) { + html = rcmail.gettext('changeconfirmnotifications', 'tasklist'); + } + else { + data._notify = settings.itip_notify; + } } // ask whether to change my partstat and notify organizer else if (data._status_before !== undefined && data.status && data._status_before != data.status && is_attendee(rec)) { partstat = true; - html = rcmail.gettext('partstatupdatenotification', 'tasklist'); + if (do_confirm) { + html = rcmail.gettext('partstatupdatenotification', 'tasklist'); + } + else if (settings.itip_notify & 1) { + data._reportpartstat = data.status == 'CANCELLED' ? 'DECLINED' : data.status; + } } // remove to avoid endless recursion @@ -1622,7 +1633,7 @@ function rcube_tasklist_ui(settings) // send invitation checkbox var invbox = ''; + + (!data.noreply && settings.itip_notify & 1 ? 'checked="checked" ' : '') + '/>'; if (data['delegated-to']) tooltip = rcmail.gettext('delegatedto', 'tasklist') + data['delegated-to']; @@ -1637,7 +1648,7 @@ function rcube_tasklist_ui(settings) var html = '' + dispname + '' + '' + Q(data.status || '') + '' + - (data.cutype != 'RESOURCE' ? '' + (readonly || !invbox ? '' : invbox) + '' : '') + + (data.cutype != 'RESOURCE' ? '' + (readonly || !invbox ? '' : invbox) + '' : '') + '' + (readonly ? '' : dellink) + ''; var tr = $('') @@ -1654,7 +1665,7 @@ function rcube_tasklist_ui(settings) tr.find('a.expandlink').click(data, function(e) { me.expand_attendee_group(e, add_attendee, remove_attendee); }); tr.find('input.edit-attendee-reply').click(function() { var enabled = $('#edit-attendees-invite:checked').length || $('input.edit-attendee-reply:checked').length; - $('p.attendees-commentbox')[enabled ? 'show' : 'hide'](); + $('#taskeditform .attendees-commentbox')[enabled ? 'show' : 'hide'](); }); task_attendees.push(data); @@ -1940,8 +1951,8 @@ function rcube_tasklist_ui(settings) var invite = $('#edit-attendees-invite').get(0); var comment = $('#edit-attendees-comment'); - notify.checked = has_attendees(rec); - invite.checked = true; + invite.checked = settings.itip_notify & 1 > 0; + notify.checked = has_attendees(rec) && invite.checked; // tag-edit line var tagline = $(rcmail.gui_objects.edittagline).empty(); @@ -1974,7 +1985,7 @@ function rcube_tasklist_ui(settings) task_attendees = []; attendees_list = $('#edit-attendees-table > tbody').html(''); - $('#edit-attendees-notify')[(notify.checked && allow_invitations ? 'show' : 'hide')](); + $('#edit-attendees-notify')[(allow_invitations && (settings.itip_notify & 2) ? 'show' : 'hide')](); $('#edit-localchanges-warning')[(has_attendees(rec) && !(allow_invitations || (rec.owner && is_organizer(rec, rec.owner))) ? 'show' : 'hide')](); // attendees (aka assignees) @@ -1992,14 +2003,12 @@ function rcube_tasklist_ui(settings) // make sure comment box is visible if at least one attendee has reply enabled // or global "send invitations" checkbox is checked - if (reply_selected || $('#edit-attendees-invite:checked').length) { - $('p.attendees-commentbox').show(); - } + $('#taskeditform .attendees-commentbox')[(reply_selected || invite.checked ? 'show' : 'hide')](); // select the correct organizer identity var identity_id = 0; $.each(settings.identities, function(i,v) { - if (rec.organizer && v == rec.organizer.email) { + if (!rec.organizer || v == rec.organizer.email) { identity_id = i; return false; } @@ -2112,7 +2121,7 @@ function rcube_tasklist_ui(settings) need_invitation = true; delete data.attendees[i]['noreply']; } - else { + else if (settings.itip_notify > 0) { data.attendees[i].noreply = 1; } } @@ -2121,9 +2130,12 @@ function rcube_tasklist_ui(settings) // tell server to send notifications if ((data.attendees.length || (rec.id && rec.attendees.length)) && allow_invitations && (notify.checked || invite.checked || need_invitation)) { - data._notify = 1; + data._notify = settings.itip_notify; data._comment = comment.val(); } + else if (data._notify) { + delete data._notify; + } if (save_task(data, action)) $dialog.dialog('close'); diff --git a/plugins/tasklist/tasklist.php b/plugins/tasklist/tasklist.php index fe8c5c36..fb881391 100644 --- a/plugins/tasklist/tasklist.php +++ b/plugins/tasklist/tasklist.php @@ -203,6 +203,10 @@ class tasklist extends rcube_plugin $oldrec = $rec; $success = $refresh = false; + // force notify if hidden + active + if ((int)$this->rc->config->get('calendar_itip_send_option', 3) === 1 && empty($rec['_reportpartstat'])) + $rec['_notify'] = 1; + switch ($action) { case 'new': $oldrec = null; @@ -575,7 +579,8 @@ class tasklist extends rcube_plugin } // set organizer from identity selector - if (isset($rec['_identity']) && ($identity = $this->rc->user->get_identity($rec['_identity']))) { + if ((isset($rec['_identity']) || (!empty($rec['attendees']) && empty($rec['organizer']))) && + ($identity = $this->rc->user->get_identity($rec['_identity']))) { $rec['organizer'] = array('name' => $identity['name'], 'email' => $identity['email']); } @@ -696,6 +701,7 @@ class tasklist extends rcube_plugin $itip = $this->load_itip(); $emails = $this->lib->get_user_emails(); + $itip_notify = (int)$this->rc->config->get('calendar_itip_send_option', 3); // add comment to the iTip attachment $task['comment'] = $comment; @@ -725,7 +731,7 @@ class tasklist extends rcube_plugin } // skip if notification is disabled for this attendee - if ($attendee['noreply']) { + if ($attendee['noreply'] && $itip_notify & 2) { continue; } diff --git a/plugins/tasklist/tasklist_ui.php b/plugins/tasklist/tasklist_ui.php index f3a2bb63..8d4170af 100644 --- a/plugins/tasklist/tasklist_ui.php +++ b/plugins/tasklist/tasklist_ui.php @@ -72,6 +72,7 @@ class tasklist_ui $settings = array(); $settings['invite_shared'] = (int)$this->rc->config->get('calendar_allow_invite_shared', 0); + $settings['itip_notify'] = (int)$this->rc->config->get('calendar_itip_send_option', 3); $settings['sort_col'] = $this->rc->config->get('tasklist_sort_col', ''); $settings['sort_order'] = $this->rc->config->get('tasklist_sort_order', 'asc'); @@ -450,11 +451,18 @@ class tasklist_ui $table->add_header('name', $this->plugin->gettext($attrib['coltitle'] ?: 'attendee')); $table->add_header('confirmstate', $this->plugin->gettext('confirmstate')); if ($invitations) { - $table->add_header(array('class' => 'sendmail', 'title' => $this->plugin->gettext('sendinvitations')), + $table->add_header(array('class' => 'invite', 'title' => $this->plugin->gettext('sendinvitations')), $invite->show(1) . html::label('edit-attendees-invite', $this->plugin->gettext('sendinvitations'))); } $table->add_header('options', ''); + // hide invite column if disabled by config + $itip_notify = (int)$this->rc->config->get('calendar_itip_send_option', 3); + if ($invitations && !($itip_notify & 2)) { + $css = sprintf('#%s td.invite, #%s th.invite { display:none !important }', $attrib['id'], $attrib['id']); + $this->rc->output->add_footer(html::tag('style', array('type' => 'text/css'), $css)); + } + return $table->show($attrib); }