Partial invitations handling, participants autocompletion (T726, T729)
This commit is contained in:
parent
9d32f5cbae
commit
48ddb0eea4
5 changed files with 277 additions and 16 deletions
|
@ -1125,7 +1125,9 @@ function manticore_init()
|
||||||
var info = rcmail.env.file_data;
|
var info = rcmail.env.file_data;
|
||||||
|
|
||||||
rcmail.enable_command('document-save', 'document-export', true);
|
rcmail.enable_command('document-save', 'document-export', true);
|
||||||
rcmail.enable_command('files-close', info && info.session && info.session.is_owner);
|
|
||||||
|
if (info && info.session && info.session.is_owner)
|
||||||
|
rcmail.enable_command('files-close', 'document-editors', true);
|
||||||
};
|
};
|
||||||
|
|
||||||
rcube_webmail.prototype.document_save = function()
|
rcube_webmail.prototype.document_save = function()
|
||||||
|
@ -1138,6 +1140,144 @@ rcube_webmail.prototype.document_export = function(type)
|
||||||
manticore.export(type || 'odt');
|
manticore.export(type || 'odt');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
rcube_webmail.prototype.document_editors = function()
|
||||||
|
{
|
||||||
|
var info = rcmail.env.file_data;
|
||||||
|
|
||||||
|
if (!info || !info.session || !info.session.is_owner)
|
||||||
|
return;
|
||||||
|
|
||||||
|
kolab_files_editors_dialog(info.session);
|
||||||
|
};
|
||||||
|
|
||||||
|
// close editing session
|
||||||
|
rcube_webmail.prototype.files_close = function()
|
||||||
|
{
|
||||||
|
// @todo: check document "unsaved changes" state and display a warning
|
||||||
|
file_api.document_delete(this.env.file_data.session.id);
|
||||||
|
};
|
||||||
|
|
||||||
|
// document editors management dialog
|
||||||
|
function kolab_files_editors_dialog(session)
|
||||||
|
{
|
||||||
|
var ac_props, items = [], buttons = {},
|
||||||
|
dialog = $('#document-editors-dialog');
|
||||||
|
|
||||||
|
// always add the session organizer
|
||||||
|
items.push(kolab_files_attendee_record(session.owner, 'organizer'));
|
||||||
|
|
||||||
|
$.each(session.invitations || [], function() {
|
||||||
|
items.push(kolab_files_attendee_record(this.user, this.status));
|
||||||
|
});
|
||||||
|
|
||||||
|
$('table > tbody', dialog).html(items);
|
||||||
|
|
||||||
|
buttons[rcmail.gettext('kolab_files.close')] = function() {
|
||||||
|
kolab_dialog_close(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
// show dialog window
|
||||||
|
kolab_dialog_show(dialog, {
|
||||||
|
title: rcmail.gettext('kolab_files.manageeditors'),
|
||||||
|
buttons: buttons,
|
||||||
|
button_classes: ['mainaction']
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!rcmail.env.editors_dialog) {
|
||||||
|
rcmail.env.editors_dialog = dialog;
|
||||||
|
|
||||||
|
// init attendees autocompletion
|
||||||
|
if (rcmail.env.autocomplete_threads > 0) {
|
||||||
|
ac_props = {
|
||||||
|
threads: rcmail.env.autocomplete_threads,
|
||||||
|
sources: rcmail.env.autocomplete_sources
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
rcmail.init_address_input_events($('#invitation-editor-name'), ac_props);
|
||||||
|
|
||||||
|
rcmail.addEventListener('autocomplete_insert', function(e) {
|
||||||
|
var success = false;
|
||||||
|
if (e.field.name == 'participant') {
|
||||||
|
success = kolab_files_add_attendees(e.insert, 'invited', e.data && e.data.type == 'group' ? 'GROUP' : 'INDIVIDUAL');
|
||||||
|
}
|
||||||
|
if (e.field && success) {
|
||||||
|
e.field.value = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#invitation-editor-add').click(function() {
|
||||||
|
var input = $('#invitation-editor-name');
|
||||||
|
rcmail.ksearch_blur();
|
||||||
|
if (kolab_files_add_attendees(input.val(), 'invited', 'INDIVIDUAL')) {
|
||||||
|
input.val('');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// add the given list of participants
|
||||||
|
function kolab_files_add_attendees(names)
|
||||||
|
{
|
||||||
|
var i, item, email, name, attendees = {}, counter = 0;
|
||||||
|
|
||||||
|
names = file_api.explode_quoted_string(names.replace(/,\s*$/, ''), ',');
|
||||||
|
|
||||||
|
// parse name/email pairs
|
||||||
|
for (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) {
|
||||||
|
attendees[email] = {user: email, name: name};
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
alert(rcmail.gettext('noemailwarning'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove already existing entries
|
||||||
|
if (counter) {
|
||||||
|
if (attendees[rcmail.env.file_data.session.owner]) {
|
||||||
|
delete attendees[this.user];
|
||||||
|
counter--;
|
||||||
|
}
|
||||||
|
$.each(rcmail.env.file_data.session.invitations || [], function() {
|
||||||
|
if (this.user in attendees) {
|
||||||
|
delete attendees[this.user];
|
||||||
|
counter--;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (counter)
|
||||||
|
file_api.document_invite(rcmail.env.file_data.session.id, attendees);
|
||||||
|
};
|
||||||
|
|
||||||
|
function kolab_files_attendee_record(user, status)
|
||||||
|
{
|
||||||
|
return $('<tr>').attr('class', 'invitation' + (status ? ' ' + status : ''))
|
||||||
|
.append($('<td class="name">').text(user))
|
||||||
|
.append($('<td class="status">').text(rcmail.gettext('kolab_files.status' + status)))
|
||||||
|
.append($('<td class="options">'));
|
||||||
|
// @todo: delete and accept button
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************/
|
/***********************************************************/
|
||||||
/********** Commands **********/
|
/********** Commands **********/
|
||||||
|
@ -1283,13 +1423,7 @@ rcube_webmail.prototype.files_edit = function(session)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// close editing session
|
// save changes to the file
|
||||||
rcube_webmail.prototype.files_close = function()
|
|
||||||
{
|
|
||||||
// @todo: check document "unsaved changes" state and display a warning
|
|
||||||
file_api.document_delete(this.env.file_data.session.id);
|
|
||||||
};
|
|
||||||
|
|
||||||
rcube_webmail.prototype.files_save = function()
|
rcube_webmail.prototype.files_save = function()
|
||||||
{
|
{
|
||||||
if (!this.file_editor)
|
if (!this.file_editor)
|
||||||
|
@ -2935,6 +3069,36 @@ function kolab_files_ui()
|
||||||
// @todo: force sessions info update
|
// @todo: force sessions info update
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Invite document session participants
|
||||||
|
this.document_invite = function(id, attendees)
|
||||||
|
{
|
||||||
|
var list = [];
|
||||||
|
|
||||||
|
// expect attendees to be email => name hash
|
||||||
|
$.each(attendees || {}, function() { list.push(this); });
|
||||||
|
|
||||||
|
if (list.length) {
|
||||||
|
this.req = this.set_busy(true, 'kolab_files.documentinviting');
|
||||||
|
this.request('document_invite', {id: id, users: list}, 'document_invite_response');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// document invite response handler
|
||||||
|
this.document_invite_response = function(response)
|
||||||
|
{
|
||||||
|
if (!this.response(response))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var info = rcmail.env.file_data,
|
||||||
|
table = $('#document-editors-dialog table > tbody');
|
||||||
|
|
||||||
|
$.each(response.list || {}, function() {
|
||||||
|
table.appned(kolab_files_attendee_record(this.user, this.status));
|
||||||
|
if (info.session && info.session.invitations)
|
||||||
|
info.session.invitations.push($.merge({status: 'invited'}, this));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// handle auth errors on folder list
|
// handle auth errors on folder list
|
||||||
this.folder_list_auth_errors = function(result)
|
this.folder_list_auth_errors = function(result)
|
||||||
{
|
{
|
||||||
|
|
|
@ -147,6 +147,7 @@ class kolab_files_engine
|
||||||
'file-edit-dialog' => array($this, 'file_edit_dialog'),
|
'file-edit-dialog' => array($this, 'file_edit_dialog'),
|
||||||
'filelist' => array($this, 'file_list'),
|
'filelist' => array($this, 'file_list'),
|
||||||
'filequotadisplay' => array($this, 'quota_display'),
|
'filequotadisplay' => array($this, 'quota_display'),
|
||||||
|
'document-editors-dialog' => array($this, 'document_editors_dialog'),
|
||||||
));
|
));
|
||||||
|
|
||||||
if ($this->rc->task != 'files') {
|
if ($this->rc->task != 'files') {
|
||||||
|
@ -342,6 +343,37 @@ class kolab_files_engine
|
||||||
return '<div></div>';
|
return '<div></div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Template object for dcument editors dialog
|
||||||
|
*/
|
||||||
|
public function document_editors_dialog($attrib)
|
||||||
|
{
|
||||||
|
$table = new html_table(array('cols' => 3, 'border' => 0, 'cellpadding' => 0, 'class' => 'records-table'));
|
||||||
|
|
||||||
|
$table->add_header('username', $this->plugin->gettext('participant'));
|
||||||
|
$table->add_header('status', $this->plugin->gettext('status'));
|
||||||
|
$table->add_header('options', null);
|
||||||
|
|
||||||
|
$input = new html_inputfield(array('name' => 'participant', 'id' => 'invitation-editor-name', 'size' => 30));
|
||||||
|
$textarea = new html_textarea(array('name' => 'comment', 'id' => 'invitation-comment',
|
||||||
|
'rows' => 4, 'cols' => 55, 'title' => $this->plugin->gettext('invitationtexttitle')));
|
||||||
|
$button = new html_inputfield(array('type' => 'button', 'class' => 'button', 'id' => 'invitation-editor-add', 'value' => $this->plugin->gettext('addparticipant')));
|
||||||
|
|
||||||
|
$this->plugin->add_label('close', 'manageeditors', 'statusorganizer', 'statusaccepted',
|
||||||
|
'statusinvited', 'statusdeclined', 'statusrequested'
|
||||||
|
);
|
||||||
|
|
||||||
|
// initialize attendees autocompletion
|
||||||
|
$this->rc->autocomplete_init();
|
||||||
|
|
||||||
|
return '<div>' . $table->show() . html::div(null,
|
||||||
|
html::div(null, $input->show() . " " . $button->show())
|
||||||
|
. html::p('attendees-commentbox', html::label(null,
|
||||||
|
$this->plugin->gettext('invitationtextlabel') . $textarea->show())
|
||||||
|
)
|
||||||
|
) . '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Template object for file_rename form
|
* Template object for file_rename form
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -49,6 +49,7 @@ $labels['createandedit'] = 'Create and Edit';
|
||||||
$labels['copyfile'] = 'Copy a file';
|
$labels['copyfile'] = 'Copy a file';
|
||||||
$labels['copyandedit'] = 'Copy and Edit';
|
$labels['copyandedit'] = 'Copy and Edit';
|
||||||
$labels['documenttitle'] = 'Title:';
|
$labels['documenttitle'] = 'Title:';
|
||||||
|
$labels['close'] = 'Close';
|
||||||
|
|
||||||
$labels['collection_audio'] = 'Audio';
|
$labels['collection_audio'] = 'Audio';
|
||||||
$labels['collection_video'] = 'Video';
|
$labels['collection_video'] = 'Video';
|
||||||
|
@ -104,6 +105,18 @@ $labels['select'] = 'Select';
|
||||||
$labels['terminatesession'] = 'Terminate the session';
|
$labels['terminatesession'] = 'Terminate the session';
|
||||||
$labels['terminate'] = 'Terminate';
|
$labels['terminate'] = 'Terminate';
|
||||||
$labels['sessionterminating'] = 'Terminating the session...';
|
$labels['sessionterminating'] = 'Terminating the session...';
|
||||||
|
$labels['manageeditors'] = 'Invite to document';
|
||||||
|
$labels['participant'] = 'Participant';
|
||||||
|
$labels['status'] = 'Status';
|
||||||
|
$labels['addparticipant'] = 'Add participant';
|
||||||
|
$labels['delparticipant'] = 'Remove participant';
|
||||||
|
$labels['invitationtexttitle'] = 'This comment will be attached to the invitation/notification message sent to the participant';
|
||||||
|
$labels['invitationtextlabel'] = 'Invitation/notification comment';
|
||||||
|
$labels['statusorganizer'] = 'Organizer';
|
||||||
|
$labels['statusinvited'] = 'Invited';
|
||||||
|
$labels['statusaccepted'] = 'Accepted';
|
||||||
|
$labels['statusdeclined'] = 'Declined';
|
||||||
|
$labels['statusrequested'] = 'Requested';
|
||||||
|
|
||||||
$labels['storepasswords'] = 'remember password';
|
$labels['storepasswords'] = 'remember password';
|
||||||
$labels['storepasswordsdesc'] = 'Stored passwords will be encrypted. Enable this if you do not want to be asked for the password on every login or you want this storage to be available via WebDAV.';
|
$labels['storepasswordsdesc'] = 'Stored passwords will be encrypted. Enable this if you do not want to be asked for the password on every login or you want this storage to be available via WebDAV.';
|
||||||
|
|
|
@ -82,6 +82,10 @@
|
||||||
text-shadow: 0 1px 1px #eee;
|
text-shadow: 0 1px 1px #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ul.toolbarmenu li span.saveas {
|
||||||
|
background: url(images/buttons.png) -5px -253px no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
#document-title {
|
#document-title {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
@ -102,6 +106,15 @@
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#collaborators a.button.add {
|
||||||
|
background: url(../../../../skins/larry/images/buttons.png) -5px -357px no-repeat;
|
||||||
|
min-width: 16px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
padding: 2px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
#quicksearchbar #filesearchmenulink {
|
#quicksearchbar #filesearchmenulink {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 5px;
|
top: 5px;
|
||||||
|
@ -400,7 +413,8 @@
|
||||||
#files-folder-mount-dialog,
|
#files-folder-mount-dialog,
|
||||||
#files-folder-auth-dialog,
|
#files-folder-auth-dialog,
|
||||||
#files-folder-create-dialog,
|
#files-folder-create-dialog,
|
||||||
#files-folder-edit-dialog {
|
#files-folder-edit-dialog,
|
||||||
|
#document-editors-dialog {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -489,10 +503,6 @@ a.filesaveall {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.toolbarmenu li span.saveas {
|
|
||||||
background: url(images/buttons.png) -5px -253px no-repeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.propform td.source.selected {
|
table.propform td.source.selected {
|
||||||
background-color: #c7e3ef;
|
background-color: #c7e3ef;
|
||||||
}
|
}
|
||||||
|
@ -542,3 +552,43 @@ table.propform td.source table.propform td {
|
||||||
.auth-options label {
|
.auth-options label {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#document-editors-dialog textarea {
|
||||||
|
width: 98%
|
||||||
|
}
|
||||||
|
|
||||||
|
#document-editors-dialog label {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#document-editors-dialog table {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#document-editors-dialog table th.status {
|
||||||
|
width: 9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#document-editors-dialog table th.options {
|
||||||
|
width: 40px
|
||||||
|
}
|
||||||
|
|
||||||
|
#document-editors-dialog table td {
|
||||||
|
padding-top: 4px;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#document-editors-dialog table td.name {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#document-editors-dialog table tr:last-child td {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#document-editors-dialog table tr.organizer td {
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
|
|
||||||
<h2 id="aria-label-collaborators" class="voice"><roundcube:label name="kolab_files.arialabelcollaborators" /></h2>
|
<h2 id="aria-label-collaborators" class="voice"><roundcube:label name="kolab_files.arialabelcollaborators" /></h2>
|
||||||
<div id="collaborators" class="toolbar" role="toolbar" aria-labelledby="aria-label-collaborators">
|
<div id="collaborators" class="toolbar" role="toolbar" aria-labelledby="aria-label-collaborators">
|
||||||
|
<roundcube:button command="document-editors" type="link" class="button add disabled" classAct="button add" classSel="button add pressed" content=" " title="kolab_files.manageeditors" />
|
||||||
<div id="members"></div>
|
<div id="members"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -49,11 +50,12 @@
|
||||||
<h3 id="aria-label-exportmenu" class="voice"><roundcube:label name="kolab_files.arialabelexportoptions" /></h3>
|
<h3 id="aria-label-exportmenu" class="voice"><roundcube:label name="kolab_files.arialabelexportoptions" /></h3>
|
||||||
<ul id="exportmenu-menu" class="toolbarmenu" role="menu" aria-labelledby="aria-label-exportmenu"></ul>
|
<ul id="exportmenu-menu" class="toolbarmenu" role="menu" aria-labelledby="aria-label-exportmenu"></ul>
|
||||||
</div>
|
</div>
|
||||||
<!--
|
|
||||||
<div id="editors-dialog" class="uidialog" data-editable="true" role="dialog" aria-labelledby="aria-label-doceditorsdialog" aria-hidden="true">
|
<div id="document-editors-dialog" class="uidialog" data-editable="true" role="dialog" aria-labelledby="aria-label-doceditorsdialog" aria-hidden="true">
|
||||||
<h3 id="aria-label-doceditorsdialog" class="voice"><roundcube:label name="kolab_files.arialabeldoceditorsdialog" /></h3>
|
<h3 id="aria-label-doceditorsdialog" class="voice"><roundcube:label name="kolab_files.arialabeldoceditorsdialog" /></h3>
|
||||||
|
<roundcube:object name="document-editors-dialog" />
|
||||||
</div>
|
</div>
|
||||||
-->
|
|
||||||
<roundcube:include file="/includes/footer.html" />
|
<roundcube:include file="/includes/footer.html" />
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
Loading…
Add table
Reference in a new issue