diff --git a/plugins/tasklist/localization/en_US.inc b/plugins/tasklist/localization/en_US.inc index 9fd0e3eb..7920c940 100644 --- a/plugins/tasklist/localization/en_US.inc +++ b/plugins/tasklist/localization/en_US.inc @@ -58,6 +58,7 @@ $labels['taskactions'] = 'Task options...'; $labels['tabsummary'] = 'Summary'; $labels['tabrecurrence'] = 'Recurrence'; +$labels['tabassignments'] = 'Assignments'; $labels['tabattachments'] = 'Attachments'; $labels['tabsharing'] = 'Sharing'; @@ -96,3 +97,38 @@ $labels['arialabellistsearchform'] = 'Tasklists search form'; $labels['arialabeltaskselector'] = 'List mode'; $labels['arialabeltasklisting'] = 'Tasks listing'; +// attendees +$labels['attendee'] = 'Participant'; +$labels['role'] = 'Role'; +$labels['availability'] = 'Avail.'; +$labels['confirmstate'] = 'Status'; +$labels['addattendee'] = 'Add participant'; +$labels['roleorganizer'] = 'Organizer'; +$labels['rolerequired'] = 'Required'; +$labels['roleoptional'] = 'Optional'; +$labels['rolechair'] = 'Chair'; +$labels['rolenonparticipant'] = 'Absent'; +$labels['sendinvitations'] = 'Send invitations'; +$labels['sendnotifications'] = 'Notify participants about modifications'; +$labels['sendcancellation'] = 'Notify participants about task cancellation'; +$labels['invitationsubject'] = 'You\'ve been invited to "$title"'; +$labels['invitationmailbody'] = "*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees\n\nPlease find attached an iCalendar file with all the task details which you can import to your tasks application."; +$labels['invitationattendlinks'] = "In case your email client doesn't support iTip requests you can use the following link to either accept or decline this invitation:\n\$url"; +$labels['eventupdatesubject'] = '"$title" has been updated'; +$labels['eventupdatesubjectempty'] = 'A task that concerns you has been updated'; +$labels['eventupdatemailbody'] = "*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees\n\nPlease find attached an iCalendar file with the updated task details which you can import to your tasks application."; +$labels['eventcancelsubject'] = '"$title" has been canceled'; +$labels['eventcancelmailbody'] = "*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees\n\nThe task has been cancelled by \$organizer.\n\nPlease find attached an iCalendar file with the updated task details."; + +// invitation handling (overrides labels from libcalendaring) +$labels['itipobjectnotfound'] = 'The task referred by this message was not found in your tasks list.'; + +$labels['itipmailbodyaccepted'] = "\$sender has accepted the assignment to the following task:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees"; +$labels['itipmailbodytentative'] = "\$sender has tentatively accepted the assignment to the following task:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees"; +$labels['itipmailbodydeclined'] = "\$sender has declined the assignment to the following task:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees"; +$labels['itipmailbodycancel'] = "\$sender has rejected your assignment to the following task:\n\n*\$title*\n\nWhen: \$date"; + +$labels['itipdeclineevent'] = 'Do you want to decline your assignment to this task?'; +$labels['declinedeleteconfirm'] = 'Do you also want to delete this declined task from your tasks list?'; +$labels['itipcomment'] = 'Invitation/notification comment'; +$labels['itipcommenttitle'] = 'This comment will be attached to the invitation/notification message sent to participants'; diff --git a/plugins/tasklist/skins/larry/tasklist.css b/plugins/tasklist/skins/larry/tasklist.css index e93a3113..1e847b35 100644 --- a/plugins/tasklist/skins/larry/tasklist.css +++ b/plugins/tasklist/skins/larry/tasklist.css @@ -849,6 +849,84 @@ a.morelink:hover { border-bottom: 2px solid #fafafa; } +.edit-attendees-table { + width: 100%; + margin-top: 0.5em; +} + +.edit-attendees-table th.role, +.edit-attendees-table td.role { + width: 9em; +} + +.edit-attendees-table th.availability, +.edit-attendees-table td.availability, +.edit-attendees-table th.confirmstate, +.edit-attendees-table td.confirmstate { + width: 4em; +} + +.edit-attendees-table th.options, +.edit-attendees-table td.options { + width: 16px; + padding: 2px 4px; +} + +.edit-attendees-table th.sendmail, +.edit-attendees-table td.sendmail { + width: 44px; + padding: 2px; +} + +.edit-attendees-table th.sendmail label { + display: inline-block; + position: relative; + top: 4px; + width: 24px; + height: 18px; + min-width: 24px; + padding: 0; + overflow: hidden; + text-indent: -5000px; + white-space: nowrap; + background: url(images/sendinvitation.png) 1px 0 no-repeat; +} + +.edit-attendees-table th.name, +.edit-attendees-table td.name { + width: auto; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.edit-attendees-table td.name select { + width: 100%; +} + +.edit-attendees-table a.deletelink { + display: inline-block; + width: 17px; + height: 17px; + padding: 0; + overflow: hidden; + text-indent: 1000px; +} + +#edit-attendees-form { + position: relative; + margin-top: 15px; +} + +#edit-attendees-form .attendees-invitebox { + text-align: right; + margin: 0; +} + +#edit-attendees-form .attendees-invitebox label { + padding-right: 3px; +} + #taskedit-attachments { margin: 0.6em 0; } @@ -954,4 +1032,3 @@ label.block { html.ie7 #taskedit-completeness-slider { display: inline; } - diff --git a/plugins/tasklist/skins/larry/templates/taskedit.html b/plugins/tasklist/skins/larry/templates/taskedit.html index c4b3c136..599974e3 100644 --- a/plugins/tasklist/skins/larry/templates/taskedit.html +++ b/plugins/tasklist/skins/larry/templates/taskedit.html @@ -1,7 +1,7 @@
@@ -79,6 +79,13 @@
+ +
+

