diff --git a/CHANGELOG b/CHANGELOG index 1f77550be..b24932fc3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG RoundCube Webmail =========================== +- Extend contact groups support (#1486682) - Fix check-recent action issues and performance (#1486526) - Fix messages order after checking for recent (#1484664) - Fix autocomplete shows entries without email (#1486452) diff --git a/program/include/rcube_contacts.php b/program/include/rcube_contacts.php index 06600665b..ac5fed38b 100644 --- a/program/include/rcube_contacts.php +++ b/program/include/rcube_contacts.php @@ -123,7 +123,7 @@ class rcube_contacts extends rcube_addressbook if (!$this->groups) return $results; - +console('---------------'); $sql_filter = $search ? " AND " . $this->db->ilike('name', '%'.$search.'%') : ''; $sql_result = $this->db->query( diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php index d99687ca9..1a665761a 100644 --- a/program/include/rcube_imap.php +++ b/program/include/rcube_imap.php @@ -2768,7 +2768,7 @@ class rcube_imap $deleted = true; $this->clear_message_cache($mailbox.'.msg'); } - + foreach ($sub_mboxes as $c_mbox) { if ($c_mbox != 'INBOX') { $this->conn->unsubscribe($c_mbox); diff --git a/program/js/app.js b/program/js/app.js index 71a213f30..77d1a3642 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -508,7 +508,7 @@ function rcube_webmail() case 'listgroup': - this.list_contacts(null, props); + this.list_contacts(props.source, props.id); break; @@ -1258,31 +1258,33 @@ function rcube_webmail() // over the folders for (var k in this.env.folder_coords) { pos = this.env.folder_coords[k]; - if (mouse.x >= pos.x1 && mouse.x < pos.x2 && mouse.y >= pos.y1 && mouse.y < pos.y2 - && this.check_droptarget(k)) { - - li = this.get_folder_li(k); - div = $(li.getElementsByTagName('div')[0]); - - // if the folder is collapsed, expand it after 1sec and restart the drag & drop process. - if (div.hasClass('collapsed')) { - if (this.folder_auto_timer) + if (mouse.x >= pos.x1 && mouse.x < pos.x2 && mouse.y >= pos.y1 && mouse.y < pos.y2){ + if (this.check_droptarget(k)) { + li = this.get_folder_li(k); + div = $(li.getElementsByTagName('div')[0]); + + // if the folder is collapsed, expand it after 1sec and restart the drag & drop process. + if (div.hasClass('collapsed')) { + if (this.folder_auto_timer) + window.clearTimeout(this.folder_auto_timer); + + this.folder_auto_expand = k; + this.folder_auto_timer = window.setTimeout(function() { + rcmail.command('collapse-folder', rcmail.folder_auto_expand); + rcmail.drag_start(null); + }, 1000); + } else if (this.folder_auto_timer) { window.clearTimeout(this.folder_auto_timer); + this.folder_auto_timer = null; + this.folder_auto_expand = null; + } - this.folder_auto_expand = k; - this.folder_auto_timer = window.setTimeout(function() { - rcmail.command('collapse-folder', rcmail.folder_auto_expand); - rcmail.drag_start(null); - }, 1000); - } else if (this.folder_auto_timer) { - window.clearTimeout(this.folder_auto_timer); - this.folder_auto_timer = null; - this.folder_auto_expand = null; + $(li).addClass('droptarget'); + this.env.folder_coords[k].on = 1; + this.env.last_folder_target = k; + } else { // Clear target, otherwise drag end will trigger move into last valid droptarget + this.env.last_folder_target = null; } - - $(li).addClass('droptarget'); - this.env.last_folder_target = k; - this.env.folder_coords[k].on = 1; } else if (pos.on) { $(this.get_folder_li(k)).removeClass('droptarget'); @@ -1502,6 +1504,8 @@ function rcube_webmail() else if (this.task == 'addressbook') return (id != this.env.source && this.env.contactfolders[id] && !this.env.contactfolders[id].readonly && !(!this.env.source && this.env.contactfolders[id].group) && + !(this.env.contactfolders[id].type == 'group' && this.env.contactfolders[this.env.source].readonly) && + !(this.env.contactfolders[id].type == 'group' && this.env.contactfolders[id].source != this.env.source) && !(this.env.contactfolders[id].type == 'group' && this.env.contactfolders[id].id == this.env.group)); else if (this.task == 'settings') return (id != this.env.folder); @@ -3417,10 +3421,7 @@ function rcube_webmail() var add_url = ''; var target = window; - // currently all groups belong to the local address book - if (group) - src = 0; - else if (!src) + if (!src) src = this.env.source; if (page && this.current_page == page && src == this.env.source && group == this.env.group) @@ -3434,7 +3435,7 @@ function rcube_webmail() else if (group != this.env.group) page = this.env.current_page = 1; - this.select_folder((group ? 'G'+group : src), (this.env.group ? 'G'+this.env.group : this.env.source)); + this.select_folder((group ? 'G'+src+group : src), (this.env.group ? 'G'+this.env.source+this.env.group : this.env.source)); this.env.source = src; this.env.group = group; @@ -3519,7 +3520,7 @@ function rcube_webmail() if (to.type == 'group') this.http_post('group-addmembers', '_cid='+urlencode(cid)+'&_source='+urlencode(this.env.source)+'&_gid='+urlencode(to.id)); else if (to.id != this.env.source && cid && this.env.address_sources[to.id] && !this.env.address_sources[to.id].readonly) - this.http_post('copy', '_cid='+urlencode(cid)+'&_source='+urlencode(this.env.source)+'&_to='+urlencode(to.id)); + this.http_post('copy', '_cid='+urlencode(cid)+'&_source='+urlencode(this.env.source)+'&_to='+urlencode(to.id)+(this.env.group ? '&_gid='+urlencode(this.env.group) : '')); }; @@ -3625,7 +3626,8 @@ function rcube_webmail() this.name_input.type = 'text'; this.name_input.onkeypress = function(e){ return rcmail.add_input_keypress(e); }; - this.gui_objects.folderlist.parentNode.appendChild(this.name_input); + var li = this.get_folder_li(this.env.source) + $(this.name_input).insertAfter(li); } this.name_input.select(); @@ -3640,11 +3642,11 @@ function rcube_webmail() this.enable_command('list', 'listgroup', false); this.name_input = document.createElement('input'); this.name_input.type = 'text'; - this.name_input.value = this.env.contactgroups['G'+this.env.group].name; + this.name_input.value = this.env.contactgroups['G'+this.env.source+this.env.group].name; this.name_input.onkeypress = function(e){ return rcmail.add_input_keypress(e); }; this.env.group_renaming = true; - var link, li = this.get_folder_li(this.env.group, 'rcmliG'); + var li = this.get_folder_li(this.env.source+this.env.group, 'rcmliG'); if (li && (link = li.firstChild)) { $(link).hide(); li.insertBefore(this.name_input, link); @@ -3661,18 +3663,18 @@ function rcube_webmail() }; // callback from server upon group-delete command - this.remove_group_item = function(id) + this.remove_group_item = function(prop) { - var li, key = 'G'+id; + var li, key = 'G'+prop.source+prop.id; if ((li = this.get_folder_li(key))) { - this.triggerEvent('removegroup', { id:id, li:li }); + this.triggerEvent('removegroup', { source:prop.source, id:prop.id, li:li }); li.parentNode.removeChild(li); delete this.env.contactfolders[key]; delete this.env.contactgroups[key]; } - this.list_contacts(null, 0); + this.list_contacts(prop.source, 0); }; // handler for keyboard events on the input field @@ -3722,30 +3724,31 @@ function rcube_webmail() this.reset_add_input(); prop.type = 'group'; - var key = 'G'+prop.id; + var key = 'G'+prop.source+prop.id; this.env.contactfolders[key] = this.env.contactgroups[key] = prop; var link = $('').attr('href', '#') - .bind('click', function() { return rcmail.command('listgroup', prop.id, this);}) + .bind('click', function() { return rcmail.command('listgroup', prop, this);}) .html(prop.name); var li = $('
  • ').attr('id', 'rcmli'+key).addClass('contactgroup').append(link); - $(this.gui_objects.folderlist).append(li); + var pli = this.get_folder_li(prop.source) + $(li).insertAfter(pli); - this.triggerEvent('insertgroup', { id:prop.id, name:prop.name, li:li[0] }); + this.triggerEvent('insertgroup', { id:prop.id, source:prop.source, name:prop.name, li:li[0] }); }; // callback for renaming a contact group - this.update_contact_group = function(id, name) + this.update_contact_group = function(prop) { this.reset_add_input(); - var key = 'G'+id, link, li = this.get_folder_li(key); + var key = 'G'+prop.source+prop.id, link, li = this.get_folder_li(key); if (li && (link = li.firstChild) && link.tagName.toLowerCase() == 'a') - link.innerHTML = name; + link.innerHTML = prop.name; this.env.contactfolders[key].name = this.env.contactgroups[key].name = name; - this.triggerEvent('updategroup', { id:id, name:name, li:li[0] }); + this.triggerEvent('updategroup', { id:prop.id, source:prop.source, name:prop.name, li:li[0] }); }; @@ -4873,8 +4876,10 @@ function rcube_webmail() this.enable_command('export', (this.contact_list && this.contact_list.rowcount > 0)); if (response.action == 'list' || response.action == 'search') { - this.enable_command('group-create', this.env.address_sources[this.env.source].groups); - this.enable_command('group-rename', 'group-delete', this.env.address_sources[this.env.source].groups && this.env.group); + this.enable_command('group-create', + (this.env.address_sources[this.env.source].groups && !this.env.address_sources[this.env.source].readonly)); + this.enable_command('group-rename', 'group-delete', + (this.env.address_sources[this.env.source].groups && this.env.group && !this.env.address_sources[this.env.source].readonly)); this.triggerEvent('listupdate', { folder:this.env.source, rowcount:this.contact_list.rowcount }); } } diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc index ec0662b24..060185010 100644 --- a/program/steps/addressbook/func.inc +++ b/program/steps/addressbook/func.inc @@ -50,7 +50,8 @@ if (!empty($_REQUEST['_search']) && isset($_SESSION['search'][$_REQUEST['_search // set data source env $OUTPUT->set_env('source', $source ? $source : '0'); $OUTPUT->set_env('readonly', $CONTACTS->readonly, false); -$OUTPUT->set_env('address_sources', $js_list); +if(! $OUTPUT->ajax_call) + $OUTPUT->set_env('address_sources', $js_list); function rcmail_directory_list($attrib) @@ -62,6 +63,7 @@ function rcmail_directory_list($attrib) $out = ''; $local_id = '0'; + $jsdata = array(); $current = get_input_value('_source', RCUBE_INPUT_GPC); $line_templ = html::tag('li', array('id' => 'rcmli%s', 'class' => 'addressbook %s'), html::a(array('href' => '%s', 'onclick' => "return ".JS_OBJECT_NAME.".command('list','%s',this)"), '%s')); @@ -81,37 +83,37 @@ function rcmail_directory_list($attrib) $dom_id = preg_replace('/[^a-z0-9\-_]/i', '', $id); $out .= sprintf($line_templ, $dom_id, ($current == $id ? 'selected' : ''), Q(rcmail_url(null, array('_source' => $id))), $js_id, (!empty($source['name']) ? Q($source['name']) : Q($id))); + $groupdata = rcmail_contact_groups(array('out' => $out, 'jsdata' => $jsdata, 'source' => $id)); + $jsdata = $groupdata['jsdata']; + $out = $groupdata['out']; } - - $out .= rcmail_contact_groups(array('items' => true)); + $OUTPUT->set_env('contactgroups', $jsdata); $OUTPUT->add_gui_object('folderlist', $attrib['id']); return html::tag('ul', $attrib, $out, html::$common_attrib); } -function rcmail_contact_groups($attrib) +function rcmail_contact_groups($args) { - global $CONTACTS, $OUTPUT; - - if (!$attrib['id']) - $attrib['id'] = 'rcmgroupslist'; - - $groups = $CONTACTS->list_groups(); - $line_templ = html::tag('li', array('id' => 'rcmliG%s', 'class' => 'contactgroup'), - html::a(array('href' => '#', 'onclick' => "return ".JS_OBJECT_NAME.".command('listgroup','%s',this)"), '%s')); + global $RCMAIL; - $jsdata = array(); - foreach ($groups as $group) { - $out .= sprintf($line_templ, $group['ID'], $group['ID'], Q($group['name'])); - $jsdata['G'.$group['ID']] = array('id' => $group['ID'], 'name' => $group['name'], 'type' => 'group'); + $groups = $RCMAIL->get_address_book($args['source'])->list_groups(); + + if (!empty($groups)) { + $line_templ = html::tag('li', array('id' => 'rcmliG%s%s', 'class' => 'contactgroup'), + html::a(array('href' => '#', 'onclick' => "return ".JS_OBJECT_NAME.".command('listgroup',{'source':'%s','id':'%s'},this)"), '%s')); + + $jsdata = array(); + foreach ($groups as $group) { + $args['out'] .= sprintf($line_templ, $args['source'], $group['ID'], $args['source'], $group['ID'], Q($group['name'])); + $args['jsdata']['G'.$args['source'].$group['ID']] = array( + 'source' => $args['source'], 'id' => $group['ID'], 'name' => $group['name'], 'type' => 'group'); + } } - - $OUTPUT->set_env('contactgroups', $jsdata); - //$OUTPUT->add_gui_object('groupslist', $attrib['id']); - - return $attrib['items'] ? $out : html::tag('ul', $attrib, $out, html::$common_attrib); + + return $args; } diff --git a/program/steps/addressbook/groups.inc b/program/steps/addressbook/groups.inc index eda258c6e..c98d4d840 100644 --- a/program/steps/addressbook/groups.inc +++ b/program/steps/addressbook/groups.inc @@ -19,7 +19,6 @@ */ - if ($CONTACTS->readonly || !$CONTACTS->groups) { $OUTPUT->show_message('sourceisreadonly', 'warning'); $OUTPUT->send(); @@ -62,6 +61,7 @@ else if ($RCMAIL->action == 'group-create') { } if ($created && $OUTPUT->ajax_call) { + $created['source'] = $source; $OUTPUT->command('insert_contact_group', $created); } else if (!$created) { @@ -77,7 +77,7 @@ else if ($RCMAIL->action == 'group-rename') { } if ($newname && $OUTPUT->ajax_call) - $OUTPUT->command('update_contact_group', $gid, $newname); + $OUTPUT->command('update_contact_group', array('source' => $source, 'id' => $gid, 'name' => $newname)); else if (!$newname) $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error'); } @@ -90,7 +90,7 @@ else if ($RCMAIL->action == 'group-delete') { } if ($deleted) - $OUTPUT->command('remove_group_item', $gid); + $OUTPUT->command('remove_group_item', array('source' => $source, 'id' => $gid)); else $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error'); } @@ -98,4 +98,4 @@ else if ($RCMAIL->action == 'group-delete') { // send response $OUTPUT->send(); -?> \ No newline at end of file +?> diff --git a/skins/default/addressbook.css b/skins/default/addressbook.css index 456d137b1..7dd1676eb 100644 --- a/skins/default/addressbook.css +++ b/skins/default/addressbook.css @@ -117,7 +117,8 @@ bottom: 22px; left: 0; right: 0; - overflow: auto; + overflow-y: auto; + overflow-x: hidden; } #groups-title @@ -237,7 +238,8 @@ #directorylist li.contactgroup { - background-position: 5px -144px; + padding-left: 15px; + background-position: 20px -144px; } #directorylist li.selected