Merge branch 'move_addressbook' of https://github.com/johndoh/roundcubemail into johndoh-move_addressbook

pull/6144/head
Aleksander Machniak 7 years ago
commit eb0228ba86

@ -19,4 +19,5 @@ $labels['addvcardmsg'] = 'Add vCard to addressbook';
$labels['vcardsavefailed'] = 'Unable to save vCard'; $labels['vcardsavefailed'] = 'Unable to save vCard';
$labels['attachvcard'] = 'Attach vCard'; $labels['attachvcard'] = 'Attach vCard';
$labels['vcard'] = 'vCard'; $labels['vcard'] = 'vCard';
$labels['forwardvcard'] = 'Forward vCard';
?> ?>

@ -22,5 +22,6 @@ $labels['vcardsavefailed'] = 'Unable to save vCard';
$labels['attachvcard'] = 'Attach vCard'; $labels['attachvcard'] = 'Attach vCard';
$labels['vcardattached'] = 'vCard file attached.'; $labels['vcardattached'] = 'vCard file attached.';
$labels['vcard'] = 'vCard'; $labels['vcard'] = 'vCard';
$labels['forwardvcard'] = 'Forward vCard';
?> ?>

@ -39,3 +39,8 @@ p.vcardattachment button {
.messagelist tr .attachment span.attachment.vcard { .messagelist tr .attachment span.attachment.vcard {
background: url(vcard.png) 0 center no-repeat; background: url(vcard.png) 0 center no-repeat;
} }
#contactmenu li a.vcard {
background: url(../../../../skins/classic/images/messageicons.png) no-repeat 7px 0;
background-position: 6px -168px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

@ -33,3 +33,8 @@ a.listbutton.vcard .inner
.messagelist tbody tr .attachment span.attachment.vcard { .messagelist tbody tr .attachment span.attachment.vcard {
background: url(vcard.png) 0 center no-repeat; background: url(vcard.png) 0 center no-repeat;
} }
ul.toolbarmenu li span.vcard {
background: url(listicons.png) no-repeat 7px 0;
background-position: 0 -3px;
}

@ -9,7 +9,7 @@
*/ */
class vcard_attachments extends rcube_plugin class vcard_attachments extends rcube_plugin
{ {
public $task = 'mail'; public $task = 'mail|addressbook';
private $message; private $message;
private $vcard_parts = array(); private $vcard_parts = array();
@ -19,6 +19,23 @@ class vcard_attachments extends rcube_plugin
{ {
$rcmail = rcmail::get_instance(); $rcmail = rcmail::get_instance();
if ($rcmail->task == 'addressbook') {
$skin_path = $this->local_skin_path();
$this->add_texts('localization', true);
$this->include_stylesheet($skin_path . '/style.css');
$this->include_script('vcardattach.js');
$this->add_button(
array(
'type' => 'link-menuitem',
'label' => 'vcard_attachments.forwardvcard',
'command' => 'attach-vcard',
'class' => 'icon vcard',
'classact' => 'icon vcard active',
'innerclass' => 'icon vcard',
),
'contactmenu');
}
else {
if ($rcmail->action == 'show' || $rcmail->action == 'preview') { if ($rcmail->action == 'show' || $rcmail->action == 'preview') {
$this->add_hook('message_load', array($this, 'message_load')); $this->add_hook('message_load', array($this, 'message_load'));
$this->add_hook('message_objects', array($this, 'message_objects')); $this->add_hook('message_objects', array($this, 'message_objects'));
@ -45,12 +62,15 @@ class vcard_attachments extends rcube_plugin
'innerclass' => 'inner', 'innerclass' => 'inner',
), ),
'compose-contacts-toolbar'); 'compose-contacts-toolbar');
$this->add_hook('message_compose', array($this, 'message_compose'));
} }
else if (!$rcmail->output->framed && (!$rcmail->action || $rcmail->action == 'list')) { else if (!$rcmail->output->framed && (!$rcmail->action || $rcmail->action == 'list')) {
$skin_path = $this->local_skin_path(); $skin_path = $this->local_skin_path();
$this->include_stylesheet($skin_path . '/style.css'); $this->include_stylesheet($skin_path . '/style.css');
$this->include_script('vcardattach.js'); $this->include_script('vcardattach.js');
} }
}
$this->register_action('plugin.savevcard', array($this, 'save_vcard')); $this->register_action('plugin.savevcard', array($this, 'save_vcard'));
} }
@ -129,6 +149,20 @@ class vcard_attachments extends rcube_plugin
return $p; return $p;
} }
/**
* This callback function adds a vCard to the message when attached from the Address book
*/
function message_compose($p)
{
if (rcube_utils::get_input_value('_attach_vcard', rcube_utils::INPUT_GET) == '1' && ($uri = rcube_utils::get_input_value('_uri', rcube_utils::INPUT_GET))) {
if ($attachment = $this->attach_vcard(array('compose_id' => $p['compose_id'], 'uri' => $uri))) {
$p['attachments'][] = $attachment;
};
}
return $p;
}
/** /**
* This callback function removes message part's content * This callback function removes message part's content
* for parts that are vcards * for parts that are vcards
@ -268,7 +302,7 @@ class vcard_attachments extends rcube_plugin
public function attach_vcard($args) public function attach_vcard($args)
{ {
if (preg_match('|^vcard://(.+)$|', $args['uri'], $m)) { if (preg_match('|^vcard://(.+)$|', $args['uri'], $m)) {
list($cid, $source) = explode('-', $m[1]); list($source, $cid, $email) = explode('-', $m[1]);
$vcard = $this->get_contact_vcard($source, $cid, $filename); $vcard = $this->get_contact_vcard($source, $cid, $filename);
$params = array( $params = array(

@ -34,33 +34,47 @@ function plugin_vcard_attach()
{ {
var id, n, contacts = [], var id, n, contacts = [],
ts = new Date().getTime(), ts = new Date().getTime(),
args = {_uploadid: ts, _id: rcmail.env.compose_id}, args = {_uploadid: ts, _id: rcmail.env.compose_id || null},
selection = rcmail.contact_list.get_selection(); selection = rcmail.contact_list.get_selection();
for (n=0; n < selection.length; n++) { for (n=0; n < selection.length; n++) {
if (rcmail.env.task == 'addressbook') {
id = selection[n];
contacts.push(rcmail.env.source + '-' + id + '-0');
}
else {
id = selection[n]; id = selection[n];
if (id && id.charAt(0) != 'E' && rcmail.env.contactdata[id]) if (id && id.charAt(0) != 'E' && rcmail.env.contactdata[id])
contacts.push(id); contacts.push(id);
} }
}
if (!contacts.length) if (!contacts.length)
return false; return false;
args._uri = 'vcard://' + contacts.join(','); args._uri = 'vcard://' + contacts.join(',');
if (rcmail.env.task == 'addressbook') {
args._attach_vcard = 1;
rcmail.open_compose_step(args);
}
else {
// add to attachments list // add to attachments list
if (!rcmail.add2attachment_list(ts, {name: '', html: rcmail.get_label('attaching'), classname: 'uploading', complete: false})) if (!rcmail.add2attachment_list(ts, {name: '', html: rcmail.get_label('attaching'), classname: 'uploading', complete: false}))
rcmail.file_upload_id = rcmail.set_busy(true, 'attaching'); rcmail.file_upload_id = rcmail.set_busy(true, 'attaching');
rcmail.http_post('upload', args); rcmail.http_post('upload', args);
}
} }
window.rcmail && rcmail.addEventListener('init', function(evt) { window.rcmail && rcmail.addEventListener('init', function(evt) {
if (rcmail.gui_objects.messagelist) if (rcmail.gui_objects.messagelist)
rcmail.addEventListener('insertrow', function(data, evt) { plugin_vcard_insertrow(data); }); rcmail.addEventListener('insertrow', function(data, evt) { plugin_vcard_insertrow(data); });
if (rcmail.env.action == 'compose' && rcmail.gui_objects.contactslist) { if ((rcmail.env.action == 'compose' || (rcmail.env.task == 'addressbook' && rcmail.env.action == '')) && rcmail.gui_objects.contactslist) {
if (rcmail.env.action == 'compose')
rcmail.env.compose_commands.push('attach-vcard'); rcmail.env.compose_commands.push('attach-vcard');
rcmail.register_command('attach-vcard', function() { plugin_vcard_attach(); }); rcmail.register_command('attach-vcard', function() { plugin_vcard_attach(); });
rcmail.contact_list.addEventListener('select', function(list) { rcmail.contact_list.addEventListener('select', function(list) {
// TODO: support attaching more than one at once // TODO: support attaching more than one at once

@ -47,6 +47,7 @@ function rcube_webmail()
this.group2expand = {}; this.group2expand = {};
this.http_request_jobs = {}; this.http_request_jobs = {};
this.menu_stack = []; this.menu_stack = [];
this.entity_selectors = [];
// webmail client settings // webmail client settings
this.dblclick_time = 500; this.dblclick_time = 500;
@ -979,14 +980,14 @@ function rcube_webmail()
if (this.task == 'mail') if (this.task == 'mail')
this.move_messages(props, event); this.move_messages(props, event);
else if (this.task == 'addressbook') else if (this.task == 'addressbook')
this.move_contacts(props); this.move_contacts(props, event);
break; break;
case 'copy': case 'copy':
if (this.task == 'mail') if (this.task == 'mail')
this.copy_messages(props, event); this.copy_messages(props, event);
else if (this.task == 'addressbook') else if (this.task == 'addressbook')
this.copy_contacts(props); this.copy_contacts(props, event);
break; break;
case 'mark': case 'mark':
@ -1233,7 +1234,7 @@ function rcube_webmail()
case 'print': case 'print':
if (this.task == 'addressbook') { if (this.task == 'addressbook') {
if (uid = this.contact_list.get_single_selection()) { if (uid = this.get_single_cid()) {
url = '&_action=print&_cid=' + uid; url = '&_action=print&_cid=' + uid;
if (this.env.source) if (this.env.source)
url += '&_source=' + urlencode(this.env.source); url += '&_source=' + urlencode(this.env.source);
@ -5903,15 +5904,21 @@ function rcube_webmail()
} }
this.env.selection_sources = $.unique(this.env.selection_sources); this.env.selection_sources = $.unique(this.env.selection_sources);
var groupcount = 0;
if (source.groups)
$.each(this.env.contactgroups, function(){ if (this.source === ref.env.source) groupcount++ });
} }
// if a group is currently selected, and there is at least one contact selected // if a group is currently selected, and there is at least one contact selected
// thend we can enable the group-remove-selected command // thend we can enable the group-remove-selected command
this.enable_command('group-assign-selected', groupcount > 0 && selected && writable);
this.enable_command('group-remove-selected', this.env.group && selected && writable); this.enable_command('group-remove-selected', this.env.group && selected && writable);
this.enable_command('print', selected == 1); this.enable_command('print', selected == 1);
this.enable_command('export-selected', 'copy', selected > 0); this.enable_command('export-selected', 'copy', selected > 0);
this.enable_command('edit', id && writable); this.enable_command('edit', id && writable);
this.enable_command('delete', 'move', selected && writable); this.enable_command('delete', 'move', selected && writable);
this.enable_command('qrcode', selected == 1);
return false; return false;
}; };
@ -5953,6 +5960,9 @@ function rcube_webmail()
this.env.address_group_stack = index < 0 ? [] : this.env.address_group_stack.slice(0, index); this.env.address_group_stack = index < 0 ? [] : this.env.address_group_stack.slice(0, index);
// remove cached contact group selector
this.destroy_entity_selector('contactgroup-selector');
// make sure the current group is on top of the stack // make sure the current group is on top of the stack
if (this.env.group) { if (this.env.group) {
if (!search) search = {}; if (!search) search = {};
@ -6130,8 +6140,15 @@ function rcube_webmail()
}; };
// copy contact(s) to the specified target (group or directory) // copy contact(s) to the specified target (group or directory)
this.copy_contacts = function(to) this.copy_contacts = function(to, event)
{ {
if (!to) {
return this.addressbook_selector(event, function(to, obj) {
var to = $(obj).data('source') ? ref.env.contactgroups['G' + $(obj).data('source') + $(obj).data('gid')] : ref.env.address_sources[to];
ref.command('copy', to);
});
}
var dest = to.type == 'group' ? to.source : to.id, var dest = to.type == 'group' ? to.source : to.id,
source = this.env.source, source = this.env.source,
group = this.env.group ? this.env.group : '', group = this.env.group ? this.env.group : '',
@ -6164,8 +6181,15 @@ function rcube_webmail()
}; };
// move contact(s) to the specified target (group or directory) // move contact(s) to the specified target (group or directory)
this.move_contacts = function(to) this.move_contacts = function(to, event)
{ {
if (!to) {
return this.addressbook_selector(event, function(to, obj) {
var to = $(obj).data('source') ? ref.env.contactgroups['G' + $(obj).data('source') + $(obj).data('gid')] : ref.env.address_sources[to];
ref.command('move', to);
});
}
var dest = to.type == 'group' ? to.source : to.id, var dest = to.type == 'group' ? to.source : to.id,
source = this.env.source, source = this.env.source,
group = this.env.group ? this.env.group : ''; group = this.env.group ? this.env.group : '';
@ -6392,6 +6416,10 @@ function rcube_webmail()
var key = 'G'+prop.source+prop.id; var key = 'G'+prop.source+prop.id;
if (this.treelist.remove(key)) { if (this.treelist.remove(key)) {
// make sure there is no cached address book or contact group selectors
this.destroy_entity_selector('addressbook-selector');
this.destroy_entity_selector('contactgroup-selector');
this.triggerEvent('group_delete', { source:prop.source, id:prop.id }); this.triggerEvent('group_delete', { source:prop.source, id:prop.id });
delete this.env.contactfolders[key]; delete this.env.contactfolders[key];
delete this.env.contactgroups[key]; delete this.env.contactgroups[key];
@ -6401,6 +6429,12 @@ function rcube_webmail()
this.list_contacts(prop.source, 0); this.list_contacts(prop.source, 0);
}; };
//assign selected contacts to a group
this.group_assign_selected = function(props, obj, event)
{
this.contactgroup_selector(event, function(to) { ref.group_member_change('add', ref.contact_list.get_selection(), ref.env.source, to); });
};
//remove selected contacts from current active group //remove selected contacts from current active group
this.group_remove_selected = function() this.group_remove_selected = function()
{ {
@ -6416,6 +6450,7 @@ function rcube_webmail()
for (n=0; n<selection.length; n++) { for (n=0; n<selection.length; n++) {
id = selection[n]; id = selection[n];
this.contact_list.remove_row(id, (n == selection.length-1)); this.contact_list.remove_row(id, (n == selection.length-1));
this.contact_list.clear_selection();
} }
} }
}; };
@ -6434,6 +6469,10 @@ function rcube_webmail()
this.env.contactfolders[key] = this.env.contactgroups[key] = prop; this.env.contactfolders[key] = this.env.contactgroups[key] = prop;
this.treelist.insert({ id:key, html:link, classes:['contactgroup'] }, prop.source, 'contactgroup'); this.treelist.insert({ id:key, html:link, classes:['contactgroup'] }, prop.source, 'contactgroup');
// make sure there is no cached address book or contact group selectors
this.destroy_entity_selector('addressbook-selector');
this.destroy_entity_selector('contactgroup-selector');
this.triggerEvent('group_insert', { id:prop.id, source:prop.source, name:prop.name, li:this.treelist.get_item(key) }); this.triggerEvent('group_insert', { id:prop.id, source:prop.source, name:prop.name, li:this.treelist.get_item(key) });
}; };
@ -6476,6 +6515,10 @@ function rcube_webmail()
// update list node and re-sort it // update list node and re-sort it
this.treelist.update(key, newnode, true); this.treelist.update(key, newnode, true);
// make sure there is no cached address book or contact group selectors
this.destroy_entity_selector('addressbook-selector');
this.destroy_entity_selector('contactgroup-selector');
this.triggerEvent('group_update', { id:prop.id, source:prop.source, name:prop.name, li:this.treelist.get_item(key), newid:prop.newid }); this.triggerEvent('group_update', { id:prop.id, source:prop.source, name:prop.name, li:this.treelist.get_item(key), newid:prop.newid });
}; };
@ -6834,7 +6877,7 @@ function rcube_webmail()
options = {button: false, cancel_button: 'close', width: 300, height: 300}, options = {button: false, cancel_button: 'close', width: 300, height: 300},
img = new Image(300, 300); img = new Image(300, 300);
img.src = this.url('addressbook/qrcode', {_source: this.env.source, _cid: this.env.cid}); img.src = this.url('addressbook/qrcode', {_source: this.env.source, _cid: this.get_single_cid()});
return this.simple_dialog(img, title, null, options); return this.simple_dialog(img, title, null, options);
}; };
@ -8174,27 +8217,14 @@ function rcube_webmail()
elem.onclick = function() { ref.command('show-headers', '', elem); }; elem.onclick = function() { ref.command('show-headers', '', elem); };
}; };
// create folder selector popup, position and display it // create folder selector popup
this.folder_selector = function(event, callback) this.folder_selector = function(event, callback)
{ {
var container = this.folder_selector_element; this.entity_selector('folder-selector', callback, this.env.mailboxes_list, function(obj, a) {
if (!container) {
var rows = [],
delim = this.env.delimiter,
ul = $('<ul class="toolbarmenu">'),
link = document.createElement('a');
container = $('<div id="folder-selector" class="popupmenu"></div>');
link.href = '#';
link.className = 'icon';
// loop over sorted folders list
$.each(this.env.mailboxes_list, function() {
var n = 0, s = 0, var n = 0, s = 0,
folder = ref.env.mailboxes[this], delim = ref.env.delimiter,
folder = ref.env.mailboxes[obj],
id = folder.id, id = folder.id,
a = $(link.cloneNode(false)).attr('rel', folder.id),
row = $('<li>'); row = $('<li>');
if (folder.virtual) if (folder.virtual)
@ -8214,8 +8244,86 @@ function rcube_webmail()
// add folder name element // add folder name element
a.append($('<span>').text(folder.name)); a.append($('<span>').text(folder.name));
row.append(a); return row.append(a);
rows.push(row); }, event);
};
// create addressbook selector popup
this.addressbook_selector = function(event, callback)
{
// build addressbook + groups list
var combined_sources = [];
// check we really need it before processing
if (!this.entity_selectors['addressbook-selector']) {
$.each(this.env.address_sources, function() {
if (!this.readonly) {
var source = this;
combined_sources.push(source);
$.each(ref.env.contactgroups, function() {
if (source.id === this.source) {
combined_sources.push(this);
}
});
}
});
}
this.entity_selector('addressbook-selector', callback, combined_sources, function(obj, a) {
var row = $('<li>');
if (obj.type == 'group') {
a.attr('rel', this.source + ':' + this.id);
a.addClass('contactgroup');
a.data('source', this.source).data('gid', this.id);
a.addClass('active').data('id', this.source + ':' + this.id);
a.css('padding-left', '16px');
}
else {
a.addClass('addressbook');
a.addClass('active').data('id', obj.id);
}
a.append($('<span>').text(obj.name));
return row.append(a);
}, event);
};
// create contactgroup selector popup
this.contactgroup_selector = function(event, callback)
{
this.entity_selector('contactgroup-selector', callback, this.env.contactgroups, function(obj, a) {
if (ref.env.source === obj.source) {
var row = $('<li>');
a.addClass('contactgroup');
a.addClass('active').data('id', obj.id);
a.append($('<span>').text(obj.name));
return row.append(a);
}
}, event);
};
// create selector popup (eg for folders or address books), position and display it
this.entity_selector = function(name, click_callback, entity_list, list_callback, event)
{
var container = this.entity_selectors[name];
if (!container) {
var rows = [],
container = $('<div>').attr('id', name).addClass('popupmenu'),
ul = $('<ul>').addClass('toolbarmenu'),
link = document.createElement('a');
link.href = '#';
link.className = 'icon';
// loop over entity list
$.each(entity_list, function() {
var a = $(link.cloneNode(false)).attr('rel', this.id);
rows.push(list_callback(this, a));
}); });
ul.append(rows).appendTo(container); ul.append(rows).appendTo(container);
@ -8230,18 +8338,23 @@ function rcube_webmail()
// register delegate event handler for folder item clicks // register delegate event handler for folder item clicks
container.on('click', 'a.active', function(e) { container.on('click', 'a.active', function(e) {
container.data('callback')($(this).data('id')); container.data('callback')($(this).data('id'), this);
}); });
this.folder_selector_element = container; this.entity_selectors[name] = container;
} }
container.data('callback', callback); container.data('callback', click_callback);
// position menu on the screen // position menu on the screen
this.show_menu('folder-selector', true, event); this.show_menu(name, true, event);
}; };
this.destroy_entity_selector = function(name)
{
$("#" + name).remove();
delete this.entity_selectors[name];
};
/***********************************************/ /***********************************************/
/********* popup menu functions *********/ /********* popup menu functions *********/

