alecpl
2010-05-13 bb8012cfcde4ee598c2281373252a84ce0c96cc2
- Extend contact groups support (#1486682) 


7 files modified
108 ■■■■ changed files
CHANGELOG 1 ●●●● patch | view | raw | blame | history
program/include/rcube_contacts.php 2 ●●● patch | view | raw | blame | history
program/include/rcube_imap.php patch | view | raw | blame | history
program/js/app.js 61 ●●●● patch | view | raw | blame | history
program/steps/addressbook/func.inc 32 ●●●● patch | view | raw | blame | history
program/steps/addressbook/groups.inc 6 ●●●● patch | view | raw | blame | history
skins/default/addressbook.css 6 ●●●●● patch | view | raw | blame | history
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)
program/include/rcube_contacts.php
@@ -123,7 +123,7 @@
        if (!$this->groups)
            return $results;
console('---------------');
        $sql_filter = $search ? " AND " . $this->db->ilike('name', '%'.$search.'%') : '';
        $sql_result = $this->db->query(
program/include/rcube_imap.php
program/js/app.js
@@ -508,7 +508,7 @@
      case 'listgroup':
        this.list_contacts(null, props);
        this.list_contacts(props.source, props.id);
        break;
@@ -1258,9 +1258,8 @@
      // 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)) {
        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]);
@@ -1281,8 +1280,11 @@
          }
          $(li).addClass('droptarget');
          this.env.last_folder_target = k;
          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;
          }
        }
        else if (pos.on) {
          $(this.get_folder_li(k)).removeClass('droptarget');
@@ -1502,6 +1504,8 @@
    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 @@
    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 @@
    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 @@
    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 @@
      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 @@
      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 @@
  };
  // 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 @@
    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 = $('<a>').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 = $('<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 @@
          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 });
          }
        }
program/steps/addressbook/func.inc
@@ -50,6 +50,7 @@
// set data source env
$OUTPUT->set_env('source', $source ? $source : '0');
$OUTPUT->set_env('readonly', $CONTACTS->readonly, false);
if(! $OUTPUT->ajax_call)
$OUTPUT->set_env('address_sources', $js_list);
@@ -62,6 +63,7 @@
  $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 @@
    $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;
  global $RCMAIL;
  
  if (!$attrib['id'])
    $attrib['id'] = 'rcmgroupslist';
  $groups = $RCMAIL->get_address_book($args['source'])->list_groups();
  
  $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'));
  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) {
    $out .= sprintf($line_templ, $group['ID'], $group['ID'], Q($group['name']));
    $jsdata['G'.$group['ID']] = array('id' => $group['ID'], 'name' => $group['name'], 'type' => '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;
}
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 @@
  }
  
  if ($created && $OUTPUT->ajax_call) {
    $created['source'] = $source;
    $OUTPUT->command('insert_contact_group', $created);
  }
  else if (!$created) {
@@ -77,7 +77,7 @@
  }
  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 @@
  }
  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');
}
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