Changeset a61bbb2 in github


Ignore:
Timestamp:
Mar 26, 2010 12:38:20 PM (3 years ago)
Author:
thomascube <thomas@…>
Branches:
master, HEAD, courier-fix, dev-browser-capabilities, pdo, release-0.6, release-0.7, release-0.8
Children:
0dc5bc8
Parents:
c75f8e9
Message:

Added basic contact groups feature

Files:
2 added
24 edited

Legend:

Unmodified
Added
Removed
  • CHANGELOG

    r33e2e42 ra61bbb2  
    22=========================== 
    33 
     4- Added contact groups in address book (not finished yet) 
    45- Added PageUp/PageDown/Home/End keys support on lists (#1486430) 
    56- Added possibility to select all messages in a folder (#1484756) 
  • SQL/mysql.initial.sql

    r94fe9ca ra61bbb2  
    9595) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; 
    9696 
     97-- Table structure for table `contactgroups` 
     98 
     99CREATE TABLE `contactgroups` ( 
     100  `contactgroup_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, 
     101  `user_id` int(10) UNSIGNED NOT NULL DEFAULT '0', 
     102  `changed` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 
     103  `del` tinyint(1) NOT NULL DEFAULT '0', 
     104  `name` varchar(128) NOT NULL DEFAULT '', 
     105  PRIMARY KEY(`contactgroup_id`), 
     106  CONSTRAINT `user_id_fk_contactgroups` FOREIGN KEY (`user_id`) 
     107    REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE, 
     108  INDEX `contactgroups_user_index` (`user_id`,`del`) 
     109) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; 
     110 
     111CREATE TABLE `contactgroupmembers` ( 
     112  `contactgroup_id` int(10) UNSIGNED NOT NULL, 
     113  `contact_id` int(10) UNSIGNED NOT NULL DEFAULT '0', 
     114  `created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 
     115  PRIMARY KEY (`contactgroup_id`, `contact_id`), 
     116  CONSTRAINT `contactgroup_id_fk_contactgroups` FOREIGN KEY (`contactgroup_id`) 
     117    REFERENCES `contactgroups`(`contactgroup_id`) ON DELETE CASCADE ON UPDATE CASCADE, 
     118  CONSTRAINT `contact_id_fk_contacts` FOREIGN KEY (`contact_id`) 
     119    REFERENCES `contacts`(`contact_id`) ON DELETE CASCADE ON UPDATE CASCADE 
     120) /*!40000 ENGINE=INNODB */; 
     121 
    97122 
    98123-- Table structure for table `identities` 
  • SQL/mysql.update.sql

    rac756e8 ra61bbb2  
    8484ALTER TABLE `identities` ADD INDEX `user_identities_index` (`user_id`, `del`); 
    8585 
     86CREATE TABLE `contactgroups` ( 
     87  `contactgroup_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, 
     88  `user_id` int(10) UNSIGNED NOT NULL DEFAULT '0', 
     89  `changed` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 
     90  `del` tinyint(1) NOT NULL DEFAULT '0', 
     91  `name` varchar(128) NOT NULL DEFAULT '', 
     92  PRIMARY KEY(`contactgroup_id`), 
     93  CONSTRAINT `user_id_fk_contactgroups` FOREIGN KEY (`user_id`) 
     94    REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE, 
     95  INDEX `contactgroups_user_index` (`user_id`,`del`) 
     96) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; 
     97 
     98CREATE TABLE `contactgroupmembers` ( 
     99  `contactgroup_id` int(10) UNSIGNED NOT NULL, 
     100  `contact_id` int(10) UNSIGNED NOT NULL DEFAULT '0', 
     101  `created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 
     102  PRIMARY KEY (`contactgroup_id`, `contact_id`), 
     103  CONSTRAINT `contactgroup_id_fk_contactgroups` FOREIGN KEY (`contactgroup_id`) 
     104    REFERENCES `contactgroups`(`contactgroup_id`) ON DELETE CASCADE ON UPDATE CASCADE, 
     105  CONSTRAINT `contact_id_fk_contacts` FOREIGN KEY (`contact_id`) 
     106    REFERENCES `contacts`(`contact_id`) ON DELETE CASCADE ON UPDATE CASCADE 
     107) /*!40000 ENGINE=INNODB */; 
     108 
    86109/*!40014 SET FOREIGN_KEY_CHECKS=1 */; 
  • SQL/sqlite.initial.sql

    r94fe9ca ra61bbb2  
    2020 
    2121--  
    22 -- Table structure for table contacts 
     22-- Table structure for table contacts and related 
    2323--  
    2424 
     
    3636 
    3737CREATE INDEX ix_contacts_user_id ON contacts(user_id, email); 
     38 
     39 
     40CREATE TABLE contactgroups ( 
     41  contactgroup_id integer NOT NULL PRIMARY KEY, 
     42  user_id integer NOT NULL default '0', 
     43  changed datetime NOT NULL default '0000-00-00 00:00:00', 
     44  del tinyint NOT NULL default '0', 
     45  name varchar(128) NOT NULL default '' 
     46); 
     47 
     48CREATE INDEX ix_contactgroups_user_id ON contactgroups(user_id, del); 
     49 
     50 
     51CREATE TABLE contactgroupmembers ( 
     52  contactgroup_id integer NOT NULL, 
     53  contact_id integer NOT NULL default '0', 
     54  created datetime NOT NULL default '0000-00-00 00:00:00', 
     55  PRIMARY KEY (contactgroup_id, contact_id) 
     56); 
     57 
    3858 
    3959-- -------------------------------------------------------- 
  • SQL/sqlite.update.sql

    r94fe9ca ra61bbb2  
    4848DROP INDEX ix_identities_user_id; 
    4949CREATE INDEX ix_identities_user_id ON identities (user_id, del); 
     50 
     51CREATE TABLE contactgroups ( 
     52  contactgroup_id integer NOT NULL PRIMARY KEY, 
     53  user_id integer NOT NULL default '0', 
     54  changed datetime NOT NULL default '0000-00-00 00:00:00', 
     55  del tinyint NOT NULL default '0', 
     56  name varchar(128) NOT NULL default '' 
     57); 
     58 
     59CREATE INDEX ix_contactgroups_user_id ON contactgroups(user_id, del); 
     60 
     61CREATE TABLE contactgroupmembers ( 
     62  contactgroup_id integer NOT NULL, 
     63  contact_id integer NOT NULL default '0', 
     64  created datetime NOT NULL default '0000-00-00 00:00:00', 
     65  PRIMARY KEY (contactgroup_id, contact_id) 
     66); 
     67 
  • config/db.inc.php.dist

    r2273d41 ra61bbb2  
    4545$rcmail_config['db_table_contacts'] = 'contacts'; 
    4646 
     47$rcmail_config['db_table_contactgroups'] = 'contactgroups'; 
     48 
     49$rcmail_config['db_table_contactgroupmembers'] = 'contactgroupmembers'; 
     50 
    4751$rcmail_config['db_table_session'] = 'session'; 
    4852 
  • index.php

    rf52c936f ra61bbb2  
    218218  'addressbook' => array( 
    219219    'add' => 'edit.inc', 
     220    'create-group' => 'groups.inc', 
     221    'delete-group' => 'groups.inc', 
     222    'removefromgroup' => 'groups.inc', 
     223    'add2group' => 'groups.inc', 
    220224  ), 
    221225   
  • program/include/rcmail.php

    rd8c440c ra61bbb2  
    301301      $list['0'] = array( 
    302302        'id' => 0, 
    303         'name' => rcube_label('personaladrbook'), 
     303        'name' => rcube_label('personaladrbook'), 
     304        'groups' => true, 
    304305        'readonly' => false, 
    305         'autocomplete' => in_array('sql', $autocomplete) 
     306        'autocomplete' => in_array('sql', $autocomplete) 
    306307      ); 
    307308    } 
     
    310311      foreach ($ldap_config as $id => $prop) 
    311312        $list[$id] = array( 
    312           'id' => $id, 
    313           'name' => $prop['name'], 
    314           'readonly' => !$prop['writable'], 
    315           'autocomplete' => in_array('sql', $autocomplete) 
     313          'id' => $id, 
     314          'name' => $prop['name'], 
     315          'groups' => false, 
     316          'readonly' => !$prop['writable'], 
     317          'autocomplete' => in_array('sql', $autocomplete) 
    316318        ); 
    317319    } 
  • program/include/rcube_addressbook.php

    r1d786c8 ra61bbb2  
    3030    /** public properties */ 
    3131    var $primary_key; 
     32    var $groups = false; 
    3233    var $readonly = true; 
    3334    var $ready = false; 
     
    6263     */ 
    6364    abstract function list_records($cols=null, $subset=0); 
     65 
     66    /** 
     67     * List all active contact groups of this source 
     68     * 
     69     * @return array  Indexed list of contact groups, each a hash array 
     70     */ 
     71    function list_groups() { } 
    6472 
    6573    /** 
     
    125133 
    126134    /** 
     135     * Setter for the current group 
     136     * (empty, has to be re-implemented by extending class) 
     137     */ 
     138    function set_group($gid) { } 
     139 
     140    /** 
    127141     * Create a new contact record 
    128142     * 
  • program/include/rcube_contacts.php

    reb27aad ra61bbb2  
    4040  var $primary_key = 'contact_id'; 
    4141  var $readonly = false; 
     42  var $groups = true; 
    4243  var $list_page = 1; 
    4344  var $page_size = 10; 
     45  var $group_id = 0; 
    4446  var $ready = false; 
    4547 
     
    8385 
    8486  /** 
     87   * Setter for the current group 
     88   * (empty, has to be re-implemented by extending class) 
     89   */ 
     90  function set_group($gid) 
     91  { 
     92    $this->group_id = $gid; 
     93  } 
     94 
     95 
     96  /** 
    8597   * Reset all saved results and search parameters 
    8698   */ 
     
    93105  } 
    94106   
     107  /** 
     108   * List all active contact groups of this source 
     109   * 
     110   * @param string  Search string to match group name 
     111   * @return array  Indexed list of contact groups, each a hash array 
     112   */ 
     113  function list_groups($search = null) 
     114  { 
     115    $results = array(); 
     116    $sql_filter = $search ? "AND " . $this->db->ilike('name', '%'.$search.'%') : ''; 
     117 
     118    $sql_result = $this->db->query( 
     119      "SELECT * FROM ".get_table_name('contactgroups')." 
     120       WHERE  del<>1 
     121       AND    user_id=? 
     122       $sql_filter 
     123       ORDER BY name", 
     124      $this->user_id); 
     125 
     126    while ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) { 
     127      $sql_arr['ID'] = $sql_arr['contactgroup_id']; 
     128      $results[] = $sql_arr; 
     129    } 
     130     
     131    return $results; 
     132  } 
    95133   
    96134  /** 
     
    110148    if ($this->result->count) 
    111149    { 
     150      if ($this->group_id) 
     151        $join = "LEFT JOIN ".get_table_name('contactgroupmembers')." AS rcmgrouplinks". 
     152          " ON (rcmgrouplinks.contact_id=rcmcontacts.".$this->primary_key.")"; 
     153       
    112154      $start_row = $subset < 0 ? $this->result->first + $this->page_size + $subset : $this->result->first; 
    113155      $length = $subset != 0 ? abs($subset) : $this->page_size; 
    114156       
    115157      $sql_result = $this->db->limitquery( 
    116         "SELECT * FROM ".$this->db_name." 
    117          WHERE  del<>1 
    118          AND    user_id=?" . 
     158        "SELECT * FROM ".$this->db_name." AS rcmcontacts ".$join." 
     159         WHERE  rcmcontacts.del<>1 
     160         AND    rcmcontacts.user_id=?" . 
     161        ($this->group_id ? " AND rcmgrouplinks.contactgroup_id=?" : ""). 
    119162        ($this->filter ? " AND (".$this->filter.")" : "") . 
    120         " ORDER BY name", 
     163        " ORDER BY rcmcontacts.name", 
    121164        $start_row, 
    122165        $length, 
    123         $this->user_id); 
     166        $this->user_id, 
     167        $this->group_id); 
    124168    } 
    125169     
     
    185229  function count() 
    186230  { 
     231    if ($this->group_id) 
     232      $join = "LEFT JOIN ".get_table_name('contactgroupmembers')." AS rcmgrouplinks". 
     233        " ON (rcmgrouplinks.contact_id=rcmcontacts.".$this->primary_key.")"; 
     234       
    187235    // count contacts for this user 
    188236    $sql_result = $this->db->query( 
    189       "SELECT COUNT(contact_id) AS rows 
    190        FROM ".$this->db_name." 
    191        WHERE  del<>1 
    192        AND    user_id=?". 
     237      "SELECT COUNT(rcmcontacts.contact_id) AS rows 
     238       FROM ".$this->db_name." AS rcmcontacts ".$join." 
     239       WHERE  rcmcontacts.del<>1 
     240       AND    rcmcontacts.user_id=?". 
     241       ($this->group_id ? " AND rcmgrouplinks.contactgroup_id=?" : ""). 
    193242       ($this->filter ? " AND (".$this->filter.")" : ""), 
    194       $this->user_id); 
     243      $this->user_id, 
     244      $this->group_id); 
    195245 
    196246    $sql_arr = $this->db->fetch_assoc($sql_result); 
     
    358408  } 
    359409 
     410 
     411  /** 
     412   * Create a contact group with the given name 
     413   * 
     414   * @param string The group name 
     415   * @return False on error, array with record props in success 
     416   */ 
     417  function create_group($name) 
     418  { 
     419    $result = false; 
     420     
     421    $sql_result = $this->db->query( 
     422      "SELECT * FROM ".get_table_name('contactgroups')." 
     423       WHERE  del<>1 
     424       AND    user_id=? 
     425       AND    name LIKE ?", 
     426      $this->user_id, 
     427      $name . '%'); 
     428     
     429    // make sure we have a unique name 
     430    if ($num = $this->db->num_rows($sql_result)) 
     431      $name .= ' ' . ($num+1); 
     432     
     433    $this->db->query( 
     434      "INSERT INTO ".get_table_name('contactgroups')." (user_id, changed, name) 
     435       VALUES (".intval($this->user_id).", ".$this->db->now().", ".$this->db->quote($name).")" 
     436      ); 
     437     
     438    if ($insert_id = $this->db->insert_id('contactgroups')) 
     439      $result = array('id' => $insert_id, 'name' => $name); 
     440     
     441    return $result; 
     442  } 
     443 
     444  /** 
     445   * Delete the given group and all linked group members 
     446   * 
     447   * @param string Group identifier 
     448   */ 
     449  function delete_group($gid) 
     450  { 
     451    $sql_result = $this->db->query( 
     452      "DELETE FROM ".get_table_name('contactgroupmembers')." 
     453       WHERE  contactgroup_id=?", 
     454      $gid); 
     455     
     456    $sql_result = $this->db->query( 
     457      "UPDATE ".get_table_name('contactgroups')." 
     458       SET del=1, changed=".$this->db->now()." 
     459       WHERE  contactgroup_id=?", 
     460      $gid); 
     461     
     462    return $this->db->affected_rows(); 
     463  } 
     464 
     465  /** 
     466   * Add the given contact records the a certain group 
     467   * 
     468   * @param string  Group identifier 
     469   * @param array   List of contact identifiers to be added 
     470   */ 
     471  function add_to_group($group_id, $ids) 
     472  { 
     473    if (!is_array($ids)) 
     474      $ids = explode(',', $ids); 
     475     
     476    $added = 0; 
     477     
     478    foreach ($ids as $contact_id) { 
     479      $sql_result = $this->db->query( 
     480        "SELECT 1 FROM ".get_table_name('contactgroupmembers')." 
     481         WHERE  contactgroup_id=? 
     482         AND    contact_id=?", 
     483      $group_id, 
     484      $contact_id); 
     485       
     486      if (!$this->db->num_rows($sql_result)) { 
     487        $this->db->query( 
     488          "INSERT INTO ".get_table_name('contactgroupmembers')." (contactgroup_id, contact_id, created) 
     489           VALUES (".intval($group_id).", ".intval($contact_id).", ".$this->db->now().")" 
     490        ); 
     491        if (!$this->db->db_error) 
     492          $added++; 
     493      } 
     494    } 
     495     
     496    return $added; 
     497  } 
     498   
     499   
     500  /** 
     501   * Remove the given contact records from a certain group 
     502   * 
     503   * @param string  Group identifier 
     504   * @param array   List of contact identifiers to be removed 
     505   */ 
     506  function remove_from_group($group_id, $ids) 
     507  { 
     508    if (!is_array($ids)) 
     509      $ids = explode(',', $ids); 
     510     
     511    $sql_result = $this->db->query( 
     512      "DELETE FROM ".get_table_name('contactgroupmembers')." 
     513       WHERE  contactgroup_id=? 
     514       AND    contact_id IN (".join(',', array_map(array($this->db, 'quote'), $ids)).")", 
     515      $group_id); 
     516     
     517    return $this->db->affected_rows(); 
     518  } 
     519   
    360520} 
  • program/js/app.js

    r33e2e42 ra61bbb2  
    285285 
    286286      case 'addressbook': 
     287        if (this.gui_objects.folderlist) 
     288          this.env.contactfolders = $.extend($.extend({}, this.env.address_sources), this.env.contactgroups); 
     289         
    287290        if (this.gui_objects.contactslist) 
    288291          { 
    289           this.contact_list = new rcube_list_widget(this.gui_objects.contactslist, {multiselect:true, draggable:true, keyboard:true}); 
     292          this.contact_list = new rcube_list_widget(this.gui_objects.contactslist, 
     293            {multiselect:true, draggable:this.gui_objects.folderlist?true:false, keyboard:true}); 
    290294          this.contact_list.row_init = function(row){ p.triggerEvent('insertrow', { cid:row.uid, row:row }); }; 
    291295          this.contact_list.addEventListener('keypress', function(o){ p.contactlist_keypress(o); }); 
     
    307311            this.contact_list.focus(); 
    308312             
    309           this.gui_objects.folderlist = this.gui_objects.contactslist; 
     313          //this.gui_objects.folderlist = this.gui_objects.contactslist; 
    310314          } 
    311315 
    312316        this.set_page_buttons(); 
    313317         
    314         if (this.env.address_sources && this.env.address_sources[this.env.source] && !this.env.address_sources[this.env.source].readonly) 
     318        if (this.env.address_sources && this.env.address_sources[this.env.source] && !this.env.address_sources[this.env.source].readonly) { 
    315319          this.enable_command('add', 'import', true); 
     320          this.enable_command('add-group', this.env.address_sources[this.env.source].groups); 
     321        } 
    316322         
    317323        if (this.env.cid) 
     
    326332          this.enable_command('export', true); 
    327333 
    328         this.enable_command('list', true); 
     334        this.enable_command('list', 'listgroup', true); 
    329335        break; 
    330336 
     
    490496      case 'menu-open': 
    491497      case 'menu-save': 
    492             this.triggerEvent(command, {props:props}); 
    493             return false; 
    494         break; 
     498        this.triggerEvent(command, {props:props}); 
     499        return false; 
    495500 
    496501      case 'open': 
     
    523528          this.enable_command('add', 'import', (this.env.address_sources && !this.env.address_sources[props].readonly)); 
    524529          } 
     530        break; 
     531 
     532 
     533      case 'listgroup': 
     534        this.list_contacts(null, props); 
    525535        break; 
    526536 
     
    970980        this.add_contact(props); 
    971981        break; 
    972        
     982 
    973983      // quicksearch 
    974984      case 'search': 
     
    989999          this.list_mailbox(this.env.mailbox); 
    9901000        else if (s && this.task == 'addressbook') 
    991           this.list_contacts(this.env.source); 
     1001          this.list_contacts(this.env.source, this.env.group); 
     1002        break; 
     1003 
     1004      case 'add-group': 
     1005        this.add_contact_group(props) 
    9921006        break; 
    9931007 
     
    11921206        this.contact_list.blur(); 
    11931207      list = this.contact_list; 
    1194       model = this.env.address_sources; 
     1208      model = this.env.contactfolders; 
    11951209    } 
    11961210    else if (this.ksearch_value) { 
     
    12001214    // handle mouse release when dragging 
    12011215    if (this.drag_active && model && this.env.last_folder_target) { 
    1202       var mbox = model[this.env.last_folder_target].id; 
    1203  
     1216      var target = model[this.env.last_folder_target]; 
     1217       
    12041218      $(this.get_folder_li(this.env.last_folder_target)).removeClass('droptarget'); 
    12051219      this.env.last_folder_target = null; 
    12061220      list.draglayer.hide(); 
    12071221 
    1208       if (!this.drag_menu(e, mbox)) 
    1209         this.command('moveto', mbox); 
     1222      if (!this.drag_menu(e, target)) 
     1223        this.command('moveto', target); 
    12101224    } 
    12111225     
     
    12191233  }; 
    12201234 
    1221   this.drag_menu = function(e, mbox) 
     1235  this.drag_menu = function(e, target) 
    12221236  { 
    12231237    var modkey = rcube_event.get_modifier(e); 
    12241238    var menu = $('#'+this.gui_objects.message_dragmenu); 
    12251239 
    1226     if (menu && modkey == SHIFT_KEY) { 
     1240    if (menu && modkey == SHIFT_KEY && this.commands['copy']) { 
    12271241      var pos = rcube_event.get_mouse_pos(e); 
    1228       this.env.drag_mbox = mbox; 
     1242      this.env.drag_target = target; 
    12291243      menu.css({top: (pos.y-10)+'px', left: (pos.x-10)+'px'}).show(); 
    12301244      return true; 
    12311245    } 
     1246     
     1247    return false; 
    12321248  }; 
    12331249 
     
    12381254      menu.hide(); 
    12391255    } 
    1240     this.command(action, this.env.drag_mbox); 
    1241     this.env.drag_mbox = null; 
     1256    this.command(action, this.env.drag_target); 
     1257    this.env.drag_target = null; 
    12421258  }; 
    12431259 
    12441260  this.drag_start = function(list) 
    12451261  { 
    1246     var model = this.task == 'mail' ? this.env.mailboxes : this.env.address_sources; 
     1262    var model = this.task == 'mail' ? this.env.mailboxes : this.env.contactfolders; 
    12471263 
    12481264    this.drag_active = true; 
     
    14851501      return (this.env.mailboxes[id] && this.env.mailboxes[id].id != this.env.mailbox && !this.env.mailboxes[id].virtual); 
    14861502    else if (this.task == 'addressbook') 
    1487       return (id != this.env.source && this.env.address_sources[id] && !this.env.address_sources[id].readonly); 
     1503      return (id != this.env.source && this.env.contactfolders[id] && !this.env.contactfolders[id].readonly && 
     1504        !(!this.env.source && this.env.contactfolders[id].group) && 
     1505        !(this.env.contactfolders[id].type == 'group' && this.env.contactfolders[id].id == this.env.group)); 
    14881506    else if (this.task == 'settings') 
    14891507      return (id != this.env.folder); 
     
    17851803        this.list_mailbox(this.env.mailbox, page); 
    17861804      else if (this.task=='addressbook') 
    1787         this.list_contacts(this.env.source, page); 
     1805        this.list_contacts(this.env.source, null, page); 
    17881806      } 
    17891807    }; 
     
    21752193  this.move_messages = function(mbox) 
    21762194    { 
     2195    if (mbox && typeof mbox == 'object') 
     2196      mbox = mbox.id; 
     2197       
    21772198    // exit if current or no mailbox specified or if selection is empty 
    21782199    if (!mbox || mbox == this.env.mailbox || (!this.env.uid && (!this.message_list || !this.message_list.get_selection().length))) 
     
    30983119        + (this.env.mailbox ? '&_mbox='+urlencode(this.env.mailbox) : '') 
    30993120        + (this.env.source ? '&_source='+urlencode(this.env.source) : '') 
     3121        + (this.env.group ? '&_gid='+urlencode(this.env.group) : '') 
    31003122        + (addurl ? addurl : ''), true); 
    31013123      } 
     
    32093231    var pre = this.ksearch_input.value.substring(0, p); 
    32103232    var end = this.ksearch_input.value.substring(p+this.ksearch_value.length, this.ksearch_input.value.length); 
    3211     var insert  = this.env.contacts[id]+', '; 
     3233    var insert = ''; 
     3234     
     3235    // insert all members of a group 
     3236    if (typeof this.env.contacts[id] == 'object' && this.env.contacts[id].members) { 
     3237      for (var i=0; i < this.env.contacts[id].members.length; i++) 
     3238        insert += this.env.contacts[id].members[i] + ', '; 
     3239    } 
     3240    else if (typeof this.env.contacts[id] == 'string') 
     3241      insert = this.env.contacts[id] + ', '; 
     3242 
    32123243    this.ksearch_input.value = pre + insert + end; 
    32133244 
     
    32703301    // display search results 
    32713302    if (a_results.length && this.ksearch_input && this.ksearch_value) { 
    3272       var p, ul, li, s_val = this.ksearch_value; 
     3303      var p, ul, li, text, s_val = this.ksearch_value; 
    32733304       
    32743305      // create results pane if not present 
     
    32843315 
    32853316      // add each result line to list 
    3286       for (i=0; i<a_results.length; i++) { 
     3317      for (i=0; i < a_results.length; i++) { 
     3318        text = typeof a_results[i] == 'object' ? a_results[i].name : a_results[i]; 
    32873319        li = document.createElement('LI'); 
    3288         li.innerHTML = a_results[i].replace(new RegExp('('+s_val+')', 'ig'), '##$1%%').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/##([^%]+)%%/g, '<b>$1</b>'); 
     3320        li.innerHTML = text.replace(new RegExp('('+s_val+')', 'ig'), '##$1%%').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/##([^%]+)%%/g, '<b>$1</b>'); 
    32893321        li.onmouseover = function(){ ref.ksearch_select(this); }; 
    32903322        li.onmouseup = function(){ ref.ksearch_click(this) }; 
     
    33643396    }; 
    33653397 
    3366   this.list_contacts = function(src, page) 
     3398  this.list_contacts = function(src, group, page) 
    33673399    { 
    33683400    var add_url = ''; 
    33693401    var target = window; 
    33703402     
     3403    // currently all groups belong to the local address book 
     3404    if (group) 
     3405      src = 0; 
     3406     
    33713407    if (!src) 
    33723408      src = this.env.source; 
    33733409     
    3374     if (page && this.current_page==page && src == this.env.source) 
     3410    if (page && this.current_page == page && src == this.env.source && group == this.env.group) 
    33753411      return false; 
    33763412       
     
    33813417      this.reset_qsearch(); 
    33823418      } 
     3419    else if (group != this.env.group) 
     3420      page = this.env.current_page = 1; 
    33833421 
    33843422    this.select_folder(src, this.env.source); 
     3423    this.select_folder(group, this.env.group, 'rcmliG'); 
     3424     
    33853425    this.env.source = src; 
     3426    this.env.group = group; 
    33863427 
    33873428    // load contacts remotely 
    33883429    if (this.gui_objects.contactslist) 
    33893430      { 
    3390       this.list_contacts_remote(src, page); 
     3431      this.list_contacts_remote(src, group, page); 
    33913432      return; 
    33923433      } 
     
    33973438      add_url = '&_framed=1'; 
    33983439      } 
     3440       
     3441    if (group) 
     3442      add_url += '&_gid='+group; 
     3443    if (page) 
     3444      add_url += '&_page='+page; 
    33993445 
    34003446    // also send search request to get the correct listing 
     
    34033449 
    34043450    this.set_busy(true, 'loading'); 
    3405     target.location.href = this.env.comm_path+(src ? '&_source='+urlencode(src) : '')+(page ? '&_page='+page : '')+add_url; 
     3451    target.location.href = this.env.comm_path + (src ? '&_source='+urlencode(src) : '') + add_url; 
    34063452    }; 
    34073453 
    34083454  // send remote request to load contacts list 
    3409   this.list_contacts_remote = function(src, page) 
     3455  this.list_contacts_remote = function(src, group, page) 
    34103456    { 
    34113457    // clear message list first 
     
    34173463    var url = (src ? '_source='+urlencode(src) : '') + (page ? (src?'&':'') + '_page='+page : ''); 
    34183464    this.env.source = src; 
     3465    this.env.group = group; 
     3466     
     3467    if (group) 
     3468      url += '&_gid='+group; 
    34193469     
    34203470    // also send search request to get the right messages  
     
    34543504      cid = this.contact_list.get_selection().join(','); 
    34553505 
    3456     if (to != this.env.source && cid && this.env.address_sources[to] && !this.env.address_sources[to].readonly) 
    3457       this.http_post('copy', '_cid='+urlencode(cid)+'&_source='+urlencode(this.env.source)+'&_to='+urlencode(to)); 
     3506    if (to.type == 'group') 
     3507      this.http_post('add2group', '_cid='+urlencode(cid)+'&_source='+urlencode(this.env.source)+'&_gid='+urlencode(to.id)); 
     3508    else if (to.id != this.env.source && cid && this.env.address_sources[to.id] && !this.env.address_sources[to.id].readonly) 
     3509      this.http_post('copy', '_cid='+urlencode(cid)+'&_source='+urlencode(this.env.source)+'&_to='+urlencode(to.id)); 
    34583510    }; 
    34593511 
     
    34633515    // exit if no mailbox specified or if selection is empty 
    34643516    var selection = this.contact_list.get_selection(); 
    3465     if (!(selection.length || this.env.cid) || !confirm(this.get_label('deletecontactconfirm'))) 
     3517    if (!(selection.length || this.env.cid) || (!this.env.group && !confirm(this.get_label('deletecontactconfirm')))) 
    34663518      return; 
    34673519       
     
    34913543 
    34923544    // send request to server 
    3493     this.http_post('delete', '_cid='+urlencode(a_cids.join(','))+'&_source='+urlencode(this.env.source)+'&_from='+(this.env.action ? this.env.action : '')+qs); 
     3545    if (this.env.group) 
     3546      this.http_post('removefromgroup', '_cid='+urlencode(a_cids.join(','))+'&_source='+urlencode(this.env.source)+'&_gid='+urlencode(this.env.group)+qs); 
     3547    else 
     3548      this.http_post('delete', '_cid='+urlencode(a_cids.join(','))+'&_source='+urlencode(this.env.source)+'&_from='+(this.env.action ? this.env.action : '')+qs); 
     3549       
    34943550    return true; 
    34953551    }; 
     
    35063562      // cid change 
    35073563      if (newcid) { 
    3508         row.id = 'rcmrow' + newcid; 
     3564        row.id = 'rcmrow' + newcid; 
    35093565        this.contact_list.remove_row(cid); 
    35103566        this.contact_list.init_row(row); 
    3511         this.contact_list.selection[0] = newcid; 
    3512         row.style.display = ''; 
     3567        this.contact_list.selection[0] = newcid; 
     3568        ow.style.display = ''; 
    35133569      } 
    35143570 
     
    35483604    this.enable_command('export', (this.contact_list.rowcount > 0)); 
    35493605    }; 
     3606   
     3607   
     3608  this.add_contact_group = function() 
     3609  { 
     3610    if (!this.gui_objects.folderlist || !this.env.address_sources[this.env.source].groups) 
     3611      return; 
     3612       
     3613    if (!this.name_input) { 
     3614      this.name_input = document.createElement('input'); 
     3615      this.name_input.type = 'text'; 
     3616      this.name_input.onkeypress = function(e){ return rcmail.add_input_keypress(e); }; 
     3617     
     3618      this.gui_objects.folderlist.parentNode.appendChild(this.name_input); 
     3619    } 
     3620     
     3621    this.name_input.select(); 
     3622  }; 
     3623   
     3624  // handler for keyboard events on the input field 
     3625  this.add_input_keypress = function(e) 
     3626  { 
     3627    var key = rcube_event.get_keycode(e); 
     3628 
     3629    // enter 
     3630    if (key == 13) { 
     3631      var newname = this.name_input.value; 
     3632       
     3633      if (newname) { 
     3634        this.set_busy(true, 'loading'); 
     3635        this.http_post('create-group', '_source='+urlencode(this.env.source)+'&_name='+urlencode(newname), true); 
     3636      } 
     3637      return false; 
     3638    } 
     3639    // escape 
     3640    else if (key == 27) 
     3641      this.reset_add_input(); 
     3642       
     3643    return true; 
     3644  }; 
     3645   
     3646  this.reset_add_input = function() 
     3647  { 
     3648    if (this.name_input) { 
     3649      this.name_input.parentNode.removeChild(this.name_input); 
     3650      this.name_input = null; 
     3651    } 
     3652  }; 
     3653   
     3654  // callback for creating a new contact group 
     3655  this.insert_contact_group = function(prop) 
     3656  { 
     3657    this.reset_add_input(); 
     3658  } 
    35503659 
    35513660 
     
    42574366 
    42584367  // mark a mailbox as selected and set environment variable 
    4259   this.select_folder = function(name, old) 
     4368  this.select_folder = function(name, old, prefix) 
    42604369  { 
    42614370    if (this.gui_objects.folderlist) 
     
    42634372      var current_li, target_li; 
    42644373       
    4265       if ((current_li = this.get_folder_li(old))) { 
     4374      if ((current_li = this.get_folder_li(old, prefix))) { 
    42664375        $(current_li).removeClass('selected').removeClass('unfocused'); 
    42674376      } 
    4268       if ((target_li = this.get_folder_li(name))) { 
     4377      if ((target_li = this.get_folder_li(name, prefix))) { 
    42694378        $(target_li).removeClass('unfocused').addClass('selected'); 
    42704379      } 
    42714380       
    42724381      // trigger event hook 
    4273       this.triggerEvent('selectfolder', { folder:name, old:old }); 
     4382      this.triggerEvent('selectfolder', { folder:name, old:old, prefix:prefix }); 
    42744383    } 
    42754384  }; 
    42764385 
    42774386  // helper method to find a folder list item 
    4278   this.get_folder_li = function(name) 
    4279   { 
     4387  this.get_folder_li = function(name, prefix) 
     4388  { 
     4389    if (!prefix) 
     4390      prefix = 'rcmli'; 
    42804391    if (this.gui_objects.folderlist) 
    42814392    { 
    42824393      name = String(name).replace(this.identifier_expr, '_'); 
    4283       return document.getElementById('rcmli'+name); 
     4394      return document.getElementById(prefix+name); 
    42844395    } 
    42854396 
     
    47144825          this.enable_command('export', (this.contact_list && this.contact_list.rowcount > 0)); 
    47154826           
    4716           if (response.action == 'list') 
     4827          if (response.action == 'list') { 
     4828            this.enable_command('add-group', this.env.address_sources[this.env.source].groups); 
     4829            // disabeld for now: this.enable_command('rename-group', 'delete-group', this.env.address_sources[this.env.source].groups && this.env.group); 
    47174830            this.triggerEvent('listupdate', { folder:this.env.source, rowcount:this.contact_list.rowcount }); 
     4831          } 
    47184832        } 
    47194833        break; 
  • program/localization/de_CH/labels.inc

    r71e7545 ra61bbb2  
    215215$labels['export'] = 'Exportieren'; 
    216216$labels['exportvcards'] = 'Kontakte im vCard-Format exportieren'; 
     217$labels['newcontactgroup'] = 'Neue Adressgruppe erstellen'; 
     218$labels['groupactions']   = 'Aktionen fÃŒr Kontaktgruppen...'; 
    217219$labels['previouspage'] = 'Eine Seite zurÃŒck'; 
    218220$labels['firstpage'] = 'Erste Seite'; 
    219221$labels['nextpage'] = 'NÀchste Seite'; 
    220222$labels['lastpage'] = 'Letzte Seite'; 
     223$labels['group'] = 'Gruppe'; 
    221224$labels['groups'] = 'Gruppen'; 
    222225$labels['personaladrbook'] = 'Persönliches Adressbuch'; 
  • program/localization/de_CH/messages.inc

    r3c9aa23 ra61bbb2  
    9494$messages['selectimportfile'] = 'Bitte wÀhlen Sie eine Datei zum Importieren aus'; 
    9595$messages['addresswriterror'] = 'Das gewÀhlte Adressbuch kann nicht verÀndert werden'; 
     96$messages['contactaddedtogroup'] = 'Kontakte wurden dieser Gruppe hinzugefÃŒgt'; 
     97$messages['contactremovedfromgroup'] = 'Kontakte wurden aus dieser Gruppe entfernt'; 
    9698$messages['importwait'] = 'Daten werden importiert, bitte warten...'; 
    9799$messages['importerror'] = 'Import fehlgeschlagen! Die hochgeladene Datei ist nicht im vCard-Format.'; 
  • program/localization/en_US/labels.inc

    rfb7ec57 ra61bbb2  
    259259$labels['export']         = 'Export'; 
    260260$labels['exportvcards']   = 'Export contacts in vCard format'; 
     261$labels['newcontactgroup'] = 'Create new contact group'; 
     262$labels['groupactions']   = 'Actions for contact groups...'; 
    261263 
    262264$labels['previouspage']   = 'Show previous set'; 
     
    265267$labels['lastpage']       = 'Show last set'; 
    266268 
     269$labels['group'] = 'Group'; 
    267270$labels['groups'] = 'Groups'; 
    268271$labels['personaladrbook'] = 'Personal Addresses'; 
  • program/localization/en_US/messages.inc

    rb1e74ac ra61bbb2  
    9696$messages['selectimportfile'] = 'Please select a file to upload'; 
    9797$messages['addresswriterror'] = 'The selected address book is not writeable'; 
     98$messages['contactaddedtogroup'] = 'Successfully added the contacts to this group'; 
     99$messages['contactremovedfromgroup'] = 'Successfully remove contacts from this group'; 
    98100$messages['importwait'] = 'Importing, please wait...'; 
    99101$messages['importerror'] = 'Import failed! The uploaded file is not a valid vCard file.'; 
  • program/steps/addressbook/func.inc

    r3704b78 ra61bbb2  
    4040else 
    4141  $CONTACTS->set_page(isset($_SESSION['page']) ?$_SESSION['page'] : 1); 
     42   
     43if (!empty($_REQUEST['_gid'])) 
     44  $CONTACTS->set_group(get_input_value('_gid', RCUBE_INPUT_GPC)); 
    4245 
    4346// set message set for search result 
     
    6164  $local_id = '0'; 
    6265  $current = get_input_value('_source', RCUBE_INPUT_GPC); 
    63   $line_templ = html::tag('li', array('id' => 'rcmli%s', 'class' => '%s'), 
     66  $line_templ = html::tag('li', array('id' => 'rcmli%s', 'class' => 'addressbook %s'), 
    6467    html::a(array('href' => '%s', 'onclick' => "return ".JS_OBJECT_NAME.".command('list','%s',this)"), '%s')); 
    6568 
     
    8083      Q(rcmail_url(null, array('_source' => $id))), $js_id, (!empty($source['name']) ? Q($source['name']) : Q($id))); 
    8184  } 
     85   
     86  $out .= rcmail_contact_groups(array('items' => true)); 
    8287 
    8388  $OUTPUT->add_gui_object('folderlist', $attrib['id']); 
    8489   
    8590  return html::tag('ul', $attrib, $out, html::$common_attrib); 
     91} 
     92 
     93 
     94function rcmail_contact_groups($attrib) 
     95{ 
     96  global $CONTACTS, $OUTPUT; 
     97   
     98  if (!$attrib['id']) 
     99    $attrib['id'] = 'rcmgroupslist'; 
     100   
     101  $groups = $CONTACTS->list_groups(); 
     102  $line_templ = html::tag('li', array('id' => 'rcmliG%s', 'class' => 'contactgroup'), 
     103    html::a(array('href' => '#', 'onclick' => "return ".JS_OBJECT_NAME.".command('listgroup','%s',this)"), '%s')); 
     104 
     105  $jsdata = array(); 
     106  foreach ($groups as $group) { 
     107    $out .= sprintf($line_templ, $group['ID'], $group['ID'], Q($group['name'])); 
     108    $jsdata['G'.$group['ID']] = array('id' => $group['ID'], 'name' => $group['name'], 'type' => 'group'); 
     109  } 
     110   
     111  $OUTPUT->set_env('contactgroups', $jsdata); 
     112  //$OUTPUT->add_gui_object('groupslist', $attrib['id']); 
     113   
     114  return $attrib['items'] ? $out : html::tag('ul', $attrib, $out, html::$common_attrib); 
    86115} 
    87116 
     
    201230$OUTPUT->add_handlers(array( 
    202231  'directorylist' => 'rcmail_directory_list', 
     232//  'groupslist' => 'rcmail_contact_groups', 
    203233  'addresslist' => 'rcmail_contacts_list', 
    204234  'addressframe' => 'rcmail_contact_frame', 
  • program/steps/mail/autocomplete.inc

    r1b5f98a ra61bbb2  
    66 |                                                                       | 
    77 | This file is part of the RoundCube Webmail client                     | 
    8  | Copyright (C) 2008-2009, RoundCube Dev Team                           | 
     8 | Copyright (C) 2008-2010, RoundCube Dev Team                           | 
    99 | Licensed under the GNU GPL                                            | 
    1010 |                                                                       | 
     
    2424$book_types = (array) $RCMAIL->config->get('autocomplete_addressbooks', 'sql'); 
    2525 
    26 if ($book_types && $search = get_input_value('_search', RCUBE_INPUT_POST, true)) { 
     26if ($book_types && $search = get_input_value('_search', RCUBE_INPUT_GPC, true)) { 
    2727 
    2828  foreach ($book_types as $id) { 
     
    3333      while ($sql_arr = $result->iterate()) { 
    3434          $contacts[] = format_email_recipient($sql_arr['email'], $sql_arr['name']); 
    35           if (count($contacts) >= $MAXNUM) 
     35          if (count($contacts) >= $MAXNUM) 
    3636            break 2; 
     37      } 
     38    } 
     39     
     40    // also list matching contact groups 
     41    if ($abook->groups) { 
     42      foreach ($abook->list_groups($search) as $group) { 
     43        $members = array(); 
     44        $abook->reset(); 
     45        $abook->set_group($group['ID']); 
     46        $result = $abook->list_records(array('email','name')); 
     47        while ($result && ($sql_arr = $result->iterate())) 
     48          $members[] = format_email_recipient($sql_arr['email'], $sql_arr['name']); 
     49         
     50        if (count($members)) { 
     51          $contacts[] = array('name' => $group['name'] . ' (' . rcube_label('group') . ')', 'members' => $members); 
     52          if (count($contacts) >= $MAXNUM) 
     53            break; 
     54        } 
    3755      } 
    3856    } 
    3957  } 
    4058   
    41   sort($contacts); 
     59  usort($contacts, 'contact_results_sort'); 
    4260} 
    4361 
     
    4563$OUTPUT->send(); 
    4664 
     65 
     66function contact_results_sort($a, $b) 
     67{ 
     68  $name_a = is_array($a) ? $a['name'] : $a; 
     69  $name_b = is_array($b) ? $b['name'] : $b; 
     70  return strcmp(trim($name_a, '" '), trim($name_b, '" ')); 
     71} 
     72 
    4773?> 
  • skins/default/addressbook.css

    r9224c8a ra61bbb2  
    55  position: absolute; 
    66  top: 45px; 
    7   left: 205px; 
     7  left: 225px; 
    88  height: 35px; 
    99} 
     
    7777{ 
    7878  position: absolute; 
    79   bottom: 16px; 
    80   left: 200px; 
     79  bottom: 6px; 
     80  left: 225px; 
    8181  width: 240px; 
    8282  height: 20px; 
     
    9595  top: 85px; 
    9696  right: 20px; 
    97   bottom: 40px; 
    98   left: 205px; 
    99 } 
    100  
    101 #directorylist 
     97  bottom: 30px; 
     98  left: 225px; 
     99} 
     100 
     101#directorylistbox 
    102102{ 
    103103  position: absolute; 
    104104  top: 85px; 
    105   bottom: 40px; 
     105  bottom: 30px; 
    106106  left: 20px; 
    107   width: 175px; 
     107  width: 195px; 
    108108  border: 1px solid #999999; 
    109109  background-color: #F9F9F9; 
    110110  overflow: hidden; 
     111} 
     112 
     113#directorylistwarp 
     114{ 
     115  position: absolute; 
     116  top: 20px; 
     117  bottom: 22px; 
     118  left: 0; 
     119  right: 0; 
     120  overflow: auto; 
     121} 
     122 
     123#groups-title 
     124{ 
     125  position: absolute; 
     126  top: 0; 
     127  left: 0; 
     128  right: 0; 
     129} 
     130 
     131#directorylistbox input 
     132{ 
     133  display: absolute; 
     134  margin: 2px; 
     135} 
     136 
     137#directoylistbuttons 
     138{ 
     139  display: block; 
     140  position: absolute; 
     141  bottom: 0px; 
     142  left: 0px; 
     143  right: 0px; 
     144  height: 22px; 
     145  border-top: 1px solid #999; 
     146  background: url('images/listheader.gif') top left repeat-x #CCC; 
     147} 
     148 
     149#directoylistbuttons a.button, 
     150#directoylistbuttons a.buttonPas 
     151{ 
     152  display: block; 
     153  float: left; 
     154  width: 34px; 
     155  height: 22px; 
     156  padding: 0px; 
     157  margin: 0; 
     158  overflow: hidden; 
     159  background: url('images/icons/groupactions.png') 0 0 no-repeat transparent; 
     160  opacity: 0.99; /* this is needed to make buttons appear correctly in Chrome */ 
     161} 
     162 
     163#directoylistbuttons a.groupactions { 
     164  background-position: 0 -26px; 
     165} 
     166 
     167#directoylistbuttons a.buttonPas { 
     168  opacity: 0.35; 
    111169} 
    112170 
     
    119177  background-color: #F9F9F9; 
    120178  overflow: auto; 
     179} 
     180 
     181#contactgroupslist 
     182{ 
     183  border-top: 1px solid #999; 
    121184} 
    122185 
     
    137200{ 
    138201  left: 0px; 
    139   width: 340px; 
     202  width: 280px; 
    140203} 
    141204 
     
    145208} 
    146209 
    147 #directorylist ul 
     210#directorylist 
    148211{ 
    149212  list-style: none; 
     
    153216} 
    154217 
    155 #directorylist ul li 
    156 { 
     218#directorylist li 
     219{ 
     220  display: block; 
    157221  font-size: 11px; 
     222  background: url(images/icons/folders.png) 5px -108px no-repeat; 
    158223  border-bottom: 1px solid #EBEBEB; 
    159224  white-space: nowrap; 
    160225} 
    161226 
    162 #directorylist ul li a 
    163 { 
    164   display: block; 
    165   padding-left: 6px; 
     227#directorylist li a 
     228{ 
     229  cursor: default; 
     230  display: block; 
     231  padding-left: 25px; 
    166232  padding-top: 2px; 
    167233  padding-bottom: 2px; 
     
    170236} 
    171237 
     238#directorylist li.contactgroup 
     239{ 
     240  background-position: 5px -144px; 
     241} 
     242 
    172243#directorylist li.selected 
    173244{ 
     
    202273  position: absolute; 
    203274  top: 0px; 
    204   left: 555px; 
     275  left: 290px; 
    205276  right: 0px; 
    206277  bottom: 0px; 
  • skins/default/functions.js

    r39f9d39 ra61bbb2  
    127127function rcube_mail_ui() 
    128128{ 
    129   this.markmenu = $('#markmessagemenu'); 
    130   this.searchmenu = $('#searchmenu'); 
    131   this.messagemenu = $('#messagemenu'); 
    132   this.listmenu = $('#listmenu'); 
    133   this.dragmessagemenu = $('#dragmessagemenu'); 
     129  this.popupmenus = { 
     130    markmenu:'markmessagemenu', 
     131    searchmenu:'searchmenu', 
     132    messagemenu:'messagemenu', 
     133    listmenu:'listmenu', 
     134    dragmessagemenu:'dragmessagemenu', 
     135    groupmenu:'groupoptionsmenu' 
     136  }; 
     137   
     138  var obj; 
     139  for (var k in this.popupmenus) { 
     140    obj = $('#'+this.popupmenus[k]) 
     141    if (obj.length) 
     142      this[k] = obj; 
     143  } 
    134144} 
    135145 
    136146rcube_mail_ui.prototype = { 
    137147 
     148show_popupmenu: function(obj, refname, show, above) 
     149{ 
     150  if (typeof show == 'undefined') 
     151    show = obj.is(':visible') ? false : true; 
     152   
     153  var ref = rcube_find_object(refname); 
     154  if (show && ref) { 
     155    var pos = $(ref).offset(); 
     156    obj.css({ left:pos.left, top:(pos.top + (above ? -obj.height() : ref.offsetHeight)) }); 
     157  } 
     158   
     159  obj[show?'show':'hide'](); 
     160}, 
     161 
    138162show_markmenu: function(show) 
    139163{ 
    140   if (typeof show == 'undefined') 
    141     show = this.markmenu.is(':visible') ? false : true; 
    142    
    143   var ref = rcube_find_object('markreadbutton'); 
    144   if (show && ref) 
    145     this.markmenu.css({ left:ref.offsetLeft, top:(ref.offsetTop + ref.offsetHeight) }); 
    146    
    147   this.markmenu[show?'show':'hide'](); 
     164  this.show_popupmenu(this.markmenu, 'markreadbutton', show); 
    148165}, 
    149166 
    150167show_messagemenu: function(show) 
    151168{ 
    152   if (typeof show == 'undefined') 
    153     show = this.messagemenu.is(':visible') ? false : true; 
    154  
    155   var ref = rcube_find_object('messagemenulink'); 
    156   if (show && ref) 
    157     this.messagemenu.css({ left:ref.offsetLeft, top:(ref.offsetTop + ref.offsetHeight) }); 
    158  
    159   this.messagemenu[show?'show':'hide'](); 
     169  this.show_popupmenu(this.messagemenu, 'messagemenulink', show); 
     170}, 
     171 
     172show_groupmenu: function(show) 
     173{ 
     174  this.show_popupmenu(this.groupmenu, 'groupactionslink', show, true); 
    160175}, 
    161176 
     
    268283  else if (this.dragmessagemenu && this.dragmessagemenu.is(':visible') && !rcube_mouse_is_over(evt, rcube_find_object('dragmessagemenu'))) 
    269284    this.dragmessagemenu.hide(); 
     285  else if (this.groupmenu &&  this.groupmenu.is(':visible') && target != rcube_find_object('groupactionslink')) 
     286    this.show_groupmenu(false); 
    270287  else if (this.listmenu && this.listmenu.is(':visible') && target != rcube_find_object('listmenulink')) { 
    271288    var menu = rcube_find_object('listmenu'); 
     
    291308{ 
    292309  if (rcube_event.get_keycode(evt) == 27) { 
    293     if (this.markmenu && this.markmenu.is(':visible')) 
    294       this.show_markmenu(false); 
    295     if (this.searchmenu && this.searchmenu.is(':visible')) 
    296       this.show_searchmenu(false); 
    297     if (this.messagemenu && this.messagemenu.is(':visible')) 
    298       this.show_messagemenu(false); 
    299     if (this.listmenu && this.listmenu.is(':visible')) 
    300       this.show_listmenu(false); 
    301     if (this.dragmessagemenu && this.dragmessagemenu.is(':visible')) 
    302       this.dragmessagemenu.hide(); 
     310    for (var k in this.popupmenus) { 
     311      if (this[k] && this[k].is(':visible')) 
     312        this[k].hide(); 
     313    } 
    303314  } 
    304315} 
     
    313324  rcube_event.add_listener({ object:rcmail_ui, method:'body_mouseup', event:'mouseup' }); 
    314325  rcube_event.add_listener({ object:rcmail_ui, method:'body_keypress', event:'keypress' }); 
    315   rcmail.addEventListener('menu-open', 'open_listmenu', rcmail_ui); 
    316   rcmail.addEventListener('menu-save', 'save_listmenu', rcmail_ui); 
    317   rcmail.gui_object('message_dragmenu', 'dragmessagemenu'); 
    318 } 
     326  if (rcmail.env.task == 'mail') { 
     327    rcmail.addEventListener('menu-open', 'open_listmenu', rcmail_ui); 
     328    rcmail.addEventListener('menu-save', 'save_listmenu', rcmail_ui); 
     329    rcmail.gui_object('message_dragmenu', 'dragmessagemenu'); 
     330  } 
     331} 
  • skins/default/mail.css

    rfb7ec57 ra61bbb2  
    687687#messagelist thead tr td.sortedDESC 
    688688{ 
    689   background-position: 0 -20px; 
     689  background-position: 0 -22px; 
    690690} 
    691691 
  • skins/default/templates/addressbook.html

    rd4a2c0c ra61bbb2  
    55<roundcube:include file="/includes/links.html" /> 
    66<script type="text/javascript" src="/splitter.js"></script> 
    7  
     7<script type="text/javascript" src="/functions.js"></script> 
    88<style type="text/css"> 
    9 <roundcube:if condition="count(env:address_sources) &lt;= 1" /> 
    10 #abookcountbar { left: 20px; } 
    11 #addressscreen { left: 20px;  
    12 <roundcube:exp expression="browser:ie ? 'width:expression((parseInt(document.documentElement.clientWidth)-40)+\\'px\\');' : ''" /> 
    13 } 
    149#addresslist { width: <roundcube:exp expression="!empty(cookie:addressviewsplitter) ? cookie:addressviewsplitter-5 : 245" />px; } 
    1510#contacts-box { left: <roundcube:exp expression="!empty(cookie:addressviewsplitter) ? cookie:addressviewsplitter+5 : 255" />px; 
    16 <roundcube:exp expression="browser:ie ? ('width:expression((parseInt(this.parentNode.offsetWidth)-'.(!empty(cookie:addressviewsplitter) ? cookie:addressviewsplitter+5 : 255).')+\\'px\\');') : ''" /> 
     11        <roundcube:exp expression="browser:ie ? ('width:expression((parseInt(this.parentNode.offsetWidth)-'.(!empty(cookie:addressviewsplitter) ? cookie:addressviewsplitter+5 : 255).')+\\'px\\');') : ''" /> 
    1712} 
    18 <roundcube:else /> 
    19 #addresslist { width: <roundcube:exp expression="!empty(cookie:addressviewsplitter) ? cookie:addressviewsplitter-5 : 245" />px; } 
    20 #contacts-box { left: <roundcube:exp expression="!empty(cookie:addressviewsplitter) ? cookie:addressviewsplitter+5 : 255" />px; 
    21 <roundcube:exp expression="browser:ie ? ('width:expression((parseInt(this.parentNode.offsetWidth)-'.(!empty(cookie:addressviewsplitter) ? cookie:addressviewsplitter+5 : 255).')+\\'px\\');') : ''" /> 
    22 } 
    23 <roundcube:endif /> 
    2413</style> 
    2514 
    2615</head> 
    27 <body> 
     16<body onload="rcube_init_mail_ui()"> 
    2817 
    2918<roundcube:include file="/includes/taskbar.html" /> 
     
    4635</div> 
    4736 
    48 <roundcube:if condition="count(env:address_sources) &gt; 1" /> 
    49 <div id="directorylist"> 
     37<div id="directorylistbox"> 
    5038<div id="groups-title" class="boxtitle"><roundcube:label name="groups" /></div> 
    51 <roundcube:object name="directorylist" id="directories-list" /> 
     39<div id="directorylistwarp"> 
     40  <roundcube:object name="directorylist" id="directorylist" /> 
     41  <roundcube:object name="groupslist" id="contactgroupslist" /> 
    5242</div> 
    53 <roundcube:endif /> 
     43<div id="directoylistbuttons"> 
     44  <roundcube:button command="add-group" type="link" title="newcontactgroup" class="buttonPas addgroup" classAct="button addgroup" content=" " /> 
     45  <roundcube:button name="groupactions" id="groupactionslink" type="link" title="groupactions" class="button groupactions" onclick="rcmail_ui.show_groupmenu();return false" content=" " /> 
     46</div> 
     47</div> 
     48 
     49<div id="groupoptionsmenu" class="popupmenu"> 
     50  <ul> 
     51    <li><roundcube:button command="rename-group" label="rename" classAct="active" /></li> 
     52    <li><roundcube:button command="delete-group" label="delete" classAct="active" /></li> 
     53  </ul> 
     54</div> 
    5455 
    5556<div id="addressscreen"> 
  • skins/default/templates/mail.html

    rfb7ec57 ra61bbb2  
    120120<roundcube:button name="markreadbutton" id="markreadbutton" type="link" class="button markmessage" title="markmessages" onclick="rcmail_ui.show_markmenu();return false" content=" " /> 
    121121<roundcube:button name="messagemenulink" id="messagemenulink" type="link" class="button messagemenu" title="messageactions" onclick="rcmail_ui.show_messagemenu();return false" content=" " /> 
     122</div> 
    122123 
    123124<div id="markmessagemenu" class="popupmenu"> 
     
    132133 
    133134<roundcube:include file="/includes/messagemenu.html" /> 
    134  
    135 </div> 
    136135 
    137136<div id="searchmenu" class="popupmenu"> 
Note: See TracChangeset for help on using the changeset viewer.