@ -381,6 +381,8 @@ $labels['newgroup'] = 'Create new group';
$labels['addgroup'] = 'Add group'; $labels['addgroup'] = 'Add group';
$labels['grouprename'] = 'Rename group'; $labels['grouprename'] = 'Rename group';
$labels['groupdelete'] = 'Delete group'; $labels['groupdelete'] = 'Delete group';
$labels['groupassign'] = 'Assign to group...';
$labels['groupremove'] = 'Remove from group';
$labels['groupremoveselected'] = 'Remove selected contacts from group'; $labels['groupremoveselected'] = 'Remove selected contacts from group';
$labels['uponelevel'] = 'Up one level'; $labels['uponelevel'] = 'Up one level';
$labels['previouspage'] = 'Show previous set'; $labels['previouspage'] = 'Show previous set';
@ -608,6 +610,7 @@ $labels['arialabelmessageheaders'] = 'Message headers';
$labels['arialabelforwardingoptions'] = 'Forwarding options'; $labels['arialabelforwardingoptions'] = 'Forwarding options';
$labels['arialabelreplyalloptions'] = 'Reply-all options'; $labels['arialabelreplyalloptions'] = 'Reply-all options';
$labels['arialabelmoremessageactions'] = 'More message actions'; $labels['arialabelmoremessageactions'] = 'More message actions';
$labels['arialabelmorecontactactions'] = 'More contact actions';
$labels['arialabelmarkmessagesas'] = 'Mark selected messages as...'; $labels['arialabelmarkmessagesas'] = 'Mark selected messages as...';
$labels['arialabelcomposeoptions'] = 'Composition options'; $labels['arialabelcomposeoptions'] = 'Composition options';
$labels['arialabelresponsesmenu'] = 'Canned responses menu'; $labels['arialabelresponsesmenu'] = 'Canned responses menu';

