diff options
| -rw-r--r-- | program/include/main.inc | 88 | ||||
| -rw-r--r-- | program/js/app.js | 72 | ||||
| -rw-r--r-- | program/js/common.js | 26 | ||||
| -rw-r--r-- | program/js/list.js | 15 | ||||
| -rw-r--r-- | program/steps/addressbook/func.inc | 48 | ||||
| -rw-r--r-- | skins/default/addresses.css | 9 | ||||
| -rw-r--r-- | skins/default/mail.css | 5 | 
7 files changed, 142 insertions, 121 deletions
| diff --git a/program/include/main.inc b/program/include/main.inc index a6ad93d2b..87c727700 100644 --- a/program/include/main.inc +++ b/program/include/main.inc @@ -929,11 +929,11 @@ function rcmail_mailbox_list($attrib)      $out = $select->show();    }    else { -    $out = html::tag('ul', $attrib, rcmail_render_folder_tree_html($a_mailboxes, $mbox_name, $attrib['maxlength'], $attrib['realnames']), html::$common_attrib); -  } - -  if ($type=='ul') { +    $js_mailboxlist = array(); +    $out = html::tag('ul', $attrib, rcmail_render_folder_tree_html($a_mailboxes, $mbox_name, $js_mailboxlist, $attrib), html::$common_attrib); +          $RCMAIL->output->add_gui_object('mailboxlist', $attrib['id']); +    $RCMAIL->output->set_env('mailboxes', $js_mailboxlist);      $RCMAIL->output->set_env('collapsed_folders', $RCMAIL->config->get('collapsed_folders'));    } @@ -973,64 +973,68 @@ function rcmail_mailbox_select($p = array())   * @access private   */  function rcmail_build_folder_tree(&$arrFolders, $folder, $delm='/', $path='') -  { +{    $pos = strpos($folder, $delm); -  if ($pos !== false) -    { +  if ($pos !== false) {      $subFolders = substr($folder, $pos+1);      $currentFolder = substr($folder, 0, $pos); -    } -  else -    { +    $virtual = !isset($arrFolders[$currentFolder]); +  } +  else {      $subFolders = false;      $currentFolder = $folder; -    } +    $virtual = false; +  }    $path .= $currentFolder; -  if (!isset($arrFolders[$currentFolder])) -    { +  if (!isset($arrFolders[$currentFolder])) {      $arrFolders[$currentFolder] = array(        'id' => $path,        'name' => rcube_charset_convert($currentFolder, 'UTF-7'), +      'virtual' => $virtual,        'folders' => array()); -    } +  } +  else +    $arrFolders[$currentFolder]['virtual'] = $virtual;    if (!empty($subFolders))      rcmail_build_folder_tree($arrFolders[$currentFolder]['folders'], $subFolders, $delm, $path.$delm); -  } +}  /**   * Return html for a structured list <ul> for the mailbox tree   * @access private   */ -function rcmail_render_folder_tree_html(&$arrFolders, &$mbox_name, $maxlength, $realnames=false, $nestLevel=0) -  { +function rcmail_render_folder_tree_html(&$arrFolders, &$mbox_name, &$jslist, $attrib, $nestLevel=0) +{    global $RCMAIL, $CONFIG; +   +  $maxlength = intval($attrib['maxlength']); +  $realnames = (bool)$attrib['realnames']; +  $msgcounts = $RCMAIL->imap->get_cache('messagecount');    $idx = 0;    $out = ''; -  foreach ($arrFolders as $key => $folder) -    { +  foreach ($arrFolders as $key => $folder) {      $zebra_class = (($nestLevel+1)*$idx) % 2 == 0 ? 'even' : 'odd';      $title = null; -    if (($folder_class = rcmail_folder_classname($folder['id'])) && !$realnames) +    if (($folder_class = rcmail_folder_classname($folder['id'])) && !$realnames) {        $foldername = rcube_label($folder_class); -    else -      { +    } +    else {        $foldername = $folder['name'];        // shorten the folder name to a given length -      if ($maxlength && $maxlength>1) -        { +      if ($maxlength && $maxlength > 1) {          $fname = abbreviate_string($foldername, $maxlength);          if ($fname != $foldername)            $title = $foldername;          $foldername = $fname; -        }        } +    }      // make folder name safe for ids and class names      $folder_id = asciiwords($folder['id'], true); @@ -1054,35 +1058,45 @@ function rcmail_render_folder_tree_html(&$arrFolders, &$mbox_name, $maxlength, $        $classes[] = 'selected';      $collapsed = preg_match('/&'.rawurlencode($folder['id']).'&/', $RCMAIL->config->get('collapsed_folders')); +    $unread = $msgcounts ? intval($msgcounts[$folder['id']]['UNSEEN']) : 0; +     +    if ($folder['virtual']) +      $classes[] = 'virtual'; +    else if ($unread) +      $classes[] = 'unread';      $js_name = JQ($folder['id']); +    $html_name = Q($foldername . ($unread ? " ($unread)" : '')); +    $link_attrib = $folder['virtual'] ? array() : array( +      'href' => rcmail_url('', array('_mbox' => $folder['id'])), +      'onclick' => sprintf("return %s.command('list','%s',this)", JS_OBJECT_NAME, $js_name), +      'title' => $title, +    ); +      $out .= html::tag('li', array(          'id' => "rcmli".$folder_id,          'class' => join(' ', $classes),          'noclose' => true), -      html::a(array( -        'href' => rcmail_url('', array('_mbox' => $folder['id'])), -        'onclick' => sprintf("return %s.command('list','%s',this)", JS_OBJECT_NAME, $js_name), -        'onmouseover' => sprintf("return %s.focus_folder('%s')", JS_OBJECT_NAME, $js_name), -        'onmouseout' => sprintf("return %s.unfocus_folder('%s')", JS_OBJECT_NAME, $js_name), -        'onmouseup' => sprintf("return %s.folder_mouse_up('%s')", JS_OBJECT_NAME, $js_name), -        'title' => $title, -      ), Q($foldername)) . +      html::a($link_attrib, $html_name) .        (!empty($folder['folders']) ? html::div(array(          'class' => ($collapsed ? 'collapsed' : 'expanded'),          'style' => "position:absolute",          'onclick' => sprintf("%s.command('collapse-folder', '%s')", JS_OBJECT_NAME, $js_name)        ), ' ') : '')); -    if (!empty($folder['folders'])) -      $out .= "\n<ul" . ($collapsed ? " style=\"display: none;\"" : "") . ">\n" . rcmail_render_folder_tree_html($folder['folders'], $mbox_name, $maxlength, $realnames, $nestLevel+1) . "</ul>\n"; +    $jslist[$folder_id] = array('id' => $folder['id'], 'name' => $foldername, 'virtual' => $folder['virtual']); +     +    if (!empty($folder['folders'])) { +      $out .= html::tag('ul', array('style' => ($collapsed ? "display:none;" : null)), +        rcmail_render_folder_tree_html($folder['folders'], $mbox_name, $jslist, $attrib, $nestLevel+1)); +    }      $out .= "</li>\n";      $idx++; -    } +  }    return $out; -  } +}  /** diff --git a/program/js/app.js b/program/js/app.js index 3812a73de..36072e384 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -133,6 +133,7 @@ function rcube_webmail()            this.message_list.addEventListener('keypress', function(o){ p.msglist_keypress(o); });            this.message_list.addEventListener('select', function(o){ p.msglist_select(o); });            this.message_list.addEventListener('dragstart', function(o){ p.drag_active = true; if (p.preview_timer) clearTimeout(p.preview_timer); }); +          this.message_list.addEventListener('dragmove', function(o, e){ p.drag_move(e); });            this.message_list.addEventListener('dragend', function(o){ p.drag_active = false; });            this.message_list.init(); @@ -252,6 +253,7 @@ function rcube_webmail()            this.contact_list.addEventListener('keypress', function(o){ p.contactlist_keypress(o); });            this.contact_list.addEventListener('select', function(o){ p.contactlist_select(o); });            this.contact_list.addEventListener('dragstart', function(o){ p.drag_active = true; }); +          this.contact_list.addEventListener('dragmove', function(o, e){ p.drag_move(e); });            this.contact_list.addEventListener('dragend', function(o){ p.drag_active = false; });            this.contact_list.init(); @@ -1158,27 +1160,43 @@ function rcube_webmail()    this.doc_mouse_up = function(e) -    { -    if (this.message_list) +  { +    var model, li; +     +    if (this.message_list) {        this.message_list.blur(); -    else if (this.contact_list) +      model = this.env.mailboxes; +    } +    else if (this.contact_list) {        this.contact_list.blur(); -    }; - -  this.focus_folder = function(id) -    { -    var li; -    if (this.drag_active && this.check_droptarget(id) && (li = this.get_folder_li(id))) -      this.set_classname(li, 'droptarget', true); +      model = this.env.address_sources; +    } +     +    // handle mouse release when dragging +    if (this.drag_active && model) { +      for (var k in model) { +        if ((li = this.get_folder_li(k)) && rcube_mouse_is_over(e, li.firstChild) && this.check_droptarget(k)) { +          this.set_classname(li, 'droptarget', false); +          this.command('moveto', model[k].id); +          break; +        } +      }      } +  }; -  this.unfocus_folder = function(id) -    { +  this.drag_move = function(e) +  {      var li; -    if (this.drag_active && (li = this.get_folder_li(id))) -      this.set_classname(li, 'droptarget', false); +    var model = this.task == 'mail' ? this.env.mailboxes : this.env.address_sources; +     +    if (this.gui_objects.folderlist && model) { +      for (var k in model) { +        if (li = this.get_folder_li(k)) +          this.set_classname(li, 'droptarget', (rcube_mouse_is_over(e, li.firstChild) && this.check_droptarget(k))); +      }      } - +  }; +      this.collapse_folder = function(id)      {      var div; @@ -1211,16 +1229,6 @@ function rcube_webmail()        }      } -  // onmouseup handler for folder list item -  this.folder_mouse_up = function(id) -    { -    if (this.drag_active) -      { -      this.unfocus_folder(id); -      this.command('moveto', id); -      } -    }; -    this.click_on_list = function(e)      {      if (this.message_list) @@ -1232,7 +1240,7 @@ function rcube_webmail()      if (mbox_li = this.get_folder_li())        this.set_classname(mbox_li, 'unfocused', true); -    rcube_event.cancel(e); +    return rcube_event.get_button(e) == 2 ? true : rcube_event.cancel(e);      }; @@ -1303,7 +1311,7 @@ function rcube_webmail()    this.check_droptarget = function(id)    {      if (this.task == 'mail') -      return (id != this.env.mailbox); +      return (this.env.mailboxes[id] && this.env.mailboxes[id].id != this.env.mailbox && !this.env.mailboxes[id].virtual);      else if (this.task == 'addressbook')        return (id != this.env.source && this.env.address_sources[id] && !this.env.address_sources[id].readonly);      else if (this.task == 'settings') @@ -3009,12 +3017,12 @@ function rcube_webmail()        row.id = id;        if (before && (before = this.get_folder_row_id(before))) -	tbody.insertBefore(row, document.getElementById(before)); +        tbody.insertBefore(row, document.getElementById(before));        else -        tbody.appendChild(row);	   +        tbody.appendChild(row);        if (replace) -	tbody.removeChild(replace); +        tbody.removeChild(replace);        }      // add to folder/row-ID map @@ -3136,9 +3144,9 @@ function rcube_webmail()      {      var cell, td;      var new_row = document.createElement('TR'); -    for(var n=0; n<row.childNodes.length; n++) +    for(var n=0; n<row.cells.length; n++)        { -      cell = row.childNodes[n]; +      cell = row.cells[n];        td = document.createElement('TD');        if (cell.className) diff --git a/program/js/common.js b/program/js/common.js index 6e4c643fa..209ce1070 100644 --- a/program/js/common.js +++ b/program/js/common.js @@ -114,6 +114,15 @@ get_keycode: function(e)  },  /** + * returns the event key code + */ +get_button: function(e) +{ +  e = e || window.event; +  return e && (typeof e.button != 'undefined') ? e.button : (e && e.which ? e.which : 0); +}, + +/**   * returns modifier key (constants defined at top of file)   */  get_modifier: function(e) @@ -502,18 +511,25 @@ function rcube_get_object_pos(obj)      var elm = obj.offsetParent;      while(elm && elm!=null)        { -      iX += elm.offsetLeft; -      iY += elm.offsetTop; +      iX += elm.offsetLeft - (elm.parentNode && elm.parentNode.scrollLeft ? elm.parentNode.scrollLeft : 0); +      iY += elm.offsetTop - (elm.parentNode && elm.parentNode.scrollTop ? elm.parentNode.scrollTop : 0);        elm = elm.offsetParent;        }      } -  //if(bw.mac && bw.ie5) iX += document.body.leftMargin; -  //if(bw.mac && bw.ie5) iY += document.body.topMargin; -    return {x:iX, y:iY};    } +// determine whether the mouse is over the given object or not +function rcube_mouse_is_over(ev, obj) +{ +  var mouse = rcube_event.get_mouse_pos(ev); +  var pos = rcube_get_object_pos(obj); +   +  return ((mouse.x >= pos.x) && (mouse.x < (pos.x + obj.offsetWidth)) && +    (mouse.y >= pos.y) && (mouse.y < (pos.y + obj.offsetHeight))); +} +  /**   * Return the currently applied value of a css property diff --git a/program/js/list.js b/program/js/list.js index f33c67c7b..926d98aa7 100644 --- a/program/js/list.js +++ b/program/js/list.js @@ -51,7 +51,7 @@ function rcube_list_widget(list, p)    this.drag_mouse_start = null;    this.dblclick_time = 600;    this.row_init = function(){}; -  this.events = { click:[], dblclick:[], select:[], keypress:[], dragstart:[], dragend:[] }; +  this.events = { click:[], dblclick:[], select:[], keypress:[], dragstart:[], dragmove:[], dragend:[] };    // overwrite default paramaters    if (p && typeof(p)=='object') @@ -221,7 +221,11 @@ drag_row: function(e, id)    var evtarget = rcube_event.get_target(e);    if (this.dont_select || (evtarget && (evtarget.tagName == 'INPUT' || evtarget.tagName == 'IMG')))      return false; - +     +  // accept right-clicks +  if (rcube_event.get_button(e) == 2) +    return true; +      this.in_selection_before = this.in_selection(id) ? id : false;    // selects currently unselected row @@ -576,7 +580,7 @@ key_press: function(e)        this.key_pressed = keyCode;        this.trigger_event('keypress'); -      if (this.key_pressed == list.BACKSPACE_KEY) +      if (this.key_pressed == this.BACKSPACE_KEY)          return rcube_event.cancel(e);    } @@ -704,6 +708,7 @@ drag_mouse_move: function(e)    {      var pos = rcube_event.get_mouse_pos(e);      this.draglayer.move(pos.x+20, pos.y-5); +    this.trigger_event('dragmove', e);    }    this.drag_start = false; @@ -784,12 +789,12 @@ removeEventListener: function(evt, handle)   * This will execute all registered event handlers   * @private   */ -trigger_event: function(evt) +trigger_event: function(evt, p)  {    if (this.events[evt] && this.events[evt].length) {      for (var i=0; i<this.events[evt].length; i++)        if (typeof(this.events[evt][i]) == 'function') -        this.events[evt][i](this); +        this.events[evt][i](this, p);    }  } diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc index 43d117430..98cf29f10 100644 --- a/program/steps/addressbook/func.inc +++ b/program/steps/addressbook/func.inc @@ -58,31 +58,15 @@ function rcmail_directory_list($attrib)    if (!$attrib['id'])      $attrib['id'] = 'rcmdirectorylist'; +  $out = '';    $local_id = '0';    $current = get_input_value('_source', RCUBE_INPUT_GPC); -  $line_templ = '<li id="%s" class="%s"><a href="%s"' . -    ' onclick="return %s.command(\'list\',\'%s\',this)"' . -    ' onmouseover="return %s.focus_folder(\'%s\')"' . -    ' onmouseout="return %s.unfocus_folder(\'%s\')"' . -    ' onmouseup="return %s.folder_mouse_up(\'%s\')">%s'. -    "</a></li>\n"; +  $line_templ = html::tag('li', array('id' => 'rcmli%s', 'class' => '%s'), +    html::a(array('href' => '%s', 'onclick' => "return ".JS_OBJECT_NAME.".command('list','%s',this)"), '%s')); -  // allow the following attributes to be added to the <ul> tag -  $out = '<ul' . create_attrib_string($attrib, array('style', 'class', 'id')) . ">\n";    if (strtolower($CONFIG['address_book_type']) != 'ldap') { -    $out .= sprintf($line_templ, -      'rcmli'.$local_id, -      !$current ? 'selected' : '', -      Q(rcmail_url(null, array('_source' => 0))), -      JS_OBJECT_NAME, -      $local_id, -      JS_OBJECT_NAME, -      $local_id, -      JS_OBJECT_NAME, -      $local_id, -      JS_OBJECT_NAME, -      $local_id, -      rcube_label('personaladrbook')); +    $out .= sprintf($line_templ, $local_id, (!$current ? 'selected' : ''), +      Q(rcmail_url(null, array('_source' => $local_id))), $local_id, rcube_label('personaladrbook'));    } // end if    else {      // DB address book not used, see if a source is set, if not use the @@ -92,30 +76,16 @@ function rcmail_directory_list($attrib)      } // end if    } // end else -  foreach ((array)$CONFIG['ldap_public'] as $id => $prop) -  { +  foreach ((array)$CONFIG['ldap_public'] as $id => $prop) {      $js_id = JQ($id);      $dom_id = preg_replace('/[^a-z0-9\-_]/i', '', $id); -    $out .= sprintf($line_templ, -      'rcmli'.$dom_id, -      $current == $id ? 'selected' : '', -      Q(rcmail_url(null, array('_source' => $id))), -      JS_OBJECT_NAME, -      $js_id, -      JS_OBJECT_NAME, -      $js_id, -      JS_OBJECT_NAME, -      $js_id, -      JS_OBJECT_NAME, -      $js_id, -      !empty($prop['name']) ? Q($prop['name']) : Q($id)); +    $out .= sprintf($line_templ, $dom_id, ($current == $id ? 'selected' : ''), +      Q(rcmail_url(null, array('_source' => $id))), $js_id, (!empty($prop['name']) ? Q($prop['name']) : Q($id)));    } -  $out .= '</ul>'; -    $OUTPUT->add_gui_object('folderlist', $attrib['id']); -  return $out; +  return html::tag('ul', $attrib, $out, html::$common_attrib);  } diff --git a/skins/default/addresses.css b/skins/default/addresses.css index 27612c304..8ae298781 100644 --- a/skins/default/addresses.css +++ b/skins/default/addresses.css @@ -45,12 +45,13 @@  #directorylist  {    left: 20px; -  width: 150px; +  width: 170px; +  overflow: hidden;  }  #addresslist  { -  left: 185px; +  left: 200px;    width: 340px;  } @@ -79,6 +80,7 @@  {    font-size: 11px;    border-bottom: 1px solid #EBEBEB; +  white-space: nowrap;  }  #directorylist ul li a @@ -88,6 +90,7 @@    padding-top: 2px;    padding-bottom: 2px;    text-decoration: none; +  white-space: nowrap;  }  #directorylist li.selected @@ -127,7 +130,7 @@  {    position: absolute;    top: 85px; -  left: 540px; +  left: 555px;    right: 20px;    bottom: 40px;    border: 1px solid #999999; diff --git a/skins/default/mail.css b/skins/default/mail.css index 2de775688..7807ca231 100644 --- a/skins/default/mail.css +++ b/skins/default/mail.css @@ -354,6 +354,11 @@ td.formlinks a:visited    font-weight: bold;  } +#mailboxlist li.virtual > a +{ +  color: #666; +} +  #mailboxlist li.selected,  #mailboxlist li.droptarget li.selected  { | 
