Start implementing Assignments (Attendees) tab for tasks (#1165)

This commit is contained in:
Aleksander Machniak 2014-07-23 14:35:52 +02:00
parent 5b26d69e20
commit c0da6448fb
5 changed files with 552 additions and 30 deletions

View file

@ -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';

View file

@ -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;
}

View file

@ -1,7 +1,7 @@
<div id="taskedit" class="uidialog uidialog-tabbed">
<form id="taskeditform" action="#" method="post" enctype="multipart/form-data">
<ul>
<li><a href="#taskedit-panel-main"><roundcube:label name="tasklist.tabsummary" /></a></li><li><a href="#taskedit-panel-recurrence"><roundcube:label name="tasklist.tabrecurrence" /></a></li><li id="taskedit-tab-attachments"><a href="#taskedit-panel-attachments"><roundcube:label name="tasklist.tabattachments" /></a></li>
<li><a href="#taskedit-panel-main"><roundcube:label name="tasklist.tabsummary" /></a></li><li><a href="#taskedit-panel-recurrence"><roundcube:label name="tasklist.tabrecurrence" /></a></li><li id="edit-tab-attendees"><a href="#taskedit-panel-attendees"><roundcube:label name="tasklist.tabassignments" /></a></li><li id="taskedit-tab-attachments"><a href="#taskedit-panel-attachments"><roundcube:label name="tasklist.tabattachments" /></a></li>
</ul>
<!-- basic info -->
<div id="taskedit-panel-main">
@ -79,6 +79,13 @@
<roundcube:object name="plugin.recurrence_form" part="rdate" class="form-section" />
</div>
</div>
<!-- attendees list (assignments) -->
<div id="taskedit-panel-attendees">
<h3 id="aria-label-attendeestable" class="voice"><roundcube:label name="tasklist.arialabeleventassignments" /></h3>
<roundcube:object name="plugin.attendees_list" id="edit-attendees-table" class="records-table edit-attendees-table" coltitle="attendee" aria-labelledby="aria-label-attendeestable" />
<roundcube:object name="plugin.attendees_form" id="edit-attendees-form" />
<roundcube:include file="/templates/freebusylegend.html" />
</div>
<!-- attachments list (with upload form) -->
<div id="taskedit-panel-attachments">
<div id="taskedit-attachments">
@ -91,4 +98,5 @@
<roundcube:object name="plugin.filedroparea" id="taskedit-tab-2" />
</div>
</form>
<roundcube:object name="plugin.edit_attendees_notify" id="edit-attendees-notify" class="taskedit-dialog-message" style="display:none" />
</div>

View file

@ -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 = '<a href="mailto:' + data.email + '" title="' + Q(data.email) + '" class="mailtolink" data-cutype="' + data.cutype + '">' + dispname + '</a>';
// 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 = '<select class="edit-attendee-role"' + (organizer || readonly ? ' disabled="true"' : '') + ' aria-label="' + rcmail.gettext('role','tasklist') + '">';
for (var r in opts)
select += '<option value="'+ r +'" class="' + r.toLowerCase() + '"' + (data.role == r ? ' selected="selected"' : '') +'>' + Q(opts[r]) + '</option>';
select += '</select>';
// availability
var avail = data.email ? 'loading' : 'unknown';
// delete icon
var icon = rcmail.env.deleteicon ? '<img src="' + rcmail.env.deleteicon + '" alt="" />' : rcmail.gettext('delete');
var dellink = '<a href="#delete" class="iconlink delete deletelink" title="' + Q(rcmail.gettext('delete')) + '">' + icon + '</a>';
var tooltip = data.status || '';
// send invitation checkbox
var invbox = '<input type="checkbox" class="edit-attendee-reply" value="' + Q(data.email) +'" title="' + Q(rcmail.gettext('tasklist.sendinvitations')) + '" '
+ (!data.noreply ? 'checked="checked" ' : '') + '/>';
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 = '<td class="role">' + select + '</td>' +
'<td class="name">' + dispname + '</td>' +
// '<td class="availability"><img src="./program/resources/blank.gif" class="availabilityicon ' + avail + '" data-email="' + data.email + '" alt="" /></td>' +
'<td class="confirmstate"><span class="' + String(data.status).toLowerCase() + '" title="' + Q(tooltip) + '">' + Q(data.status || '') + '</span></td>' +
(data.cutype != 'RESOURCE' ? '<td class="sendmail">' + (organizer || readonly || !invbox ? '' : invbox) + '</td>' : '') +
'<td class="options">' + (organizer || readonly ? '' : dellink) + '</td>';
var table = rcmail.env.tasklist_resources && data.cutype == 'RESOURCE' ? resources_list : attendees_list;
var tr = $('<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);

View file

@ -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')));
}
}