@ -441,6 +441,8 @@ $labels['newgroup'] = 'Create new group';
$labels['addgroup'] = 'Add group'; $labels['addgroup'] = 'Add group';
$labels['grouprename'] = 'Rename group'; $labels['grouprename'] = 'Rename group';
$labels['groupdelete'] = 'Delete group'; $labels['groupdelete'] = 'Delete group';
$labels['groupassign'] = 'Assign to group...';
$labels['groupremove'] = 'Remove from group';
$labels['groupremoveselected'] = 'Remove selected contacts from group'; $labels['groupremoveselected'] = 'Remove selected contacts from group';
$labels['uponelevel'] = 'Up one level'; $labels['uponelevel'] = 'Up one level';
@ -692,6 +694,7 @@ $labels['arialabelmessageheaders'] = 'Message headers';
$labels['arialabelforwardingoptions'] = 'Forwarding options'; $labels['arialabelforwardingoptions'] = 'Forwarding options';
$labels['arialabelreplyalloptions'] = 'Reply-all options'; $labels['arialabelreplyalloptions'] = 'Reply-all options';
$labels['arialabelmoremessageactions'] = 'More message actions'; $labels['arialabelmoremessageactions'] = 'More message actions';
$labels['arialabelmorecontactactions'] = 'More contact actions';
$labels['arialabelmarkmessagesas'] = 'Mark selected messages as...'; $labels['arialabelmarkmessagesas'] = 'Mark selected messages as...';
$labels['arialabelcomposeoptions'] = 'Composition options'; $labels['arialabelcomposeoptions'] = 'Composition options';
$labels['arialabelresponsesmenu'] = 'Canned responses menu'; $labels['arialabelresponsesmenu'] = 'Canned responses menu';

