Elastic: Redesign mail compose page - use recipient selection dialog (#6413)

pull/6486/head
Aleksander Machniak 6 years ago
parent 2dcf50019c
commit 6dfb475a26

@ -72,9 +72,29 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
rcmail.addEventListener('insertrow', function(data, evt) { plugin_vcard_insertrow(data); });
if ((rcmail.env.action == 'compose' || (rcmail.env.task == 'addressbook' && rcmail.env.action == '')) && rcmail.gui_objects.contactslist) {
if (rcmail.env.action == 'compose')
if (rcmail.env.action == 'compose') {
rcmail.env.compose_commands.push('attach-vcard');
// Elastic: add "Attach vCard" button to the attachments widget
if (window.UI && UI.recipient_selector) {
var button, form = $('#compose-attachments > div');
button = $('<button class="btn btn-secondary attach vcard">')
.attr('tabindex', $('button,input', form).first().attr('tabindex') || 0)
.text(rcmail.gettext('vcard_attachments.attachvcard'))
.appendTo(form)
.click(function() {
UI.recipient_selector('', {
title: 'vcard_attachments.attachvcard',
button: 'vcard_attachments.attachvcard',
button_class: 'attach',
focus: button,
multiselect: false,
action: function() { rcmail.command('attach-vcard'); }
});
});
}
}
rcmail.register_command('attach-vcard', function() { plugin_vcard_attach(); });
rcmail.contact_list.addEventListener('select', function(list) {
// TODO: support attaching more than one at once

@ -291,6 +291,8 @@ $labels['keyexpired'] = 'Expired';
$labels['keyrevoked'] = 'Revoked';
$labels['bccinstead'] = 'Use Bcc';
$labels['addheader'] = 'Add recipient (header)';
$labels['insert'] = 'Insert';
$labels['insertcontact'] = 'Insert contact(s)';
$labels['recipient'] = 'Recipient';
$labels['recipientedit'] = 'Recipient edit';

@ -74,7 +74,7 @@
// Listings
@color-list: @color-font;
@color-list-selected: inherit;
@color-list-selected: @color-font;
@color-list-selected-background: tint(@color-main, 90%);
@color-list-flagged: @color-error;
@color-list-deleted: lighten(@color-black, 50%);

@ -99,6 +99,9 @@ button.btn {
&.attach:before {
content: @fa-var-paperclip;
}
&.attach.vcard:before {
content: @fa-var-user;
}
&.no:before,
&.close:before,
&.cancel:before {
@ -132,6 +135,9 @@ button.btn {
&.select:before {
.font-icon-regular(@fa-var-check-circle);
}
&.insert.recipient:before {
content: @fa-var-user-plus;
}
}
a.btn,

@ -70,6 +70,21 @@ font.bold {
}
}
}
.popup & {
height: 100%;
display: flex;
flex-direction: column;
.scroller {
flex: 1;
}
.footer {
border-top: 1px solid @color-layout-border;
background-color: @color-searchbar-background;
}
}
}
.contact-header {

@ -15,6 +15,7 @@
display: none;
padding: 0;
min-width: 180px;
height: 100%;
li > a {
width: 100%;

@ -617,6 +617,9 @@ html.ms .propform {
&.add:before {
content: @fa-var-plus;
}
&.add.recipient:before {
content: @fa-var-users;
}
&.search:before {
content: @fa-var-search;
}

@ -134,8 +134,6 @@
}
#messagebody {
// TODO
&.mailvelope {
margin: 0;
}
@ -310,3 +308,7 @@
}
}
}
#compose-attachments {
margin: .5rem .5rem 0 .5rem;
}

@ -167,15 +167,6 @@
&.refresh:before {
content: @fa-var-sync;
}
&.addto:before {
content: @fa-var-user-plus;
}
&.addcc:before {
content: @fa-var-user-plus;
}
&.addbcc:before {
content: @fa-var-user-plus;
}
&.addressbook:before {
content: @fa-var-user;
}
@ -234,7 +225,7 @@
&.pagenav {
display: flex;
justify-content: normal !important;
justify-content: space-between;
align-items: center;
a.button {

@ -3,46 +3,33 @@
<roundcube:add_label name="recipientsadded" />
<roundcube:add_label name="nocontactselected" />
<roundcube:add_label name="recipient" />
<roundcube:add_label name="insert" />
<roundcube:add_label name="insertcontact" />
<roundcube:add_label name="recipientedit" />
<h1 class="voice"><roundcube:label name="compose" /></h1>
<!-- inline address book -->
<div class="sidebar listbox" role="region" aria-labelledby="aria-label-composecontacts">
<div class="header no-toolbar">
<a class="button icon back-content-button" href="#content" data-hidden="big"><span class="inner"><roundcube:label name="back" /></span></a>
<span id="aria-label-composecontacts" class="header-title"><roundcube:label name="contacts" /></span>
</div>
<roundcube:object name="searchform" id="searchform" wrapper="searchbar toolbar"
label="contactsearchform" buttontitle="findcontacts" ariatag="h2" />
<div class="scroller" tabindex="-1">
<roundcube:object name="addressbooks" id="directorylist" class="treelist listing iconized"
summary="ariasummarycomposecontacts" />
<roundcube:object name="addresslist" id="contacts-table" class="listing iconized contactlist"
noheader="true" role="listbox" data-list="contact_list" />
</div>
<div class="footer toolbar" role="toolbar">
<roundcube:button command="add-recipient" prop="to" type="link" title="to"
class="button addto disabled" classAct="button addto" innerClass="inner" content="To+" />
<roundcube:button command="add-recipient" prop="cc" type="link" title="cc"
class="button addcc disabled" classAct="button addcc" innerClass="inner" content="Cc+" />
<roundcube:button command="add-recipient" prop="bcc" type="link" title="bcc"
class="button addbcc disabled" classAct="button addbcc" innerClass="inner" content="Bcc+" />
<roundcube:container name="compose-contacts-toolbar" id="compose-contacts-toolbar" />
</div>
<roundcube:include file="includes/pagenav.html" />
</div>
<!-- compose options and attachments list -->
<div class="list listbox">
<div class="sidebar listbox">
<div class="header">
<a class="button icon back-content-button" href="#content" data-hidden="big"><span class="inner"><roundcube:label name="back" /></span></a>
<span class="header-title all-sizes"><roundcube:label name="optionsandattachments" /></span>
</div>
<div class="scroller">
<!-- attachments -->
<div id="compose-attachments" class="file-upload" role="region" aria-labelledby="aria-label-compose-attachments">
<h2 id="aria-label-compose-attachments" class="voice"><roundcube:label name="attachments" /></h2>
<div class="upload-form">
<roundcube:object name="composeAttachmentForm" mode="hint" />
<button class="btn btn-secondary attach" tabindex="2" href="#" onclick="rcmail.upload_input('uploadform')"><roundcube:label name="addattachment" /></button>
</div>
<roundcube:object name="composeAttachmentList" id="attachment-list" class="attachmentslist" tabindex="2" />
<roundcube:object name="fileDropArea" id="compose-attachments" />
</div>
<!-- compose options -->
<div id="compose-options" class="formcontent" role="region" aria-labelledby="aria-label-composeoptions">
<h2 id="aria-label-composeoptions" class="voice"><roundcube:label name="arialabelcomposeoptions" /></h2>
<roundcube:container name="composeoptions" id="compose-options" />
<roundcube:if condition="!in_array('mdn_default', (array)config:dont_override)" />
<div class="form-group row form-check">
<label for="compose-mdn" class="col-form-label col-6"><roundcube:label name="returnreceipt" /></label>
@ -73,7 +60,6 @@
</div>
</div>
<roundcube:endif />
<roundcube:container name="composeoptions" id="compose-options" />
<roundcube:if condition="!in_array('htmleditor', (array)config:dont_override)" />
<div class="form-group row hidden">
<label for="editor-selector" class="col-form-label col-6"><roundcube:label name="editortype" /></label>
@ -83,15 +69,6 @@
</div>
<roundcube:endif />
</div>
<div id="compose-attachments" class="file-upload" role="region" aria-labelledby="aria-label-compose-attachments">
<h2 id="aria-label-compose-attachments" class="voice"><roundcube:label name="attachments" /></h2>
<div class="upload-form">
<roundcube:object name="composeAttachmentForm" mode="hint" />
<button class="btn btn-secondary attach" tabindex="2" href="#" onclick="rcmail.upload_input('uploadform')"><roundcube:label name="addattachment" /></button>
</div>
<roundcube:object name="composeAttachmentList" id="attachment-list" class="attachmentslist" tabindex="2" />
<roundcube:object name="fileDropArea" id="compose-attachments" />
</div>
</div>
</div>
@ -102,12 +79,9 @@
<span class="header-title"><roundcube:label name="compose" /></span>
<!-- toolbar -->
<div id="messagetoolbar" class="toolbar" role="toolbar" aria-labelledby="aria-label-toolbar">
<a class="button settings" href="#options" onclick="UI.show_list(true)" data-hidden="big">
<a class="button settings" href="#options" onclick="UI.show_sidebar()" data-hidden="big">
<span class="inner"><roundcube:label name="optionsandattachments"></span>
</a>
<a class="button addressbook" href="#contacts" onclick="UI.show_sidebar()" data-hidden="big">
<span class="inner"><roundcube:label name="contacts"></span>
</a>
<roundcube:button command="savedraft" type="link" class="button save draft disabled" classAct="button save draft"
label="save" title="savemessage" tabindex="2" innerclass="inner" data-content-button="true" />
<span class="spacer"></span>
@ -120,12 +94,6 @@
<a href="#responses" class="button responses" label="responses" title="<roundcube:label name='insertresponse' />" unselectable="on" tabindex="2" data-popup="responses-menu">
<span class="inner"><roundcube:label name="responses" /></span>
</a>
<a id="composeoptionslink" class="button settings hidden" href="#options" onclick="UI.show_list(); $(this).addClass('hidden'); $('#composecontactslink').removeClass('hidden')" data-hidden="large,small">
<span class="inner"><roundcube:label name="options"></span>
</a>
<a id="composecontactslink" class="button addressbook" href="#contacts" onclick="UI.show_sidebar(true); $(this).addClass('hidden'); $('#composeoptionslink').removeClass('hidden')" data-hidden="large,small">
<span class="inner"><roundcube:label name="contacts"></span>
</a>
<roundcube:if condition="config:enable_spellcheck" />
<span class="dropbutton">
<roundcube:button command="spellcheck" type="link" class="button spellcheck disabled"
@ -169,6 +137,9 @@
<div class="col-10">
<div class="input-group">
<roundcube:object name="composeHeaders" part="to" id="_to" form="form" tabindex="1" aria-required="true" data-recipient-input="true" />
<span class="input-group-append">
<a href="#add-contact" onclick="UI.recipient_selector('to')" class="input-group-text icon add recipient" title="<roundcube:label name="addcontact" />" tabindex="1"><span class="inner"><roundcube:label name="addcontact" /></span></a>
</span>
<span class="input-group-append">
<a href="#add-header" data-popup="headers-menu" class="input-group-text icon add" title="<roundcube:label name="addheader" />" tabindex="1"><span class="inner"><roundcube:label name="addheader" /></span></a>
</span>
@ -181,7 +152,10 @@
<div class="input-group">
<roundcube:object name="composeHeaders" part="cc" id="_cc" form="form" tabindex="1" data-recipient-input="true" />
<span class="input-group-append">
<a href="#delete" onclick="UI.header_reset('_cc')" class="input-group-text icon cancel" title="<roundcube:label name='delete' />" tabindex="1"><span class="inner"><roundcube:label name="delete" /></span></a>
<a href="#add-contact" onclick="UI.recipient_selector('cc')" class="input-group-text icon add recipient" title="<roundcube:label name="addcontact" />" tabindex="1"><span class="inner"><roundcube:label name="addcontact" /></span></a>
</span>
<span class="input-group-append">
<a href="#delete" onclick="UI.header_reset('_cc')" class="input-group-text icon delete" title="<roundcube:label name='delete' />" tabindex="1"><span class="inner"><roundcube:label name="delete" /></span></a>
</span>
</div>
</div>
@ -192,7 +166,10 @@
<div class="input-group">
<roundcube:object name="composeHeaders" part="bcc" id="_bcc" form="form" tabindex="1" data-recipient-input="true" />
<span class="input-group-append">
<a href="#delete" onclick="UI.header_reset('_bcc')" class="input-group-text icon cancel" title="<roundcube:label name='delete' />" tabindex="1"><span class="inner"><roundcube:label name="delete" /></span></a>
<a href="#add-contact" onclick="UI.recipient_selector('bcc')" class="input-group-text icon add recipient" title="<roundcube:label name="addcontact" />" tabindex="1"><span class="inner"><roundcube:label name="addcontact" /></span></a>
</span>
<span class="input-group-append">
<a href="#delete" onclick="UI.header_reset('_bcc')" class="input-group-text icon delete" title="<roundcube:label name='delete' />" tabindex="1"><span class="inner"><roundcube:label name="delete" /></span></a>
</span>
</div>
</div>
@ -203,7 +180,10 @@
<div class="input-group">
<roundcube:object name="composeHeaders" part="replyto" id="_replyto" form="form" tabindex="1" data-recipient-input="true" />
<span class="input-group-append">
<a href="#delete" onclick="UI.header_reset('_replyto')" class="input-group-text icon cancel" title="<roundcube:label name='delete' />" tabindex="1"><span class="inner"><roundcube:label name="delete" /></span></a>
<a href="#add-contact" onclick="UI.recipient_selector('replyto')" class="input-group-text icon add recipient" title="<roundcube:label name="addcontact" />" tabindex="1"><span class="inner"><roundcube:label name="addcontact" /></span></a>
</span>
<span class="input-group-append">
<a href="#delete" onclick="UI.header_reset('_replyto')" class="input-group-text icon delete" title="<roundcube:label name='delete' />" tabindex="1"><span class="inner"><roundcube:label name="delete" /></span></a>
</span>
</div>
</div>
@ -214,7 +194,10 @@
<div class="input-group">
<roundcube:object name="composeHeaders" part="followupto" id="_followupto" form="form" tabindex="1" data-recipient-input="true" />
<span class="input-group-append">
<a href="#delete" onclick="UI.header_reset('_followupto')" class="input-group-text icon cancel" title="<roundcube:label name='delete' />" tabindex="1"><span class="inner"><roundcube:label name="delete" /></span></a>
<a href="#add-contact" onclick="UI.recipient_selector('followupto')" class="input-group-text icon add recipient" title="<roundcube:label name="addcontact" />" tabindex="1"><span class="inner"><roundcube:label name="addcontact" /></span></a>
</span>
<span class="input-group-append">
<a href="#delete" onclick="UI.header_reset('_followupto')" class="input-group-text icon delete" title="<roundcube:label name='delete' />" tabindex="1"><span class="inner"><roundcube:label name="delete" /></span></a>
</span>
</div>
</div>
@ -281,4 +264,18 @@
</ul>
</div>
<div id="recipient-dialog" class="popupmenu" role="region" aria-labelledby="aria-label-composecontacts">
<div class="listbox">
<roundcube:object name="searchform" id="searchform" wrapper="searchbar toolbar"
label="contactsearchform" buttontitle="findcontacts" ariatag="h2" class="no-bs" />
<div class="scroller" tabindex="-1">
<roundcube:object name="addressbooks" id="directorylist" class="treelist listing iconized"
summary="ariasummarycomposecontacts" />
<roundcube:object name="addresslist" id="contacts-table" class="listing iconized contactlist"
noheader="true" role="listbox" data-list="contact_list" data-list-select-replace="#recipient-dialog .pagenav-text" />
</div>
<roundcube:include file="includes/pagenav.html" />
</div>
</div>
<roundcube:include file="includes/footer.html" />

@ -67,6 +67,7 @@ function rcube_elastic_ui()
this.header_reset = header_reset;
this.attachmentmenu = attachmentmenu;
this.mailtomenu = mailtomenu;
this.recipient_selector = recipient_selector;
this.show_list = show_list;
this.show_sidebar = show_sidebar;
this.smart_field_init = smart_field_init;
@ -494,7 +495,8 @@ function rcube_elastic_ui()
list = table.data('list');
if (rcmail[list] && rcmail[list].multiselect) {
var button, parent = table.parents('.sidebar,.list,.content').last(),
var repl, button,
parent = table.parents('.sidebar,.list,.content').last(),
header = parent.find('.header'),
toolbar = header.find('ul');
@ -525,9 +527,14 @@ function rcube_elastic_ui()
}
}
else {
button.appendTo(toolbar).addClass('icon');
if (!parent.is('.sidebar')) {
button.addClass('toolbar-button');
if (repl = table.data('list-select-replace')) {
$(repl).replaceWith(button);
}
else {
button.appendTo(toolbar).addClass('icon');
if (!parent.is('.sidebar')) {
button.addClass('toolbar-button');
}
}
}
}
@ -759,7 +766,7 @@ function rcube_elastic_ui()
}
// Forms
var supported_controls = 'input:not(.button,[type=button],[type=file],[type=radio],[type=checkbox]),textarea';
var supported_controls = 'input:not(.button,.no-bs,[type=button],[type=file],[type=radio],[type=checkbox]),textarea';
$(supported_controls, $('.propform', context)).addClass('form-control');
$('[type=checkbox]', $('.propform', context)).addClass('form-check-input');
@ -2760,6 +2767,62 @@ function rcube_elastic_ui()
.closest('.form-group').nextAll(':not(.hidden)').first().find('input').focus();
};
/**
* Recipient (contact) selector
*/
function recipient_selector(field, opts)
{
if (!opts) opts = {};
var title = rcmail.gettext(opts.title || 'insertcontact'),
dialog = $('#recipient-dialog'),
parent = dialog.parent(),
close_func = function() {
if (dialog.is(':visible')) {
rcmail.env.recipient_dialog.dialog('close');
}
},
insert_func = function() {
if (opts.action) {
opts.action();
close_func();
return;
}
rcmail.command('add-recipient');
};
if (!rcmail.env.recipient_selector_initialized) {
rcmail.addEventListener('add-recipient', close_func);
rcmail.env.recipient_selector_initialized = true;
}
if (field) {
rcmail.env.focused_field = '#_' + field;
}
rcmail.contact_list.clear_selection();
rcmail.contact_list.multiselect = 'multiselect' in opts ? opts.multiselect : true;
rcmail.env.recipient_dialog = rcmail.simple_dialog(dialog, title, insert_func, {
button: rcmail.gettext(opts.button || 'insert'),
button_class: opts.button_class || 'insert recipient',
height: 600,
classes: {
'ui-dialog-content': 'p-0' // remove padding on dialog content
},
open: function() {
// Don't want focus in the search field, we focus first contacts source record instead
$('#directorylist a:first').focus();
},
close: function() {
dialog.appendTo(parent);
$(this).remove();
$(opts.focus || rcmail.env.focused_field).focus();
}
});
};
/**
* Create/Update quota widget (setquota event handler)
*/

Loading…
Cancel
Save