+ + + +
@@ -91,4 +98,5 @@
+
diff --git a/plugins/tasklist/tasklist.js b/plugins/tasklist/tasklist.js index 0852e126..b0c95baf 100644 --- a/plugins/tasklist/tasklist.js +++ b/plugins/tasklist/tasklist.js @@ -82,6 +82,9 @@ function rcube_tasklist_ui(settings) var tasklists_widget; var focused_task; var focused_subclass; + var task_attendees = []; + var attendees_list; +// var resources_list; var me = this; // general datepicker settings @@ -541,6 +544,34 @@ function rcube_tasklist_ui(settings) if (sel) $(sel).val(''); return false; }); + + // init attendees autocompletion + var ac_props; + // parallel autocompletion + if (rcmail.env.autocomplete_threads > 0) { + ac_props = { + threads: rcmail.env.autocomplete_threads, + sources: rcmail.env.autocomplete_sources + }; + } + rcmail.init_address_input_events($('#edit-attendee-name'), ac_props); + rcmail.addEventListener('autocomplete_insert', function(e){ + if (e.field.name == 'participant') { + $('#edit-attendee-add').click(); + } +// else if (e.field.name == 'resource' && e.data && e.data.email) { +// add_attendee($.extend(e.data, { role:'REQ-PARTICIPANT', status:'NEEDS-ACTION', cutype:'RESOURCE' })); +// e.field.value = ''; +// } + }); + + $('#edit-attendee-add').click(function(){ + var input = $('#edit-attendee-name'); + rcmail.ksearch_blur(); + if (add_attendees(input.val(), { role:'REQ-PARTICIPANT', status:'NEEDS-ACTION', cutype:'INDIVIDUAL' })) { + input.val(''); + } + }); } /** @@ -1298,6 +1329,177 @@ function rcube_tasklist_ui(settings) scroll_timer = window.setTimeout(function(){ tasklist_drag_scroll(container, dir); }, scroll_speed); } + // check if the task has 'real' attendees, excluding the current user + var has_attendees = function(task) + { + return !!(task.attendees && task.attendees.length && (task.attendees.length > 1 || String(task.attendees[0].email).toLowerCase() != settings.identity.email)); + }; + + // check if the current user is an attendee of this task + var is_attendee = function(task, role, email) + { + var i, emails = email ? ';' + email.toLowerCase() : settings.identity.emails; + + for (i=0; task.attendees && i < task.attendees.length; i++) { + if ((!role || task.attendees[i].role == role) && task.attendees[i].email && emails.indexOf(';'+task.attendees[i].email.toLowerCase()) >= 0) + return task.attendees[i]; + } + + return false; + }; + + // check if the current user is the organizer + var is_organizer = function(task, email) + { + return is_attendee(task, 'ORGANIZER', email) || !task.id; + }; + + // add the given list of participants + var add_attendees = function(names, params) + { + names = explode_quoted_string(names.replace(/,\s*$/, ''), ','); + + // parse name/email pairs + var item, email, name, success = false; + for (var i=0; i < names.length; i++) { + email = name = ''; + item = $.trim(names[i]); + + if (!item.length) { + continue; + } // address in brackets without name (do nothing) + else if (item.match(/^<[^@]+@[^>]+>$/)) { + email = item.replace(/[<>]/g, ''); + } // address without brackets and without name (add brackets) + else if (rcube_check_email(item)) { + email = item; + } // address with name + else if (item.match(/([^\s<@]+@[^>]+)>*$/)) { + email = RegExp.$1; + name = item.replace(email, '').replace(/^["\s<>]+/, '').replace(/["\s<>]+$/, ''); + } + if (email) { + add_attendee($.extend({ email:email, name:name }, params)); + success = true; + } + else { + alert(rcmail.gettext('noemailwarning')); + } + } + + return success; + }; + + // add the given attendee to the list + var add_attendee = function(data, readonly) + { + if (!me.selected_task) + return false; + + // check for dupes... + var exists = false; + $.each(task_attendees, function(i, v) { exists |= (v.email == data.email); }); + if (exists) + return false; + + var list = me.selected_task && me.tasklists[me.selected_task.list] ? me.tasklists[me.selected_task.list] : me.tasklists[me.selected_list]; + + var dispname = Q(data.name || data.email); + if (data.email) + dispname = '' + dispname + ''; + + // role selection + var organizer = data.role == 'ORGANIZER'; + var opts = {}; + if (organizer) + opts.ORGANIZER = rcmail.gettext('.roleorganizer'); + opts['REQ-PARTICIPANT'] = rcmail.gettext('tasklist.rolerequired'); + opts['OPT-PARTICIPANT'] = rcmail.gettext('tasklist.roleoptional'); + opts['NON-PARTICIPANT'] = rcmail.gettext('tasklist.rolenonparticipant'); + + if (data.cutype != 'RESOURCE') + opts['CHAIR'] = rcmail.gettext('tasklist.rolechair'); + + if (organizer && !readonly) + dispname = rcmail.env['identities-selector']; + + var select = ''; + + // availability + var avail = data.email ? 'loading' : 'unknown'; + + // delete icon + var icon = rcmail.env.deleteicon ? '' : rcmail.gettext('delete'); + var dellink = '' + icon + ''; + var tooltip = data.status || ''; + + // send invitation checkbox + var invbox = ''; + + if (data['delegated-to']) + tooltip = rcmail.gettext('delegatedto', 'tasklist') + data['delegated-to']; + else if (data['delegated-from']) + tooltip = rcmail.gettext('delegatedfrom', 'tasklist') + data['delegated-from']; + + var html = '' + select + '' + + '' + dispname + '' + +// '' + + '' + Q(data.status || '') + '' + + (data.cutype != 'RESOURCE' ? '' + (organizer || readonly || !invbox ? '' : invbox) + '' : '') + + '' + (organizer || readonly ? '' : dellink) + ''; + + var table = rcmail.env.tasklist_resources && data.cutype == 'RESOURCE' ? resources_list : attendees_list; + var tr = $('') + .addClass(String(data.role).toLowerCase()) + .html(html) + .appendTo(table); + + tr.find('a.deletelink').click({ id:(data.email || data.name) }, function(e) { remove_attendee(this, e.data.id); return false; }); + tr.find('a.mailtolink').click(task_attendee_click); + 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'](); + }); + + // select organizer identity + if (data.identity_id) + $('#edit-identities-list').val(data.identity_id); + + // check free-busy status +// if (avail == 'loading') { +// check_freebusy_status(tr.find('img.availabilityicon'), data.email, me.selected_task); +// } + + task_attendees.push(data); + return true; + }; + + // event handler for clicks on an attendee link + var task_attendee_click = function(e) + { + var cutype = $(this).attr('data-cutype'), + mailto = this.href.substr(7); + + if (rcmail.env.calendar_resources && cutype == 'RESOURCE') { + event_resources_dialog(mailto); + } + else { + rcmail.redirect(rcmail.url('mail/compose', { _to:mailto })); + } + return false; + }; + + // remove an attendee from the list + var remove_attendee = function(elem, id) + { + $(elem).closest('tr').remove(); + task_attendees = $.grep(task_attendees, function(data) { return (data.name != id && data.email != id) }); + }; + /** * Show task details in a dialog */ @@ -1422,7 +1624,7 @@ function rcube_tasklist_ui(settings) return false; me.selected_task = $.extend({ valarms:[] }, rec); // clone task object - rec = me.selected_task; + rec = me.selected_task; // assign temporary id if (!me.selected_task.id) @@ -1442,6 +1644,12 @@ function rcube_tasklist_ui(settings) completeness_slider.slider('value', complete.val()); var taskstatus = $('#taskedit-status').val(rec.status || ''); var tasklist = $('#taskedit-tasklist').val(rec.list || me.selected_list).prop('disabled', rec.parent_id ? true : false); + var notify = $('#edit-attendees-donotify').get(0); + var invite = $('#edit-attendees-invite').get(0); + var comment = $('#edit-attendees-comment'); + + notify.checked = has_attendees(rec); + invite.checked = true; // tag-edit line var tagline = $(rcmail.gui_objects.edittagline).empty(); @@ -1468,6 +1676,49 @@ function rcube_tasklist_ui(settings) // set recurrence me.set_recurrence_edit(rec); + // init attendees tab + var organizer = !rec.attendees || is_organizer(rec), + allow_invitations = organizer || (rec.owner && rec.owner == 'anonymous') || settings.invite_shared; + + task_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-localchanges-warning')[(has_attendees(rec) && !(allow_invitations || (rec.owner && is_organizer(rec, rec.owner))) ? 'show' : 'hide')](); + + var load_attendees_tab = function() + { + var j, data, reply_selected = 0; + if (rec.attendees) { + for (j=0; j < rec.attendees.length; j++) { + data = rec.attendees[j]; + add_attendee(data, !allow_invitations); + if (allow_invitations && data.role != 'ORGANIZER' && !data.noreply) { + reply_selected++; + } + } + } + + // 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(); + } + + // select the correct organizer identity + var identity_id = 0; + $.each(settings.identities, function(i,v) { + if (organizer && v == organizer.email) { + identity_id = i; + return false; + } + }); + + $('#edit-identities-list').val(identity_id); + $('#edit-attendees-form')[(allow_invitations?'show':'hide')](); +// $('#edit-attendee-schedule')[(tasklist.freebusy?'show':'hide')](); + }; + // attachments rcmail.enable_command('remove-attachment', list.editable); me.selected_task.deleted_attachments = []; @@ -1491,23 +1742,26 @@ function rcube_tasklist_ui(settings) // define dialog buttons var buttons = {}; buttons[rcmail.gettext('save', 'tasklist')] = function() { + var data = me.selected_task; + // copy form field contents into task object to save $.each({ title:title, description:description, date:recdate, time:rectime, startdate:recstartdate, starttime:recstarttime, status:taskstatus, list:tasklist }, function(key,input){ - me.selected_task[key] = input.val(); + data[key] = input.val(); }); - me.selected_task.tags = []; - me.selected_task.attachments = []; - me.selected_task.valarms = me.serialize_alarms('#taskedit-alarms'); - me.selected_task.recurrence = me.serialize_recurrence(rectime.val()); + data.tags = []; + data.attachments = []; + data.attendees = task_attendees; + data.valarms = me.serialize_alarms('#taskedit-alarms'); + data.recurrence = me.serialize_recurrence(rectime.val()); // do some basic input validation - if (!me.selected_task.title || !me.selected_task.title.length) { + if (!data.title || !data.title.length) { title.focus(); return false; } - else if (me.selected_task.startdate && me.selected_task.date) { - var startdate = $.datepicker.parseDate(datepicker_settings.dateFormat, me.selected_task.startdate, datepicker_settings); - var duedate = $.datepicker.parseDate(datepicker_settings.dateFormat, me.selected_task.date, datepicker_settings); + else if (data.startdate && data.date) { + var startdate = $.datepicker.parseDate(datepicker_settings.dateFormat, data.startdate, datepicker_settings); + var duedate = $.datepicker.parseDate(datepicker_settings.dateFormat, data.date, datepicker_settings); if (startdate > duedate) { alert(rcmail.gettext('invalidstartduedates', 'tasklist')); return false; @@ -1515,38 +1769,76 @@ function rcube_tasklist_ui(settings) } // collect tags - $('input[type="hidden"]', rcmail.gui_objects.edittagline).each(function(i,elem){ + $('input[type="hidden"]', rcmail.gui_objects.edittagline).each(function(i,elem) { if (elem.value) - me.selected_task.tags.push(elem.value); + data.tags.push(elem.value); }); // including the "pending" one in the text box var newtag = $('#tagedit-input').val(); if (newtag != '') { - me.selected_task.tags.push(newtag); + data.tags.push(newtag); } // uploaded attachments list for (var i in rcmail.env.attachments) { if (i.match(/^rcmfile(.+)/)) - me.selected_task.attachments.push(RegExp.$1); + data.attachments.push(RegExp.$1); } // task assigned to a new list - if (me.selected_task.list && listdata[id] && me.selected_task.list != listdata[id].list) { - me.selected_task._fromlist = list.id; + if (data.list && listdata[id] && data.list != listdata[id].list) { + data._fromlist = list.id; } - me.selected_task.complete = complete.val() / 100; - if (isNaN(me.selected_task.complete)) - me.selected_task.complete = null; + data.complete = complete.val() / 100; + if (isNaN(data.complete)) + data.complete = null; - if (!me.selected_task.list && list.id) - me.selected_task.list = list.id; + if (!data.list && list.id) + data.list = list.id; - if (!me.selected_task.tags.length) - me.selected_task.tags = ''; + if (!data.tags.length) + data.tags = ''; - if (save_task(me.selected_task, action)) + // read attendee roles + $('select.edit-attendee-role').each(function(i, elem) { + if (data.attendees[i]) { + data.attendees[i].role = $(elem).val(); + } + }); + + if (organizer) { + data._identity = $('#edit-identities-list option:selected').val(); + } + + // don't submit attendees if only myself is added as organizer + if (data.attendees.length == 1 && data.attendees[0].role == 'ORGANIZER' && String(data.attendees[0].email).toLowerCase() == settings.identity.email) { + data.attendees = []; + } + + // per-attendee notification suppression + var need_invitation = false; + if (allow_invitations) { + $.each(data.attendees, function (i, v) { + if (v.role != 'ORGANIZER') { + if ($('input.edit-attendee-reply[value="' + v.email + '"]').prop('checked')) { + need_invitation = true; + delete data.attendees[i]['noreply']; + } + else { + data.attendees[i].noreply = 1; + } + } + }); + } + + // 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._comment = comment.val(); + } + + if (save_task(data, action)) $dialog.dialog('close'); }; @@ -1581,8 +1873,10 @@ function rcube_tasklist_ui(settings) // set dialog size according to content me.dialog_resize($dialog.get(0), $dialog.height(), 580); - } + if (tasklist.attendees) + window.setTimeout(load_attendees_tab, 1); + } /** * Open a task attachment either in a browser window for inline view or download it @@ -2060,6 +2354,29 @@ function rcube_tasklist_ui(settings) /**** Utility functions ****/ + // same as str.split(delimiter) but it ignores delimiters within quoted strings + var explode_quoted_string = function(str, delimiter) + { + var result = [], + strlen = str.length, + q, p, i, char, last; + + for (q = p = i = 0; i < strlen; i++) { + char = str.charAt(i); + if (char == '"' && last != '\\') { + q = !q; + } + else if (!q && char == delimiter) { + result.push(str.substring(p, i)); + p = i + 1; + } + last = char; + } + + result.push(str.substr(p)); + return result; + }; + /** * Clear any text selection * (text is probably selected when double-clicking somewhere) @@ -2205,7 +2522,7 @@ jQuery.unqiqueStrings = (function() { var rctasks; window.rcmail && rcmail.addEventListener('init', function(evt) { - rctasks = new rcube_tasklist_ui(rcmail.env.libcal_settings); + rctasks = new rcube_tasklist_ui($.extend(rcmail.env.tasklist_settings, rcmail.env.libcal_settings)); // register button commands rcmail.register_command('newtask', function(){ rctasks.edit_task(null, 'new', {}); }, true); diff --git a/plugins/tasklist/tasklist_ui.php b/plugins/tasklist/tasklist_ui.php index fc7320ef..4dd7b82b 100644 --- a/plugins/tasklist/tasklist_ui.php +++ b/plugins/tasklist/tasklist_ui.php @@ -55,10 +55,41 @@ class tasklist_ui $this->plugin->include_script('tasklist_base.js'); // copy config to client - // $this->rc->output->set_env('tasklist_settings', $settings); + $this->rc->output->set_env('tasklist_settings', $this->load_settings()); + + // initialize attendees autocompletion + $this->rc->autocomplete_init(); $this->ready = true; - } + } + + /** + * + */ + function load_settings() + { + $settings = array(); + + //$settings['invite_shared'] = (int)$this->rc->config->get('calendar_allow_invite_shared', $this->defaults['calendar_allow_invite_shared']); + + // get user identity to create default attendee + foreach ($this->rc->user->list_identities() as $rec) { + if (!$identity) + $identity = $rec; + + $identity['emails'][] = $rec['email']; + $settings['identities'][$rec['identity_id']] = $rec['email']; + } + + $identity['emails'][] = $this->rc->user->get_username(); + $settings['identity'] = array( + 'name' => $identity['name'], + 'email' => strtolower($identity['email']), + 'emails' => ';' . strtolower(join(';', $identity['emails'])) + ); + + return $settings; + } /** * Register handler methods for the template engine @@ -78,6 +109,9 @@ class tasklist_ui $this->plugin->register_handler('plugin.attachments_form', array($this, 'attachments_form')); $this->plugin->register_handler('plugin.attachments_list', array($this, 'attachments_list')); $this->plugin->register_handler('plugin.filedroparea', array($this, 'file_drop_area')); + $this->plugin->register_handler('plugin.attendees_list', array($this, 'attendees_list')); + $this->plugin->register_handler('plugin.attendees_form', array($this, 'attendees_form')); + $this->plugin->register_handler('plugin.edit_attendees_notify', array($this, 'edit_attendees_notify')); $this->plugin->include_script('jquery.tagedit.js'); $this->plugin->include_script('tasklist.js'); @@ -375,4 +409,54 @@ class tasklist_ui } } + /** + * + */ + function attendees_list($attrib = array()) + { + // add "noreply" checkbox to attendees table only + $invitations = strpos($attrib['id'], 'attend') !== false; + + $invite = new html_checkbox(array('value' => 1, 'id' => 'edit-attendees-invite')); + $table = new html_table(array('cols' => 4 + intval($invitations), 'border' => 0, 'cellpadding' => 0, 'class' => 'rectable')); + + $table->add_header('role', $this->plugin->gettext('role')); + $table->add_header('name', $this->plugin->gettext($attrib['coltitle'] ?: 'attendee')); +// $table->add_header('availability', $this->plugin->gettext('availability')); + $table->add_header('confirmstate', $this->plugin->gettext('confirmstate')); + if ($invitations) { + $table->add_header(array('class' => 'sendmail', 'title' => $this->plugin->gettext('sendinvitations')), + $invite->show(1) . html::label('edit-attendees-invite', $this->plugin->gettext('sendinvitations'))); + } + $table->add_header('options', ''); + + return $table->show($attrib); + } + + /** + * + */ + function attendees_form($attrib = array()) + { + $input = new html_inputfield(array('name' => 'participant', 'id' => 'edit-attendee-name', 'size' => 30)); + $textarea = new html_textarea(array('name' => 'comment', 'id' => 'edit-attendees-comment', + 'rows' => 4, 'cols' => 55, 'title' => $this->plugin->gettext('itipcommenttitle'))); + + return html::div($attrib, + html::div(null, $input->show() . " " . + html::tag('input', array('type' => 'button', 'class' => 'button', 'id' => 'edit-attendee-add', 'value' => $this->plugin->gettext('addattendee'))) + // . " " . html::tag('input', array('type' => 'button', 'class' => 'button', 'id' => 'edit-attendee-schedule', 'value' => $this->plugin->gettext('scheduletime').'...')) + ) . + html::p('attendees-commentbox', html::label(null, $this->plugin->gettext('itipcomment') . $textarea->show())) + ); + } + + /** + * + */ + function edit_attendees_notify($attrib = array()) + { + $checkbox = new html_checkbox(array('name' => '_notify', 'id' => 'edit-attendees-donotify', 'value' => 1)); + return html::div($attrib, html::label(null, $checkbox->show(1) . ' ' . $this->plugin->gettext('sendnotifications'))); + } }