@ -131,7 +131,9 @@ $RCMAIL->register_action_map(array(
'search-delete' => 'search.inc', 'search-delete' => 'search.inc',
)); ));
// Disable qr-code if php-gd or Endroid's QrCode is not installed
$OUTPUT->set_env('qrcode', function_exists('imagecreate') && class_exists('Endroid\QrCode\QrCode'));
$OUTPUT->add_label('qrcode');
// instantiate a contacts object according to the given source // instantiate a contacts object according to the given source
function rcmail_contact_source($source=null, $init_env=false, $writable=false) function rcmail_contact_source($source=null, $init_env=false, $writable=false)

@ -42,10 +42,6 @@ if ($cid && ($record = ($CONTACT_RECORD ?: $CONTACTS->get_record($cid, true))))
// get address book name (for display) // get address book name (for display)
rcmail_set_sourcename($CONTACTS); rcmail_set_sourcename($CONTACTS);
// Disable qr-code if php-gd or Endroid's QrCode is not installed
$OUTPUT->set_env('qrcode', function_exists('imagecreate') && class_exists('Endroid\QrCode\QrCode'));
$OUTPUT->add_label('qrcode');
$OUTPUT->add_handlers(array( $OUTPUT->add_handlers(array(
'contacthead' => 'rcmail_contact_head', 'contacthead' => 'rcmail_contact_head',
'contactdetails' => 'rcmail_contact_details', 'contactdetails' => 'rcmail_contact_details',

@ -104,7 +104,8 @@ else if (!empty($result) && $result->count > 0) {
// add record for every email address of the contact // add record for every email address of the contact
$emails = $CONTACTS->get_col_values('email', $row, true); $emails = $CONTACTS->get_col_values('email', $row, true);
foreach ($emails as $i => $email) { foreach ($emails as $i => $email) {
$row_id = $row['ID'].'-'.$i; $source = $row['sourceid'] ?: $source;
$row_id = $source.'-'.$row['ID'].'-'.$i;
$jsresult[$row_id] = format_email_recipient($email, $name); $jsresult[$row_id] = format_email_recipient($email, $name);
$classname = $row['_type'] == 'group' ? 'group' : 'person'; $classname = $row['_type'] == 'group' ? 'group' : 'person';
$keyname = $row['_type'] == 'group' ? 'contactgroup' : 'contact'; $keyname = $row['_type'] == 'group' ? 'contactgroup' : 'contact';

@ -84,7 +84,7 @@ if (!empty($result) && $result->count > 0) {
// (same as in list_contacts.inc) // (same as in list_contacts.inc)
$emails = $source->get_col_values('email', $row, true); $emails = $source->get_col_values('email', $row, true);
foreach ($emails as $i => $email) { foreach ($emails as $i => $email) {
$row_id = $row['ID'].'-'.$i; $row_id = $row['sourceid'].'-'.$row['ID'].'-'.$i;
$jsresult[$row_id] = format_email_recipient($email, $name); $jsresult[$row_id] = format_email_recipient($email, $name);
$title = rcube_addressbook::compose_search_name($row, $email, $name); $title = rcube_addressbook::compose_search_name($row, $email, $name);

@ -92,6 +92,45 @@
background-position: -170px -32px; background-position: -170px -32px;
} }
#abooktoolbar a.contactmenu {
background: url(images/mail_toolbar.png) 0 0 no-repeat transparent;
background-position: -320px 0;
width: 34px;
}
#contactmenu li a
{
background: url(images/contactactions.png) no-repeat 7px 0;
background-position: 7px 20px;
}
#contactmenu li a.qrcode
{
background-position: 7px -39px;
}
#contactmenu li a.assigngroup
{
background-position: 7px 0;
}
#contactmenu li a.removegroup
{
background-position: 7px -19px;
}
#contactmenu li a.movelink
{
background: url(images/messageactions.png) no-repeat 7px 0;
background-position: 6px -160px;
}
#contactmenu li a.copylink
{
background: url(images/messageactions.png) no-repeat 7px 0;
background-position: 6px -142px;
}
#abookcountbar #abookcountbar
{ {
margin-top: 4px; margin-top: 4px;
@ -142,7 +181,9 @@
} }
#directorylist li a, #directorylist li a,
#savedsearchlist li a #savedsearchlist li a,
#addressbook-selector li a,
#contactgroup-selector li a
{ {
cursor: default; cursor: default;
display: block; display: block;
@ -200,6 +241,23 @@
background-position: 6px -162px; background-position: 6px -162px;
} }
#addressbook-selector li a.addressbook
{
padding-left: 25px;
}
#addressbook-selector li a.contactgroup
{
padding-left: 45px !important;
background-position: 25px -143px;
}
#contactgroup-selector li a
{
padding-left: 25px;
background-position: 5px -143px;
}
#contacts-table #contacts-table
{ {
width: 100%; width: 100%;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

@ -31,6 +31,7 @@
</span> </span>
<roundcube:button command="advanced-search" type="link" class="buttonPas search" classAct="button search" classSel="button searchSel" title="advsearch" content=" " /> <roundcube:button command="advanced-search" type="link" class="buttonPas search" classAct="button search" classSel="button searchSel" title="advsearch" content=" " />
<roundcube:container name="toolbar" id="abooktoolbar" /> <roundcube:container name="toolbar" id="abooktoolbar" />
<roundcube:button name="contactmenulink" id="contactmenulink" type="link" class="button contactmenu" title="moreactions" onclick="rcmail_ui.show_popup('contactmenu');return false" content=" " />
</div> </div>
<div id="quicksearchbar"> <div id="quicksearchbar">
@ -56,6 +57,21 @@
</ul> </ul>
</div> </div>
<div id="contactmenu" class="popupmenu">
<ul class="toolbarmenu" id="contactmenumenu">
<roundcube:if condition="env:qrcode" />
<roundcube:button type="link-menuitem" class="qrcode" command="qrcode" label="qrcode" classAct="qrcode active" />
<roundcube:endif />
<roundcube:button type="link-menuitem" class="assigngroup" command="group-assign-selected" label="groupassign" classAct="assigngroup active" innerclass="folder-selector-link" />
<roundcube:button type="link-menuitem" class="removegroup" command="group-remove-selected" label="groupremove" classAct="removegroup active" />
<roundcube:if condition="env:writable_source &gt; 1" />
<roundcube:button type="link-menuitem" class="movelink" command="move" label="moveto" classAct="movelink active" innerclass="folder-selector-link" />
<roundcube:button type="link-menuitem" class="copylink" command="copy" label="copyto" classAct="copylink active" innerclass="folder-selector-link" />
<roundcube:endif />
<roundcube:container name="contactmenu" id="contactmenumenu" />
</ul>
</div>
<div id="mainscreen"> <div id="mainscreen">
<div id="directorylistbox"> <div id="directorylistbox">
@ -107,7 +123,6 @@
<ul> <ul>
<li><roundcube:button command="group-rename" type="link" label="grouprename" classAct="active" /></li> <li><roundcube:button command="group-rename" type="link" label="grouprename" classAct="active" /></li>
<li><roundcube:button command="group-delete" type="link" label="groupdelete" classAct="active" /></li> <li><roundcube:button command="group-delete" type="link" label="groupdelete" classAct="active" /></li>
<li><roundcube:button command="group-remove-selected" type="link" label="groupremoveselected" classAct="active" /></li>
<li class="separator_above"><roundcube:button command="search-create" type="link" label="searchsave" classAct="active" /></li> <li class="separator_above"><roundcube:button command="search-create" type="link" label="searchsave" classAct="active" /></li>
<li><roundcube:button command="search-delete" type="link" label="searchdelete" classAct="active" /></li> <li><roundcube:button command="search-delete" type="link" label="searchdelete" classAct="active" /></li>
<roundcube:container name="groupoptions" id="groupoptionsmenu" /> <roundcube:container name="groupoptions" id="groupoptionsmenu" />

@ -21,9 +21,6 @@
</div> </div>
<p> <p>
<roundcube:button command="edit" type="input" class="button" label="editcontact" condition="!ENV:readonly" /> <roundcube:button command="edit" type="input" class="button" label="editcontact" condition="!ENV:readonly" />
<roundcube:if condition="env:qrcode" />
<roundcube:button command="qrcode" type="input" class="button" label="qrcode" />
<roundcube:endif />
</p> </p>
</div> </div>
<script type="text/javascript">rcube_init_tabs('contacttabs')</script> <script type="text/javascript">rcube_init_tabs('contacttabs')</script>

@ -403,3 +403,41 @@ a.deletebutton {
#import-box .propform { #import-box .propform {
max-width: 50em; max-width: 50em;
} }
ul.toolbarmenu li span.qrcode {
background-position: 0 -2408px;
}
ul.toolbarmenu li span.assigngroup {
background-position: 0 -2358px;
}
ul.toolbarmenu li span.removegroup {
background-position: 0 -2384px;
}
#addressbook-selector li a,
#contactgroup-selector li a {
padding-left: 2px;
}
#addressbook-selector li a span,
#contactgroup-selector li a span {
background: url(images/listicons.png) 4px 20px no-repeat;
display: block;
height: 17px;
min-height: 14px;
padding: 4px 4px 1px 28px;
overflow: hidden;
max-width: 120px;
text-overflow: ellipsis;
}
#addressbook-selector li a.addressbook span {
background-position: 4px -2222px;
}
#addressbook-selector li a.contactgroup span,
#contactgroup-selector li a.contactgroup span {
background-position: 4px -2245px;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 16 KiB

@ -26,6 +26,7 @@
<roundcube:button command="print" type="link" class="button print disabled" classAct="button print" classSel="button print pressed" label="print" title="printcontact" /> <roundcube:button command="print" type="link" class="button print disabled" classAct="button print" classSel="button print pressed" label="print" title="printcontact" />
<roundcube:button command="advanced-search" type="link" class="button search disabled" classAct="button search" classSel="button search pressed" label="advanced" title="advsearch" /> <roundcube:button command="advanced-search" type="link" class="button search disabled" classAct="button search" classSel="button search pressed" label="advanced" title="advsearch" />
<roundcube:container name="toolbar" id="addressbooktoolbar" /> <roundcube:container name="toolbar" id="addressbooktoolbar" />
<roundcube:button name="contactmenulink" id="contactmenulink" type="link" class="button more" label="more" title="moreactions" onclick="UI.toggle_popup('contactmenu',event);return false" aria-haspopup="true" aria-expanded="false" aria-owns="contactmenu-menu" />
<div id="exportmenu" class="popupmenu" aria-hidden="true"> <div id="exportmenu" class="popupmenu" aria-hidden="true">
<h3 id="aria-label-exportmenu" class="voice"><roundcube:label name="arialabelcontactexportoptions" /></h3> <h3 id="aria-label-exportmenu" class="voice"><roundcube:label name="arialabelcontactexportoptions" /></h3>
@ -35,6 +36,21 @@
</ul> </ul>
</div> </div>
<div id="contactmenu" class="popupmenu" aria-hidden="true">
<h3 id="aria-label-contactmenu" class="voice"><roundcube:label name="arialabelmorecontactactions" /></h3>
<ul id="contactmenu-menu" class="toolbarmenu iconized" role="menu" aria-labelledby="aria-label-contactmenu">
<roundcube:if condition="env:qrcode" />
<roundcube:button type="link-menuitem" command="qrcode" label="qrcode" class="icon" classAct="icon active" innerclass="icon qrcode" />
<roundcube:endif />
<roundcube:button type="link-menuitem" command="group-assign-selected" label="groupassign" class="icon" classAct="icon active" innerclass="icon assigngroup folder-selector-link" />
<roundcube:button type="link-menuitem" command="group-remove-selected" label="groupremove" class="icon" classAct="icon active" innerclass="icon removegroup" />
<roundcube:if condition="env:writable_source &gt; 1" />
<roundcube:button type="link-menuitem" command="move" label="moveto" class="icon" classAct="icon active" innerclass="icon move folder-selector-link" />
<roundcube:button type="link-menuitem" command="copy" label="copyto" class="icon" classAct="icon active" innerclass="icon copy folder-selector-link" />
<roundcube:endif />
<roundcube:container name="contactmenu" id="contactmenu-menu" />
</ul>
</div>
</div> </div>
<!-- search box --> <!-- search box -->
@ -103,7 +119,7 @@
<roundcube:button command="lastpage" type="link" class="icon lastpage disabled" classAct="icon lastpage" title="lastpage" label="last" /> <roundcube:button command="lastpage" type="link" class="icon lastpage disabled" classAct="icon lastpage" title="lastpage" label="last" />
</div> </div>
<div class="boxfooter"> <div class="boxfooter">
<roundcube:button command="add" type="link" title="newcontact" class="listbutton add disabled" classAct="listbutton add" innerClass="inner" label="addcontact" /><roundcube:button command="delete" type="link" title="deletecontact" class="listbutton delete disabled" classAct="listbutton delete" innerClass="inner" label="deletecontact" /><roundcube:button command="group-remove-selected" type="link" title="groupremoveselected" class="listbutton removegroup disabled" classAct="listbutton removegroup" innerClass="inner" label="groupremoveselected" /> <roundcube:button command="add" type="link" title="newcontact" class="listbutton add disabled" classAct="listbutton add" innerClass="inner" label="addcontact" /><roundcube:button command="delete" type="link" title="deletecontact" class="listbutton delete disabled" classAct="listbutton delete" innerClass="inner" label="deletecontact" />
<span class="countdisplay" aria-live="polite" aria-relevant="text"> <span class="countdisplay" aria-live="polite" aria-relevant="text">
<span class="voice"><roundcube:label name="contacts" /></span> <span class="voice"><roundcube:label name="contacts" /></span>
<roundcube:object name="recordsCountDisplay" label="fromtoshort" /> <roundcube:object name="recordsCountDisplay" label="fromtoshort" />

@ -25,9 +25,6 @@
<div id="headerbuttons" class="formbuttons"> <div id="headerbuttons" class="formbuttons">
<roundcube:button command="edit" type="input" class="button mainaction" label="editcontact" condition="!ENV:readonly" /> <roundcube:button command="edit" type="input" class="button mainaction" label="editcontact" condition="!ENV:readonly" />
<roundcube:if condition="env:qrcode" />
<roundcube:button command="qrcode" type="input" class="button" label="qrcode" />
<roundcube:endif />
</div> </div>
<roundcube:include file="/includes/footer.html" /> <roundcube:include file="/includes/footer.html" />

Loading…
Cancel
Save