From 3cb61e7528c2a8544083bf14e02ea4b9387671fb Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Wed, 16 Jul 2014 05:08:11 -0400
Subject: [PATCH] Collapsible (and iconized) folders tree in folder manager (#1489648)

---
 program/js/treelist.js                 |   36 +
 skins/classic/templates/folders.html   |    2 
 program/steps/settings/folders.inc     |  114 +++-
 skins/larry/settings.css               |   13 
 skins/classic/common.css               |  154 ++++++
 skins/larry/templates/folders.html     |    2 
 skins/larry/templates/mail.html        |    2 
 program/steps/settings/edit_folder.inc |   36 
 skins/classic/mail.css                 |  146 ------
 skins/classic/templates/mail.html      |    2 
 program/steps/settings/func.inc        |   17 
 program/steps/settings/save_folder.inc |   10 
 skins/classic/settings.css             |   30 -
 skins/larry/styles.css                 |  218 +++++++++
 program/js/app.js                      |  306 +++++++------
 skins/larry/mail.css                   |  218 ---------
 16 files changed, 674 insertions(+), 632 deletions(-)

diff --git a/program/js/app.js b/program/js/app.js
index a47d971..895671a 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -544,7 +544,7 @@
     // select first input field in an edit form
     if (this.gui_objects.editform)
       $("input,select,textarea", this.gui_objects.editform)
-        .not(':hidden').not(':disabled').first().select();
+        .not(':hidden').not(':disabled').first().select().focus();
 
     // unset contentframe variable if preview_pane is enabled
     if (this.env.contentframe && !$('#' + this.env.contentframe).is(':visible'))
@@ -5793,39 +5793,52 @@
     this.last_sub_rx = RegExp('['+delim+']?[^'+delim+']+$');
 
     this.subscription_list = new rcube_treelist_widget(this.gui_objects.subscriptionlist, {
-        selectable: true
+        selectable: true,
+        id_prefix: 'rcmli',
+        id_encode: this.html_identifier_encode,
+        id_decode: this.html_identifier_decode
     });
 
     this.subscription_list
       .addEventListener('select', function(node) { ref.subscription_select(node.id); })
-      .draggable({cancel: '#mailboxroot'})
+      .addEventListener('collapse', function(node) { ref.folder_collapsed(node) })
+      .addEventListener('expand', function(node) { ref.folder_collapsed(node) })
+      .draggable({cancel: 'li.mailbox.root'})
       .droppable({
         // @todo: find better way, accept callback is executed for every folder
         // on the list when dragging starts (and stops), this is slow, but
         // I didn't find a method to check droptarget on over event
         accept: function(node) {
-          var source = ref.env.subscriptionrows[$(node).attr('id')],
-            dest = ref.env.subscriptionrows[this.id],
-            source_name = source[0],
-            dest_name = dest[0];
+          var source_folder = ref.folder_id2name($(node).attr('id')),
+            dest_folder = ref.folder_id2name(this.id),
+            source = ref.env.subscriptionrows[source_folder],
+            dest = ref.env.subscriptionrows[dest_folder];
 
-          return !source[2]
-            && dest_name != source_name.replace(ref.last_sub_rx, '')
-            && !dest_name.startsWith(source_name + ref.env.delimiter);
+          return source && !source[2]
+            && dest_folder != source_folder.replace(ref.last_sub_rx, '')
+            && !dest_folder.startsWith(source_folder + ref.env.delimiter);
         },
         drop: function(e, ui) {
-          ref.subscription_move_folder(ui.draggable.attr('id'), this.id);
+          var source = ref.folder_id2name(ui.draggable.attr('id')),
+            dest = ref.folder_id2name(this.id);
+
+          ref.subscription_move_folder(source, dest);
         }
       });
+  };
+
+  this.folder_id2name = function(id)
+  {
+    return ref.html_identifier_decode(id.replace(/^rcmli/, ''));
   };
 
   this.subscription_select = function(id)
   {
     var folder;
 
-    if (id && id != 'mailboxroot' && (folder = this.env.subscriptionrows[id])) {
-      this.env.mailbox = folder[0];
-      this.show_folder(folder[0]);
+    if (id && id != '*' && (folder = this.env.subscriptionrows[id])) {
+      this.env.mailbox = id;
+      this.show_folder(id);
       this.enable_command('delete-folder', !folder[2]);
     }
     else {
@@ -5837,16 +5850,13 @@
 
   this.subscription_move_folder = function(from, to)
   {
-    var source = this.env.subscriptionrows[from][0];
-      dest = this.env.subscriptionrows[to][0];
-
-    if (source && dest !== null && source != dest && dest != source.replace(this.last_sub_rx, '')) {
-      var path = source.split(this.env.delimiter),
+    if (from && to !== null && from != to && to != from.replace(this.last_sub_rx, '')) {
+      var path = from.split(this.env.delimiter),
         basename = path.pop(),
-        newname = dest === '' ? basename : dest + this.env.delimiter + basename;
+        newname = to === '' || to === '*' ? basename : to + this.env.delimiter + basename;
 
-      if (newname != source) {
-        this.http_post('rename-folder', {_folder_oldname: source, _folder_newname: newname},
+      if (newname != from) {
+        this.http_post('rename-folder', {_folder_oldname: from, _folder_newname: newname},
           this.set_busy(true, 'foldermoving'));
       }
     }
@@ -5861,50 +5871,51 @@
   // delete a specific mailbox with all its messages
   this.delete_folder = function(name)
   {
-    var id = this.get_folder_row_id(name ? name : this.env.mailbox),
-      folder = this.env.subscriptionrows[id][0];
+    if (!name)
+      name = this.env.mailbox;
 
-    if (folder && confirm(this.get_label('deletefolderconfirm'))) {
-      this.http_post('delete-folder', {_mbox: folder}, this.set_busy(true, 'folderdeleting'));
+    if (name && confirm(this.get_label('deletefolderconfirm'))) {
+      this.http_post('delete-folder', {_mbox: name}, this.set_busy(true, 'folderdeleting'));
     }
   };
 
   // Add folder row to the table and initialize it
-  this.add_folder_row = function (name, display_name, is_protected, subscribed, skip_init, class_name)
+  this.add_folder_row = function (id, name, display_name, is_protected, subscribed, class_name, refrow, subfolders)
   {
     if (!this.gui_objects.subscriptionlist)
       return false;
 
-    var row, n, tmp, tmp_name, rowid, collator,
+    var row, n, tmp, tmp_name, rowid, collator, pos, p, parent = '',
       folders = [], list = [], slist = [],
-      list_element = $(this.gui_objects.subscriptionlist),
-      refrow = $('li', list_element).get(1),
-      id = 'rcmli'+((new Date).getTime());
+      list_element = $(this.gui_objects.subscriptionlist);
+      row = refrow ? refrow : $($('li', list_element).get(1)).clone(true);
 
-    if (!refrow) {
+    if (!row.length) {
       // Refresh page if we don't have a table row to clone
       this.goto_url('folders');
       return false;
     }
 
-    // clone a table row if there are existing rows
-    row = $(refrow).clone(true);
-
     // set ID, reset css class
-    row.attr({id: id, 'class': class_name});
+    row.attr({id: 'rcmli' + this.html_identifier_encode(id), 'class': class_name});
+
+    if (!refrow || !refrow.length) {
+      // remove old subfolders and toggle
+      $('ul,div.treetoggle', row).remove();
+    }
 
     // set folder name
-    $('.name', row).html(display_name);
+    $('a:first', row).text(display_name);
 
     // update subscription checkbox
-    $('input[name="_subscribed[]"]', row).val(name)
+    $('input[name="_subscribed[]"]:first', row).val(id)
       .prop({checked: subscribed ? true : false, disabled: is_protected ? true : false});
 
     // add to folder/row-ID map
     this.env.subscriptionrows[id] = [name, display_name, false];
 
     // copy folders data to an array for sorting
-    $.each(this.env.subscriptionrows, function(k, v) { folders.push(v); });
+    $.each(this.env.subscriptionrows, function(k, v) { v[3] = k; folders.push(v); });
 
     try {
       // use collator if supported (FF29, IE11, Opera15, Chrome24)
@@ -5916,64 +5927,106 @@
     folders.sort(function(a, b) {
       var i, f1, f2,
         path1 = a[0].split(ref.env.delimiter),
-        path2 = b[0].split(ref.env.delimiter);
+        path2 = b[0].split(ref.env.delimiter),
+        len = path1.length;
 
-      for (i=0; i<path1.length; i++) {
+      for (i=0; i<len; i++) {
         f1 = path1[i];
         f2 = path2[i];
 
         if (f1 !== f2) {
+          if (f2 === undefined)
+            return 1;
           if (collator)
             return collator.compare(f1, f2);
           else
             return f1 < f2 ? -1 : 1;
         }
+        else if (i == len-1) {
+          return -1
+        }
       }
     });
 
     for (n in folders) {
+      p = folders[n][3];
       // protected folder
       if (folders[n][2]) {
-        tmp_name = folders[n][0] + this.env.delimiter;
+        tmp_name = p + this.env.delimiter;
         // prefix namespace cannot have subfolders (#1488349)
         if (tmp_name == this.env.prefix_ns)
           continue;
-        slist.push(folders[n][0]);
+        slist.push(p);
         tmp = tmp_name;
       }
       // protected folder's child
-      else if (tmp && folders[n][0].startsWith(tmp))
-        slist.push(folders[n][0]);
+      else if (tmp && p.startsWith(tmp))
+        slist.push(p);
       // other
       else {
-        list.push(folders[n][0]);
+        list.push(p);
         tmp = null;
       }
     }
 
     // check if subfolder of a protected folder
     for (n=0; n<slist.length; n++) {
-      if (name.startsWith(slist[n] + this.env.delimiter))
-        rowid = this.get_folder_row_id(slist[n]);
+      if (id.startsWith(slist[n] + this.env.delimiter))
+        rowid = slist[n];
     }
 
     // find folder position after sorting
     for (n=0; !rowid && n<list.length; n++) {
-      if (n && list[n] == name)
-        rowid = this.get_folder_row_id(list[n-1]);
+      if (n && list[n] == id)
+        rowid = list[n-1];
     }
 
     // add row to the table
-    if (rowid)
-      $('#' + rowid).after(row);
-    else
+    if (rowid && (n = this.subscription_list.get_item(rowid, true))) {
+      // find parent folder
+      if (pos = id.lastIndexOf(this.env.delimiter)) {
+        parent = id.substring(0, pos);
+        parent = this.subscription_list.get_item(parent, true);
+
+        // add required tree elements to the parent if not already there
+        if (!$('div.treetoggle', parent).length) {
+          $('<div>&nbsp;</div>').addClass('treetoggle collapsed').appendTo(parent);
+        }
+        if (!$('ul', parent).length) {
+          $('<ul>').css('display', 'none').appendTo(parent);
+        }
+      }
+
+      if (parent && n == parent) {
+        $('ul:first', parent).append(row);
+      }
+      else {
+        while (p = $(n).parent().parent().get(0)) {
+          if (parent && p == parent)
+            break;
+          if (!$(p).is('li.mailbox'))
+            break;
+          n = p;
+        }
+
+        $(n).after(row);
+      }
+    }
+    else {
       list_element.append(row);
+    }
+
+    // add subfolders
+    $.extend(this.env.subscriptionrows, subfolders || {});
 
     // update list widget
-    this.subscription_list.select();
+    this.subscription_list.reset(true);
+    this.subscription_select();
 
-    if (!skip_init)
-      this.init_subscription_list();
+    // expand parent
+    if (parent) {
+      this.subscription_list.expand(this.folder_id2name(parent.id));
+    }
 
     row = row.get(0);
     if (row.scrollIntoView)
@@ -5983,113 +6036,71 @@
   };
 
   // replace an existing table row with a new folder line (with subfolders)
-  this.replace_folder_row = function(oldfolder, newfolder, display_name, is_protected, class_name)
+  this.replace_folder_row = function(oldid, id, name, display_name, is_protected, class_name)
   {
     if (!this.gui_objects.subscriptionlist) {
       if (this.is_framed)
-        return parent.rcmail.replace_folder_row(oldfolder, newfolder, display_name, is_protected, class_name);
+        return parent.rcmail.replace_folder_row(oldid, id, name, display_name, is_protected, class_name);
 
       return false;
     }
 
-    var i, n, len, name, dispname, oldrow, tmprow, row, level,
-      folders = this.env.subscriptionrows,
-      id = this.get_folder_row_id(oldfolder),
-      prefix_len = oldfolder.length,
-      subscribed = $('input[name="_subscribed[]"]', $('#'+id)).prop('checked'),
-      // find subfolders of renamed folder
-      list = this.get_subfolders(oldfolder);
+    var subfolders = {},
+      row = this.subscription_list.get_item(oldid, true),
+      parent = $(row).parent(),
+      old_folder = this.env.subscriptionrows[oldid],
+      prefix_len_id = oldid.length,
+      prefix_len_name = old_folder[0].length,
+      subscribed = $('input[name="_subscribed[]"]:first', row).prop('checked');
 
     // no renaming, only update class_name
-    if (oldfolder == newfolder) {
-      $('#'+id).attr('class', class_name || '');
+    if (oldid == id) {
+      $(row).attr('class', class_name || '');
       return;
     }
 
-    // replace an existing table row
-    this._remove_folder_row(id);
-    row = $(this.add_folder_row(newfolder, display_name, is_protected, subscribed, true, class_name));
+    // update subfolders
+    $('li', row).each(function() {
+      var fname = ref.folder_id2name(this.id),
+        folder = ref.env.subscriptionrows[fname],
+        newid = id + fname.slice(prefix_len_id);
 
-    // detect tree depth change
-    if (len = list.length) {
-      level = (oldfolder.split(this.env.delimiter)).length - (newfolder.split(this.env.delimiter)).length;
+      this.id = 'rcmli' + ref.html_identifier_encode(newid);
+      $('input[name="_subscribed[]"]:first', this).val(newid);
+      folder[0] = name + folder[0].slice(prefix_len_name);
+
+      subfolders[newid] = folder;
+      delete ref.env.subscriptionrows[fname];
+    });
+
+    // get row off the list
+    row = $(row).detach();
+
+    delete this.env.subscriptionrows[oldid];
+
+    // remove parent list/toggle elements if not needed
+    if (parent.get(0) != this.gui_objects.subscriptionlist && !$('li', parent).length) {
+      $('ul,div.treetoggle', parent.parent()).remove();
     }
 
-    // move subfolders to the new branch
-    for (n=0; n<len; n++) {
-      id = list[n];
-      name = this.env.subscriptionrows[id][0];
-      dispname = this.env.subscriptionrows[id][1];
-      oldrow = $('#'+id);
-      tmprow = oldrow.clone(true);
-      oldrow.remove();
-      row.after(tmprow);
-      row = tmprow;
-      // update folder index
-      name = newfolder + name.slice(prefix_len);
-      $('input[name="_subscribed[]"]', row).val(name);
-      this.env.subscriptionrows[id][0] = name;
-      // update the name if level is changed
-      if (level != 0) {
-        if (level > 0) {
-          for (i=level; i>0; i--)
-            dispname = dispname.replace(/^&nbsp;&nbsp;&nbsp;&nbsp;/, '');
-        }
-        else {
-          for (i=level; i<0; i++)
-            dispname = '&nbsp;&nbsp;&nbsp;&nbsp;' + dispname;
-        }
-        $('.name', row).html(dispname);
-        this.env.subscriptionrows[id][1] = dispname;
-      }
-    }
-
-    // update list widget
-    this.init_subscription_list();
+    // move the existing table row
+    this.add_folder_row(id, name, display_name, is_protected, subscribed, class_name, row, subfolders);
   };
 
   // remove the table row of a specific mailbox from the table
-  this.remove_folder_row = function(folder, subs)
+  this.remove_folder_row = function(folder)
   {
-    var n, len, list = [], id = this.get_folder_row_id(folder);
+    var list = [], row = this.subscription_list.get_item(folder, true);
 
     // get subfolders if any
-    if (subs)
-      list = this.get_subfolders(folder);
+    $('li', row).each(function() { list.push(ref.folder_id2name(this.id)); });
 
-    // remove old row
-    this._remove_folder_row(id);
+    // remove folder row (and subfolders)
+    this.subscription_list.remove(folder);
 
-    // remove subfolders
-    for (n=0, len=list.length; n<len; n++)
-      this._remove_folder_row(list[n]);
-  };
-
-  this._remove_folder_row = function(id)
-  {
-    this.subscription_list.remove(id.replace(/^rcmli/, ''));
-    $('#' + id).remove();
-    delete this.env.subscriptionrows[id];
-  };
-
-  this.get_subfolders = function(folder)
-  {
-    var name, list = [],
-      prefix = folder + this.env.delimiter,
-      row = $('#'+this.get_folder_row_id(folder)).get(0);
-
-    while (row = row.nextSibling) {
-      if (row.id) {
-        name = this.env.subscriptionrows[row.id][0];
-        if (name && name.startsWith(prefix)) {
-          list.push(row.id);
-        }
-        else
-          break;
-      }
-    }
-
-    return list;
+    // update local list variable
+    list.push(folder);
+    $.each(list, function(i, v) { delete ref.env.subscriptionrows[v]; });
   };
 
   this.subscribe = function(folder)
@@ -6106,15 +6117,6 @@
       var lock = this.display_message(this.get_label('folderunsubscribing'), 'loading');
       this.http_post('unsubscribe', {_mbox: folder}, lock);
     }
-  };
-
-  // helper method to find a specific mailbox row ID
-  this.get_folder_row_id = function(folder)
-  {
-    var id, folders = this.env.subscriptionrows;
-    for (id in folders)
-      if (folders[id] && folders[id][0] == folder)
-        return id;
   };
 
   // when user select a folder in manager
@@ -6140,9 +6142,9 @@
   // disables subscription checkbox (for protected folder)
   this.disable_subscription = function(folder)
   {
-    var id = this.get_folder_row_id(folder);
-    if (id)
-      $('input[name="_subscribed[]"]', $('#'+id)).prop('disabled', true);
+    var row = this.subscription_list.get_item(folder, true);
+    if (row)
+      $('input[name="_subscribed[]"]:first', row).prop('disabled', true);
   };
 
   this.folder_size = function(folder)
diff --git a/program/js/treelist.js b/program/js/treelist.js
index 6a5518a..ab13630 100644
--- a/program/js/treelist.js
+++ b/program/js/treelist.js
@@ -68,6 +68,8 @@
     tree_state,
     ui_droppable,
     ui_draggable,
+    draggable_opts,
+    droppable_opts,
     list_id = (container.attr('id') || p.id_prefix || '0'),
     me = this;
 
@@ -470,7 +472,7 @@
   /**
    *
    */
-  function reset()
+  function reset(keep_content)
   {
     select('');
 
@@ -478,7 +480,22 @@
     indexbyid = {};
     drag_active = false;
 
-    container.html('');
+    if (keep_content) {
+      if (draggable_opts) {
+        draggable('destroy');
+        draggable(draggable_opts);
+      }
+
+      if (droppable_opts) {
+        droppable('destroy');
+        droppable(droppable_opts);
+      }
+
+      update_data();
+    }
+    else {
+      container.html('');
+    }
 
     reset_search();
   }
@@ -1043,6 +1060,13 @@
   {
     if (!opts) opts = {};
 
+    if ($.type(opts) == 'string') {
+      $('li:not(.virtual)', container).droppable(opts);
+      return this;
+    }
+
+    droppable_opts = opts;
+
     var my_opts = $.extend({
         greedy: true,
         tolerance: 'pointer',
@@ -1084,8 +1108,16 @@
   {
     if (!opts) opts = {};
 
+    if ($.type(opts) == 'string') {
+      $('li:not(.virtual)', container).draggable(opts);
+      return this;
+    }
+
+    draggable_opts = opts;
+
     var my_opts = $.extend({
         appendTo: 'body',
+        revert: 'invalid',
         iframeFix: true,
         addClasses: false,
         cursorAt: {left: -20, top: 5},
diff --git a/program/steps/settings/edit_folder.inc b/program/steps/settings/edit_folder.inc
index 51f4d8d..172a953 100644
--- a/program/steps/settings/edit_folder.inc
+++ b/program/steps/settings/edit_folder.inc
@@ -38,22 +38,20 @@
     $storage = $RCMAIL->get_storage();
 
     // edited folder name (empty in create-folder mode)
-    $mbox      = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_GPC, true);
-    $mbox_imap = rcube_charset::convert($mbox, RCUBE_CHARSET, 'UTF7-IMAP');
+    $mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_GPC, true);
 
     // predefined path for new folder
-    $parent      = rcube_utils::get_input_value('_path', rcube_utils::INPUT_GPC, true);
-    $parent_imap = rcube_charset::convert($parent, RCUBE_CHARSET, 'UTF7-IMAP');
+    $parent = rcube_utils::get_input_value('_path', rcube_utils::INPUT_GPC, true);
 
     $threading_supported = $storage->get_capability('THREAD');
     $delimiter = $storage->get_hierarchy_delimiter();
 
     // Get mailbox parameters
     if (strlen($mbox)) {
-        $options   = rcmail_folder_options($mbox_imap);
+        $options   = rcmail_folder_options($mbox);
         $namespace = $storage->get_namespace();
 
-        $path   = explode($delimiter, $mbox_imap);
+        $path   = explode($delimiter, $mbox);
         $folder = array_pop($path);
         $path   = implode($delimiter, $path);
         $folder = rcube_charset::convert($folder, 'UTF7-IMAP');
@@ -62,7 +60,7 @@
     }
     else {
         $options = array();
-        $path    = $parent_imap;
+        $path    = $parent;
 
         // allow creating subfolders of INBOX folder
         if ($path == 'INBOX') {
@@ -88,7 +86,7 @@
 
     // Location (name)
     if ($options['protected']) {
-        $foldername = str_replace($delimiter, ' &raquo; ', rcube::Q($RCMAIL->localize_folderpath($mbox_imap)));
+        $foldername = str_replace($delimiter, ' &raquo; ', rcube::Q($RCMAIL->localize_folderpath($mbox)));
     }
     else if ($options['norename']) {
         $foldername = rcube::Q($folder);
@@ -101,7 +99,7 @@
         $foldername = $foldername->show($folder);
 
         if ($options['special']) {
-            $foldername .= '&nbsp;(' . rcube::Q($RCMAIL->localize_foldername($mbox_imap)) .')';
+            $foldername .= '&nbsp;(' . rcube::Q($RCMAIL->localize_foldername($mbox)) .')';
         }
     }
 
@@ -122,7 +120,7 @@
     }
     else {
         $selected = isset($_POST['_parent']) ? $_POST['_parent'] : $path_id;
-        $exceptions = array($mbox_imap);
+        $exceptions = array($mbox);
 
         // Exclude 'prefix' namespace from parent folders list (#1488349)
         // If INBOX. namespace exists, folders created as INBOX subfolders
@@ -154,7 +152,7 @@
     );
 
     // Settings: threading
-    if ($threading_supported && ($mbox_imap == 'INBOX' || (!$options['noselect'] && !$options['is_root']))) {
+    if ($threading_supported && ($mbox == 'INBOX' || (!$options['noselect'] && !$options['is_root']))) {
         $select = new html_select(array('name' => '_viewmode', 'id' => '_viewmode'));
         $select->add($RCMAIL->gettext('list'), 0);
         $select->add($RCMAIL->gettext('threads'), 1);
@@ -162,11 +160,11 @@
         if (isset($_POST['_viewmode'])) {
             $value = (int) $_POST['_viewmode'];
         }
-        else if (strlen($mbox_imap)) {
+        else if (strlen($mbox)) {
             $a_threaded   = $RCMAIL->config->get('message_threading', array());
             $default_mode = $RCMAIL->config->get('default_list_mode', 'list');
 
-            $value = (int) (isset($a_threaded[$mbox_imap]) ? $a_threaded[$mbox_imap] : $default_mode == 'threads');
+            $value = (int) (isset($a_threaded[$mbox]) ? $a_threaded[$mbox] : $default_mode == 'threads');
         }
 
         $form['props']['fieldsets']['settings']['content']['viewmode'] = array(
@@ -213,14 +211,14 @@
             'content' => array()
         );
 
-        if ((!$options['noselect'] && !$options['is_root']) || $mbox_imap == 'INBOX') {
-            $msgcount = $storage->count($mbox_imap, 'ALL', true, false);
+        if ((!$options['noselect'] && !$options['is_root']) || $mbox == 'INBOX') {
+            $msgcount = $storage->count($mbox, 'ALL', true, false);
 
             // Size
             if ($msgcount) {
                 // create link with folder-size command
                 $onclick = sprintf("return %s.command('folder-size', '%s', this)",
-                    rcmail_output::JS_OBJECT_NAME, rcube::JQ($mbox_imap));
+                    rcmail_output::JS_OBJECT_NAME, rcube::JQ($mbox));
                 $size = html::a(array('href' => '#', 'onclick' => $onclick,
                     'id' => 'folder-size'), $RCMAIL->gettext('getfoldersize'));
             }
@@ -250,7 +248,7 @@
     // Allow plugins to modify folder form content
     $plugin = $RCMAIL->plugins->exec_hook('folder_form',
         array('form' => $form, 'options' => $options,
-            'name' => $mbox_imap, 'parent_name' => $parent_imap));
+            'name' => $mbox, 'parent_name' => $parent));
 
     $form = $plugin['form'];
 
@@ -290,8 +288,8 @@
 
     $RCMAIL->output->set_env('messagecount', (int) $msgcount);
 
-    if ($mbox_imap !== null && empty($_POST)) {
-        $RCMAIL->output->command('parent.set_quota', $RCMAIL->quota_content(null, $mbox_imap));
+    if ($mbox !== null && empty($_POST)) {
+        $RCMAIL->output->command('parent.set_quota', $RCMAIL->quota_content(null, $mbox));
     }
 
     return $out;
diff --git a/program/steps/settings/folders.inc b/program/steps/settings/folders.inc
index ad5f37d..19c4457 100644
--- a/program/steps/settings/folders.inc
+++ b/program/steps/settings/folders.inc
@@ -20,14 +20,12 @@
  +-----------------------------------------------------------------------+
 */
 
-// WARNING: folder names in UI are encoded with RCUBE_CHARSET
-
 // init IMAP connection
 $STORAGE = $RCMAIL->get_storage();
 
 // subscribe mailbox
 if ($RCMAIL->action == 'subscribe') {
-    $mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true, 'UTF7-IMAP');
+    $mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true);
 
     if (strlen($mbox)) {
         $result = $STORAGE->subscribe(array($mbox));
@@ -58,7 +56,8 @@
 }
 // unsubscribe mailbox
 else if ($RCMAIL->action == 'unsubscribe') {
-    $mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true, 'UTF7-IMAP');
+    $mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true);
+
     if (strlen($mbox)) {
         $result = $STORAGE->unsubscribe(array($mbox));
         if ($result)
@@ -69,8 +68,7 @@
 }
 // delete an existing mailbox
 else if ($RCMAIL->action == 'delete-folder') {
-    $mbox_utf8 = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true);
-    $mbox      = rcube_charset::convert($mbox_utf8, RCUBE_CHARSET, 'UTF7-IMAP');
+    $mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true);
 
     if (strlen($mbox)) {
         $plugin = $RCMAIL->plugins->exec_hook('folder_delete', array('name' => $mbox));
@@ -90,7 +88,7 @@
 
     if ($OUTPUT->ajax_call && $deleted) {
         // Remove folder and subfolders rows
-        $OUTPUT->command('remove_folder_row', $mbox_utf8, true);
+        $OUTPUT->command('remove_folder_row', $mbox);
         $OUTPUT->show_message('folderdeleted', 'confirmation');
         // Clear content frame
         $OUTPUT->command('subscription_select');
@@ -102,13 +100,10 @@
 }
 // rename an existing mailbox
 else if ($RCMAIL->action == 'rename-folder') {
-    $name_utf8    = trim(rcube_utils::get_input_value('_folder_newname', rcube_utils::INPUT_POST, true));
-    $oldname_utf8 = rcube_utils::get_input_value('_folder_oldname', rcube_utils::INPUT_POST, true);
+    $name    = trim(rcube_utils::get_input_value('_folder_newname', rcube_utils::INPUT_POST, true));
+    $oldname = rcube_utils::get_input_value('_folder_oldname', rcube_utils::INPUT_POST, true);
 
-    if (strlen($name_utf8) && strlen($oldname_utf8)) {
-        $name    = rcube_charset::convert($name_utf8, RCUBE_CHARSET, 'UTF7-IMAP');
-        $oldname = rcube_charset::convert($oldname_utf8, RCUBE_CHARSET, 'UTF7-IMAP');
-
+    if (strlen($name) && strlen($oldname)) {
         $rename = rcmail_rename_folder($oldname, $name);
     }
 
@@ -121,8 +116,7 @@
 }
 // clear mailbox
 else if ($RCMAIL->action == 'purge') {
-    $mbox_utf8    = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true);
-    $mbox         = rcube_charset::convert($mbox_utf8, RCUBE_CHARSET, 'UTF7-IMAP');
+    $mbox         = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true);
     $delimiter    = $STORAGE->get_hierarchy_delimiter();
     $trash_mbox   = $RCMAIL->config->get('trash_mbox');
     $trash_regexp = '/^' . preg_quote($trash . $delimiter, '/') . '/';
@@ -150,7 +144,7 @@
             $OUTPUT->show_message('messagemoved', 'confirmation');
         }
         $_SESSION['unseen_count'][$mbox] = 0;
-        $OUTPUT->command('show_folder', $mbox_utf8, null, true);
+        $OUTPUT->command('show_folder', $mbox, null, true);
     }
     else {
         $RCMAIL->display_server_error('errorsaving');
@@ -270,6 +264,7 @@
 
     $js_folders = array();
     $folders    = array();
+    $collapsed  = $RCMAIL->config->get('collapsed_folders');
 
     // create list of available folders
     foreach ($list_folders as $i => $folder) {
@@ -278,11 +273,10 @@
         $subscribed = $sub_key !== false;
         $protected  = $protect_default && isset($special_folders[$folder['id']]);
         $noselect   = false;
-        $classes    = array('listitem');
+        $classes    = array();
 
         $folder_utf8    = rcube_charset::convert($folder['id'], 'UTF7-IMAP');
-        $display_folder = str_repeat('&nbsp;&nbsp;&nbsp;&nbsp;', $folder['level'])
-            . rcube::Q($protected ? $RCMAIL->localize_foldername($folder['id']) : $folder['name']);
+        $display_folder = rcube::Q($protected ? $RCMAIL->localize_foldername($folder['id']) : $folder['name']);
 
         if ($folder['virtual']) {
             $classes[] = 'virtual';
@@ -338,45 +332,85 @@
             }
         }
 
-        $row_id = 'rcmli' . $idx;
-        $folders[$row_id] = array(
+        $is_collapsed = strpos($collapsed, '&'.rawurlencode($folder['id']).'&') !== false;
+        $folder_id    = rcube_utils::html_identifier($folder['id'], true);
+
+        if ($folder_class = $RCMAIL->folder_classname($folder['id'])) {
+            $classes[] = $folder_class;
+        }
+
+        $folders[$folder['id']] = array(
+            'idx'         => $folder_id,
+            'folder_imap' => $folder['id'],
             'folder'      => $folder_utf8,
             'display'     => $display_folder,
-            'class'       => join(' ', $classes),
-            'folder_imap' => $folder['id'],
-            'subscribed'  => $subscribed,
             'protected'   => $protected || $folder['virtual'],
-            'content'     => html::a(array('class' => 'name', 'href' => '#_' . $row_id), $display_folder)
-                . $checkbox_subscribe->show(($subscribed ? $folder_utf8 : ''),
-                    array('value' => $folder_utf8, 'disabled' => $disabled ? 'disabled' : ''))
+            'class'       => join(' ', $classes),
+            'subscribed'  => $subscribed,
+            'level'       => $folder['level'],
+            'collapsed'   => $is_collapsed,
+            'content'     => html::a(array('href' => '#'), $display_folder)
+                . $checkbox_subscribe->show(($subscribed ? $folder['id'] : ''),
+                    array('value' => $folder['id'], 'disabled' => $disabled ? 'disabled' : ''))
         );
     }
 
     $plugin = $RCMAIL->plugins->exec_hook('folders_list', array('list' => $folders));
 
     // add drop-target representing 'root'
-    $roots = array(
-        'mailboxroot' => array(
-            'folder'    => '',
-            'display'   => '',
-            'protected' => true,
-            'class'     => 'root',
-            'content'   => html::span('name', '&nbsp;')
-        )
+    $root = array(
+        'idx'         => rcube_utils::html_identifier('*', true),
+        'folder_imap' => '*',
+        'folder'      => '',
+        'display'     => '',
+        'protected'   => true,
+        'class'       => 'root',
+        'content'     => '<span>&nbsp;</span>',
     );
-    $folders = array_merge($roots, $plugin['list']);
 
-    while (list($key, $data) = each($folders)) {
-        $js_folders[$key] = array($data['folder'], $data['display'], $data['protected']);
-        $folders[$key]    = html::tag('li', array('id'  => $key, 'class' => $data['class']), $data['content']);
+    $folders        = array();
+    $plugin['list'] = array_values($plugin['list']);
+
+    array_unshift($plugin['list'], $root);
+
+    for ($i = 0, $length = count($plugin['list'])-1; $i<$length; $i++) {
+        $folders[] = rcmail_folder_tree_element($plugin['list'], $i, $js_folders);
     }
 
     $OUTPUT->add_gui_object('subscriptionlist', $attrib['id']);
     $OUTPUT->set_env('subscriptionrows', $js_folders);
     $OUTPUT->set_env('defaultfolders', array_keys($special_folders));
+    $OUTPUT->set_env('collapsed_folders', $collapsed);
     $OUTPUT->set_env('delimiter', $delimiter);
 
-    return $form_start . html::tag('ul', $attrib, implode("\n", $folders)) . $form_end;
+    return $form_start . html::tag('ul', $attrib, implode('', $folders), html::$common_attrib) . $form_end;
+}
+
+function rcmail_folder_tree_element($folders, &$key, &$js_folders)
+{
+    $data = $folders[$key];
+    $idx  = 'rcmli' . $data['idx'];
+
+    $js_folders[$data['folder_imap']] = array($data['folder'], $data['display'], $data['protected']);
+    $content          = $data['content'];
+    $attribs          = array(
+        'id'    => $idx,
+        'class' => trim($data['class'] . ' mailbox')
+    );
+
+    $children = array();
+    while ($folders[$key+1] && $folders[$key+1]['level'] > $data['level']) {
+        $key++;
+        $children[] = rcmail_folder_tree_element($folders, $key, $js_folders);
+    }
+
+    if (!empty($children)) {
+        $content .= html::div('treetoggle ' . ($data['collapsed'] ? 'collapsed' : 'expanded'), '&nbsp;')
+            . html::tag('ul', array('style' => ($data['collapsed'] ? "display:none" : null)),
+                implode("\n", $children));
+    }
+
+    return html::tag('li', $attribs, $content);
 }
 
 function rcmail_folder_frame($attrib)
diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc
index 8a96ada..619710f 100644
--- a/program/steps/settings/func.inc
+++ b/program/steps/settings/func.inc
@@ -1302,23 +1302,20 @@
     $protect_folders = $RCMAIL->config->get('protect_default_folders');
     $storage         = $RCMAIL->get_storage();
     $delimiter       = $storage->get_hierarchy_delimiter();
-    $name_utf8       = rcube_charset::convert($name, 'UTF7-IMAP');
-    $protected       = $protect_folders && $storage->is_special_folder($name);
 
+    $name_utf8    = rcube_charset::convert($name, 'UTF7-IMAP');
+    $protected    = $protect_folders && $storage->is_special_folder($name);
     $foldersplit  = explode($delimiter, $storage->mod_folder($name));
     $level        = count($foldersplit) - 1;
-    $display_name = str_repeat('&nbsp;&nbsp;&nbsp;&nbsp;', $level)
-        . rcube::Q($protected ? $RCMAIL->localize_foldername($name) : rcube_charset::convert($foldersplit[$level], 'UTF7-IMAP'));
-
-    $class_name = trim($class_name . ' listitem');
+    $display_name = $protected ? $RCMAIL->localize_foldername($name) : rcube_charset::convert($foldersplit[$level], 'UTF7-IMAP');
+    $class_name   = trim($class_name . ' mailbox');
 
     if ($oldname === null) {
-        $OUTPUT->command('add_folder_row', $name_utf8, $display_name, $protected, $subscribe,
-            false, $class_name);
+        $OUTPUT->command('add_folder_row', $name, $name_utf8, $display_name, $protected, $subscribe,
+            $class_name);
     }
     else {
-        $OUTPUT->command('replace_folder_row', rcube_charset::convert($oldname, 'UTF7-IMAP'),
-            $name_utf8, $display_name, $protected, $class_name);
+        $OUTPUT->command('replace_folder_row', $oldname, $name, $name_utf8, $display_name, $protected, $class_name);
     }
 }
 
diff --git a/program/steps/settings/save_folder.inc b/program/steps/settings/save_folder.inc
index a054224..9bb6bf3 100644
--- a/program/steps/settings/save_folder.inc
+++ b/program/steps/settings/save_folder.inc
@@ -24,12 +24,10 @@
 // init IMAP connection
 $STORAGE = $RCMAIL->get_storage();
 
-$name = trim(rcube_utils::get_input_value('_name', rcube_utils::INPUT_POST, true));
-$old  = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true);
-$path = rcube_utils::get_input_value('_parent', rcube_utils::INPUT_POST, true);
-
+$name      = trim(rcube_utils::get_input_value('_name', rcube_utils::INPUT_POST, true));
+$path      = rcube_utils::get_input_value('_parent', rcube_utils::INPUT_POST, true);
+$old_imap  = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true);
 $name_imap = rcube_charset::convert($name, RCUBE_CHARSET, 'UTF7-IMAP');
-$old_imap  = rcube_charset::convert($old, RCUBE_CHARSET, 'UTF7-IMAP');
 // $path is in UTF7-IMAP already
 
 $delimiter = $STORAGE->get_hierarchy_delimiter();
@@ -96,7 +94,7 @@
 }
 
 // create a new mailbox
-if (!$error && !strlen($old)) {
+if (!$error && !strlen($old_imap)) {
     $folder['subscribe'] = true;
 
     $plugin = $RCMAIL->plugins->exec_hook('folder_create', array('record' => $folder));
diff --git a/skins/classic/common.css b/skins/classic/common.css
index 13f4e64..c50d1c7 100644
--- a/skins/classic/common.css
+++ b/skins/classic/common.css
@@ -290,9 +290,9 @@
 
 body > #message div.voice
 {
-	position: absolute;
-	top: -1000px;
-	clip: rect(0 0 0 0);
+  position: absolute;
+  top: -1000px;
+  clip: rect(0 0 0 0);
 }
 
 body > #message a
@@ -766,6 +766,154 @@
   background-color: #FFFFA6;
 }
 
+/***** folders list *****/
+
+.folderlist li ul li:last-child
+{
+  border-bottom: 0 none;
+}
+
+.folderlist li.inbox a
+{
+  background-position: 5px -18px;
+}
+
+.folderlist li.drafts a
+{
+  background-position: 5px -35px;
+}
+
+.folderlist li.sent a
+{
+  background-position: 5px -54px;
+}
+
+.folderlist li.junk a
+{
+  background-position: 5px -73px;
+}
+
+.folderlist li.trash a
+{
+  background-position: 5px -180px;
+}
+
+.folderlist li.trash.empty a
+{
+  background-position: 5px -90px;
+}
+
+.folderlist li a
+{
+  cursor: default;
+  display: block;
+  position: relative;
+  padding-left: 25px;
+  padding-top: 2px;
+  padding-bottom: 2px;
+  text-decoration: none;
+  height: 15px;
+  background: url(images/icons/folders.png) 5px 0 no-repeat;
+}
+
+.folderlist li.virtual > a
+{
+  color: #666;
+}
+
+.folderlist li.selected,
+.folderlist li.droptarget li.selected
+{
+  background-color: #929292;
+}
+
+.folderlist li.selected > a,
+.folderlist li.droptarget li.selected a
+{
+  color: #FFF;
+  font-weight: bold;
+}
+
+.folderlist li.droptarget
+{
+  background-color: #FFFFA6;
+}
+
+/* styles for nested folders */
+.folderlist ul {
+  list-style: none;
+  padding: 0;
+  margin: 0;
+  border-top: 1px solid #EBEBEB;
+  background-color: #FFF;
+  font-weight: normal;
+}
+
+.folderlist li.mailbox ul li a {
+  padding-left: 40px;  /* 24 + 1 x 16 */
+  background-position: 20px 0;  /* 4 + 1 x 16 */
+}
+.folderlist li.mailbox ul li div.treetoggle {
+  left: 23px !important;
+}
+
+.folderlist li.mailbox ul ul li.mailbox a {
+  padding-left: 56px;  /* 2x */
+  background-position: 36px 0;
+}
+.folderlist li.mailbox ul ul li div.treetoggle {
+  left: 39px !important;
+}
+
+.folderlist li.mailbox ul ul ul li.mailbox a {
+  padding-left: 72px;  /* 3x */
+  background-position: 52px 0;
+}
+.folderlist li.mailbox ul ul ul li div.treetoggle {
+  left: 55px !important;
+}
+
+.folderlist li.mailbox ul ul ul ul li.mailbox a {
+  padding-left: 88px;  /* 4x */
+  background-position: 68px 0;
+}
+.folderlist li.mailbox ul ul ul ul li div.treetoggle {
+  left: 71px !important;
+}
+
+/* indent folders on levels > 4 */
+.folderlist li.mailbox ul ul ul ul ul li {
+  padding-left: 16px;
+}
+.folderlist li.mailbox ul ul ul ul ul li div.treetoggle {
+  left: 87px !important;
+}
+
+.folderlist li.mailbox ul li.drafts a
+{
+  background-position: 21px -37px;
+}
+
+.folderlist li.mailbox ul li.sent a
+{
+  background-position: 21px -54px;
+}
+
+.folderlist li.mailbox ul li.junk a
+{
+  background-position: 21px -73px;
+}
+
+.folderlist li.mailbox ul li.trash a
+{
+  background-position: 21px -180px;
+}
+
+.folderlist li.mailbox ul li.trash.empty a
+{
+  background-position: 21px -90px;
+}
+
 
 /***** mac-style quicksearch field *****/
 
diff --git a/skins/classic/mail.css b/skins/classic/mail.css
index 58db795..1eeba49 100644
--- a/skins/classic/mail.css
+++ b/skins/classic/mail.css
@@ -409,160 +409,14 @@
   background-color: #FFF;
 }
 
-#mailboxlist li ul li:last-child
-{
-  border-bottom: 0 none;
-}
-
-#mailboxlist li.inbox a
-{
-  background-position: 5px -18px;
-}
-
-#mailboxlist li.drafts a
-{
-  background-position: 5px -37px;
-}
-
-#mailboxlist li.sent a
-{
-  background-position: 5px -54px;
-}
-
-#mailboxlist li.junk a
-{
-  background-position: 5px -73px;
-}
-
-#mailboxlist li.trash a
-{
-  background-position: 5px -180px;
-}
-
-#mailboxlist li.trash.empty a
-{
-  background-position: 5px -90px;
-}
-
-#mailboxlist li a
-{
-  cursor: default;
-  display: block;
-  position: relative;
-  padding-left: 25px;
-  padding-top: 2px;
-  padding-bottom: 2px;
-  text-decoration: none;
-  height: 15px;
-  background: url(images/icons/folders.png) 5px 0 no-repeat;
-}
-
 #mailboxlist li.unread
 {
   font-weight: bold;
 }
 
-#mailboxlist li.virtual > a
-{
-  color: #666;
-}
-
 #mailboxlist li.recent > a
 {
   color: #0066FF;
-}
-
-#mailboxlist li.selected,
-#mailboxlist li.droptarget li.selected
-{
-  background-color: #929292;
-}
-
-#mailboxlist li.selected > a,
-#mailboxlist li.droptarget li.selected a
-{
-  color: #FFF;
-  font-weight: bold;
-}
-
-#mailboxlist li.droptarget
-{
-  background-color: #FFFFA6;
-}
-
-/* styles for nested folders */
-#mailboxlist ul {
-  list-style: none;
-  padding: 0;
-  margin: 0;
-  border-top: 1px solid #EBEBEB;
-  background-color: #FFF;
-  font-weight: normal;
-}
-
-#mailboxlist li.mailbox ul li a {
-  padding-left: 40px;  /* 24 + 1 x 16 */
-  background-position: 20px 0;  /* 4 + 1 x 16 */
-}
-#mailboxlist li.mailbox ul li div.treetoggle {
-  left: 23px !important;
-}
-
-#mailboxlist li.mailbox ul ul li.mailbox a {
-  padding-left: 56px;  /* 2x */
-  background-position: 36px 0;
-}
-#mailboxlist li.mailbox ul ul li div.treetoggle {
-  left: 39px !important;
-}
-
-#mailboxlist li.mailbox ul ul ul li.mailbox a {
-  padding-left: 72px;  /* 3x */
-  background-position: 52px 0;
-}
-#mailboxlist li.mailbox ul ul ul li div.treetoggle {
-  left: 55px !important;
-}
-
-#mailboxlist li.mailbox ul ul ul ul li.mailbox a {
-  padding-left: 88px;  /* 4x */
-  background-position: 68px 0;
-}
-#mailboxlist li.mailbox ul ul ul ul li div.treetoggle {
-  left: 71px !important;
-}
-
-/* indent folders on levels > 4 */
-#mailboxlist li.mailbox ul ul ul ul ul li {
-  padding-left: 16px;
-}
-#mailboxlist li.mailbox ul ul ul ul ul li div.treetoggle {
-  left: 87px !important;
-}
-
-#mailboxlist li.mailbox ul li.drafts a
-{
-  background-position: 21px -37px;
-}
-
-#mailboxlist li.mailbox ul li.sent a
-{
-  background-position: 21px -54px;
-}
-
-#mailboxlist li.mailbox ul li.junk a
-{
-  background-position: 21px -73px;
-}
-
-#mailboxlist li.mailbox ul li.trash a
-{
-  background-position: 21px -180px;
-}
-
-#mailboxlist li.mailbox ul li.trash.empty a
-{
-  background-position: 21px -90px;
 }
 
 #listcontrols
diff --git a/skins/classic/settings.css b/skins/classic/settings.css
index 3b084de..fb4303f 100644
--- a/skins/classic/settings.css
+++ b/skins/classic/settings.css
@@ -23,12 +23,6 @@
   font-style: italic;
 }
 
-#subscription-table li.selected a
-{
-  color: #FFF;
-  background-color: #CC3333;
-}
-
 #subscription-table li.root
 {
   font-size: 5%;
@@ -37,28 +31,16 @@
   padding: 2px;
 }
 
-#subscription-table li a.name
-{
-  overflow: hidden;
-  text-overflow: ellipsis;
-  width: 100%;
-  display: block;
-  float: left;
-  padding: 0 0 0 5px;
-  height: 24px;
-  line-height: 24px;
-}
-
-#subscription-table li input
-{
+#subscription-table li input {
   position: absolute;
   right: 0;
+  top: 2px;
 }
 
-html.chrome #subscription-table li input,
-html.opera #subscription-table li input
-{
-  margin-top: 6px;
+#subscription-table li a {
+  padding-right: 20px;
+  overflow: hidden;
+  text-overflow: ellipsis;
 }
 
 #folder-box,
diff --git a/skins/classic/templates/folders.html b/skins/classic/templates/folders.html
index 66bec62..7ca4ac4 100644
--- a/skins/classic/templates/folders.html
+++ b/skins/classic/templates/folders.html
@@ -22,7 +22,7 @@
 <div id="folderlist-title" class="boxtitle"><span class="rightalign"><roundcube:label name="subscribed" /></span><roundcube:label name="folders" /></div>
 <div id="folderlist-content" class="boxlistcontent">
     <roundcube:object name="foldersubscription" form="subscriptionform" id="subscription-table"
-        summary="Folder subscription table" class="treelist" />
+        summary="Folder subscription table" class="treelist folderlist" />
 </div>
 <div id="folderlist-footer" class="boxfooter">
     <roundcube:button command="create-folder" type="link" title="createfolder" class="buttonPas addgroup" classAct="button addgroup" content=" " />
diff --git a/skins/classic/templates/mail.html b/skins/classic/templates/mail.html
index b73398b..7f1e1b8 100644
--- a/skins/classic/templates/mail.html
+++ b/skins/classic/templates/mail.html
@@ -24,7 +24,7 @@
 <div id="mailboxlist-container">
 <div id="mailboxlist-title" class="boxtitle"><roundcube:label name="mailboxlist" /></div>
 <div id="mailboxlist-content"  class="boxlistcontent">
-<roundcube:object name="mailboxlist" id="mailboxlist" class="treelist" folder_filter="mail" />
+  <roundcube:object name="mailboxlist" id="mailboxlist" class="treelist folderlist" folder_filter="mail" />
 </div>
 <div id="mailboxlist-footer" class="boxfooter">
   <roundcube:button name="mailboxmenulink" id="mailboxmenulink" type="link" title="folderactions" class="button groupactions" onclick="rcmail_ui.show_popup('mailboxmenu');return false" content=" " />
diff --git a/skins/larry/mail.css b/skins/larry/mail.css
index 2083cb9..05dd877 100644
--- a/skins/larry/mail.css
+++ b/skins/larry/mail.css
@@ -137,238 +137,24 @@
 	background-position: -26px -497px;
 }
 
-#mailboxlist li.mailbox {
-	position: relative;
-	background-repeat: no-repeat;
-	background-position: 6px 2px;
-}
-
 #mailboxlist > li:first-child {
-	border-radius: 4px 4px 0 0;
 	border-top: 0;
 }
 
-#mailboxlist li.mailbox a {
-	padding-left: 36px;
-	white-space: nowrap;
-	overflow: hidden;
-	text-overflow: ellipsis;
-	background-image: url(images/listicons.png);
-	background-repeat: no-repeat;
-	background-position: 6px 3px;
+html.mozilla #mailboxlist > li:first-child {
+	border-radius: 4px 4px 0 0;
 }
 
 #mailboxlist li.mailbox.unread > a {
 	padding-right: 36px;
 }
 
-#mailboxlist li.mailbox > a:focus,
-#mailboxlist li.mailbox.selected > a {
-	background-position: 6px -21px;
-}
-
-#mailboxlist li.mailbox.inbox > a {
-	background-position: 6px -189px;
-}
-
-#mailboxlist li.mailbox.inbox > a:focus,
-#mailboxlist li.mailbox.inbox.selected > a {
-	background-position: 6px -213px;
-}
-
-#mailboxlist li.mailbox.drafts > a {
-	background-position: 6px -238px;
-}
-
-#mailboxlist li.mailbox.drafts > a:focus,
-#mailboxlist li.mailbox.drafts.selected > a {
-	background-position: 6px -262px;
-}
-
-#mailboxlist li.mailbox.sent > a {
-	background-position: 6px -286px;
-}
-
-#mailboxlist li.mailbox.sent > a:focus,
-#mailboxlist li.mailbox.sent.selected > a {
-	background-position: 6px -310px;
-}
-
-#mailboxlist li.mailbox.junk > a {
-	background-position: 6px -334px;
-}
-
-#mailboxlist li.mailbox.junk > a:focus,
-#mailboxlist li.mailbox.junk.selected > a {
-	background-position: 6px -358px;
-}
-
-#mailboxlist li.mailbox.trash > a {
-	background-position: 6px -382px;
-}
-
-#mailboxlist li.mailbox.trash > a:focus,
-#mailboxlist li.mailbox.trash.selected > a {
-	background-position: 6px -406px;
-}
-
-#mailboxlist li.mailbox.trash.empty > a {
-	background-position: 6px -1924px;
-}
-
-#mailboxlist li.mailbox.trash.empty > a:focus,
-#mailboxlist li.mailbox.trash.empty.selected > a {
-	background-position: 6px -1948px;
-}
-
-#mailboxlist li.mailbox.archive > a {
-	background-position: 6px -1699px;
-}
-
-#mailboxlist li.mailbox.archive > a:focus,
-#mailboxlist li.mailbox.archive.selected > a {
-	background-position: 6px -1723px;
-}
-
-#mailboxlist li.mailbox ul li.drafts > a {
-	background-position: 23px -238px;
-}
-
-#mailboxlist li.mailbox ul li.drafts > a:focus,
-#mailboxlist li.mailbox ul li.drafts.selected > a {
-	background-position: 23px -262px;
-}
-
-#mailboxlist li.mailbox ul li.sent > a {
-	background-position: 23px -286px;
-}
-
-#mailboxlist li.mailbox ul li.sent > a:focus,
-#mailboxlist li.mailbox ul li.sent.selected > a {
-	background-position: 23px -310px;
-}
-
-#mailboxlist li.mailbox ul li.junk > a {
-	background-position: 23px -334px;
-}
-
-#mailboxlist li.mailbox ul li.junk > a:focus,
-#mailboxlist li.mailbox ul li.junk.selected > a {
-	background-position: 23px -358px;
-}
-
-#mailboxlist li.mailbox ul li.trash > a {
-	background-position: 23px -382px;
-}
-
-#mailboxlist li.mailbox ul li.trash > a:focus,
-#mailboxlist li.mailbox ul li.trash.selected > a {
-	background-position: 23px -406px;
-}
-
-#mailboxlist li.mailbox ul li.trash.empty > a {
-	background-position: 23px -1924px;
-}
-
-#mailboxlist li.mailbox ul li.trash.empty > a:focus,
-#mailboxlist li.mailbox ul li.trash.empty.selected > a {
-	background-position: 23px -1948px;
-}
-
-#mailboxlist li.mailbox ul li.archive > a {
-	background-position: 23px -1699px;
-}
-
-#mailboxlist li.mailbox ul li.archive > a:focus,
-#mailboxlist li.mailbox ul li.archive.selected > a {
-	background-position: 23px -1723px;
-}
-
 #mailboxlist li.unread {
 	font-weight: bold;
 }
 
-#mailboxlist li.virtual > a {
-	color: #aaa;
-}
-
 #mailboxlist li.recent > a {
 	color: #017cb4;
-}
-
-#mailboxlist li.mailbox div.treetoggle {
-	top: 13px;
-	left: 19px;
-}
-
-#mailboxlist li.mailbox ul li:last-child {
-	border-bottom: 0;
-}
-
-/* nested mailboxes */
-
-#mailboxlist li.mailbox ul {
-	list-style: none;
-	margin: 0;
-	padding: 0;
-	border-top: 1px solid #bbd3da;
-}
-
-#mailboxlist li.mailbox ul li a {
-	padding-left: 52px;  /* 36 + 1 x 16 */
-	background-position: 22px -95px;  /* 6 + 1 x 16 */
-}
-#mailboxlist li.mailbox ul li > a:focus,
-#mailboxlist li.mailbox ul li.selected > a {
-	background-position: 22px -119px;
-}
-#mailboxlist li.mailbox ul li div.treetoggle {
-	left: 33px;
-	top: 14px;
-}
-
-#mailboxlist li.mailbox ul ul li.mailbox a {
-	padding-left: 68px;  /* 2x */
-	background-position: 38px -95px;
-}
-#mailboxlist li.mailbox ul ul li > a:focus,
-#mailboxlist li.mailbox ul ul li.selected > a {
-	background-position: 38px -119px;
-}
-#mailboxlist li.mailbox ul ul li div.treetoggle {
-	left: 48px;
-}
-
-#mailboxlist li.mailbox ul ul ul li.mailbox a {
-	padding-left: 84px;  /* 3x */
-	background-position: 54px -95px;
-}
-#mailboxlist li.mailbox ul ul ul li > a:focus,
-#mailboxlist li.mailbox ul ul ul li.selected > a {
-	background-position: 54px -119px;
-}
-#mailboxlist li.mailbox ul ul ul li div.treetoggle {
-	left: 64px;
-}
-
-#mailboxlist li.mailbox ul ul ul ul li.mailbox a {
-	padding-left: 100px;  /* 4x */
-	background-position: 70px -95px;
-}
-#mailboxlist li.mailbox ul ul ul ul li > a:focus,
-#mailboxlist li.mailbox ul ul ul ul li.selected > a {
-	background-position: 70px -119px;
-}
-#mailboxlist li.mailbox ul ul ul ul li div.treetoggle {
-	left: 80px;
-}
-
-/* indent folders on levels > 4 */
-#mailboxlist li.mailbox ul ul ul ul ul li {
-	padding-left: 16px;
-}
-#mailboxlist li.mailbox ul ul ul ul ul li div.treetoggle {
-	left: 96px;
 }
 
 #mailboxlist li.mailbox .unreadcount {
diff --git a/skins/larry/settings.css b/skins/larry/settings.css
index 0493e30..03067ef 100644
--- a/skins/larry/settings.css
+++ b/skins/larry/settings.css
@@ -251,21 +251,14 @@
 	padding: 2px;
 }
 
-#subscription-table li a.name {
-	overflow: hidden;
-	text-overflow: ellipsis;
-	width: 100%;
-	float: left;
-}
-
 #subscription-table li input {
 	position: absolute;
 	right: 0;
+	top: 4px;
 }
 
-html.chrome #subscription-table li input,
-html.opera #subscription-table li input {
-	margin-top: 6px;
+#subscription-table li a {
+	padding-right: 20px;
 }
 
 .skinselection {
diff --git a/skins/larry/styles.css b/skins/larry/styles.css
index b0ff04f..5b76a4f 100644
--- a/skins/larry/styles.css
+++ b/skins/larry/styles.css
@@ -2606,6 +2606,224 @@
 	background-position: 4px -2100px;
 }
 
+/*** folders list ***/
+
+.folderlist li.mailbox a {
+	padding-left: 36px;
+	white-space: nowrap;
+	overflow: hidden;
+	text-overflow: ellipsis;
+	background-image: url(images/listicons.png);
+	background-repeat: no-repeat;
+	background-position: 6px 3px;
+}
+
+.folderlist li.mailbox.unread > a {
+	padding-right: 36px;
+}
+
+.folderlist li.mailbox > a:focus,
+.folderlist li.mailbox.selected > a {
+	background-position: 6px -21px;
+}
+
+.folderlist li.mailbox.inbox > a {
+	background-position: 6px -189px;
+}
+
+.folderlist li.mailbox.inbox > a:focus,
+.folderlist li.mailbox.inbox.selected > a {
+	background-position: 6px -213px;
+}
+
+.folderlist li.mailbox.drafts > a {
+	background-position: 6px -238px;
+}
+
+.folderlist li.mailbox.drafts > a:focus,
+.folderlist li.mailbox.drafts.selected > a {
+	background-position: 6px -262px;
+}
+
+.folderlist li.mailbox.sent > a {
+	background-position: 6px -286px;
+}
+
+.folderlist li.mailbox.sent > a:focus,
+.folderlist li.mailbox.sent.selected > a {
+	background-position: 6px -310px;
+}
+
+.folderlist li.mailbox.junk > a {
+	background-position: 6px -334px;
+}
+
+.folderlist li.mailbox.junk > a:focus,
+.folderlist li.mailbox.junk.selected > a {
+	background-position: 6px -358px;
+}
+
+.folderlist li.mailbox.trash > a {
+	background-position: 6px -382px;
+}
+
+.folderlist li.mailbox.trash > a:focus,
+.folderlist li.mailbox.trash.selected > a {
+	background-position: 6px -406px;
+}
+
+.folderlist li.mailbox.trash.empty > a {
+	background-position: 6px -1924px;
+}
+
+.folderlist li.mailbox.trash.empty > a:focus,
+.folderlist li.mailbox.trash.empty.selected > a {
+	background-position: 6px -1948px;
+}
+
+.folderlist li.mailbox.archive > a {
+	background-position: 6px -1699px;
+}
+
+.folderlist li.mailbox.archive > a:focus,
+.folderlist li.mailbox.archive.selected > a {
+	background-position: 6px -1723px;
+}
+
+.folderlist li.mailbox ul li.drafts > a {
+	background-position: 23px -238px;
+}
+
+.folderlist li.mailbox ul li.drafts > a:focus,
+.folderlist li.mailbox ul li.drafts.selected > a {
+	background-position: 23px -262px;
+}
+
+.folderlist li.mailbox ul li.sent > a {
+	background-position: 23px -286px;
+}
+
+.folderlist li.mailbox ul li.sent > a:focus,
+.folderlist li.mailbox ul li.sent.selected > a {
+	background-position: 23px -310px;
+}
+
+.folderlist li.mailbox ul li.junk > a {
+	background-position: 23px -334px;
+}
+
+.folderlist li.mailbox ul li.junk > a:focus,
+.folderlist li.mailbox ul li.junk.selected > a {
+	background-position: 23px -358px;
+}
+
+.folderlist li.mailbox ul li.trash > a {
+	background-position: 23px -382px;
+}
+
+.folderlist li.mailbox ul li.trash > a:focus,
+.folderlist li.mailbox ul li.trash.selected > a {
+	background-position: 23px -406px;
+}
+
+.folderlist li.mailbox ul li.trash.empty > a {
+	background-position: 23px -1924px;
+}
+
+.folderlist li.mailbox ul li.trash.empty > a:focus,
+.folderlist li.mailbox ul li.trash.empty.selected > a {
+	background-position: 23px -1948px;
+}
+
+.folderlist li.mailbox ul li.archive > a {
+	background-position: 23px -1699px;
+}
+
+.folderlist li.mailbox ul li.archive > a:focus,
+.folderlist li.mailbox ul li.archive.selected > a {
+	background-position: 23px -1723px;
+}
+
+.folderlist li.virtual > a {
+	color: #aaa;
+}
+
+.folderlist li.mailbox div.treetoggle {
+	top: 13px;
+	left: 19px;
+}
+
+.folderlist li.mailbox ul li:last-child {
+	border-bottom: 0;
+}
+
+/* nested mailboxes */
+
+.folderlist li.mailbox ul {
+	list-style: none;
+	margin: 0;
+	padding: 0;
+	border-top: 1px solid #bbd3da;
+}
+
+.folderlist li.mailbox ul li a {
+	padding-left: 52px;  /* 36 + 1 x 16 */
+	background-position: 22px -95px;  /* 6 + 1 x 16 */
+}
+.folderlist li.mailbox ul li > a:focus,
+.folderlist li.mailbox ul li.selected > a {
+	background-position: 22px -119px;
+}
+.folderlist li.mailbox ul li div.treetoggle {
+	left: 33px;
+	top: 14px;
+}
+
+.folderlist li.mailbox ul ul li.mailbox a {
+	padding-left: 68px;  /* 2x */
+	background-position: 38px -95px;
+}
+.folderlist li.mailbox ul ul li > a:focus,
+.folderlist li.mailbox ul ul li.selected > a {
+	background-position: 38px -119px;
+}
+.folderlist li.mailbox ul ul li div.treetoggle {
+	left: 48px;
+}
+
+.folderlist li.mailbox ul ul ul li.mailbox a {
+	padding-left: 84px;  /* 3x */
+	background-position: 54px -95px;
+}
+.folderlist li.mailbox ul ul ul li > a:focus,
+.folderlist li.mailbox ul ul ul li.selected > a {
+	background-position: 54px -119px;
+}
+.folderlist li.mailbox ul ul ul li div.treetoggle {
+	left: 64px;
+}
+
+.folderlist li.mailbox ul ul ul ul li.mailbox a {
+	padding-left: 100px;  /* 4x */
+	background-position: 70px -95px;
+}
+.folderlist li.mailbox ul ul ul ul li > a:focus,
+.folderlist li.mailbox ul ul ul ul li.selected > a {
+	background-position: 70px -119px;
+}
+.folderlist li.mailbox ul ul ul ul li div.treetoggle {
+	left: 80px;
+}
+
+/* indent folders on levels > 4 */
+.folderlist li.mailbox ul ul ul ul ul li {
+	padding-left: 16px;
+}
+.folderlist li.mailbox ul ul ul ul ul li div.treetoggle {
+	left: 96px;
+}
+
+
 /*** attachment list ***/
 
 .attachmentslist {
diff --git a/skins/larry/templates/folders.html b/skins/larry/templates/folders.html
index f364792..034f35a 100644
--- a/skins/larry/templates/folders.html
+++ b/skins/larry/templates/folders.html
@@ -19,7 +19,7 @@
 <div id="folderslist" class="uibox listbox">
 <h2 id="folderslist-header" class="boxtitle"><span style="float:right"><roundcube:label name="subscribed" /></span><roundcube:label name="folders" /></h2>
 <div id="folderslist-content" class="scroller withfooter">
-	<roundcube:object name="foldersubscription" form="subscriptionform" id="subscription-table" class="listing" />
+	<roundcube:object name="foldersubscription" form="subscriptionform" id="subscription-table" class="treelist listing folderlist" />
 </div>
 <div id="folderslist-footer" class="boxfooter">
 	<roundcube:button command="create-folder" type="link" title="createfolder" class="listbutton add disabled" classAct="listbutton add" innerClass="inner" label="createfolder" /><roundcube:button name="mailboxmenulink" id="mailboxmenulink" type="link" title="folderactions" class="listbutton groupactions" onclick="return UI.toggle_popup('mailboxmenu',event)" innerClass="inner" content="&#9881;" aria-haspopup="true" aria-expanded="false" aria-owns="mailboxoptionsmenu" />
diff --git a/skins/larry/templates/mail.html b/skins/larry/templates/mail.html
index f2dc677..6da2cf6 100644
--- a/skins/larry/templates/mail.html
+++ b/skins/larry/templates/mail.html
@@ -70,7 +70,7 @@
 <div id="mailboxcontainer" class="uibox listbox" role="navigation" aria-labelledby="aria-label-folderlist">
 <h2 id="aria-label-folderlist" class="voice"><roundcube:label name="arialabelfolderlist" /></h2>
 <div id="folderlist-content" class="scroller withfooter">
-<roundcube:object name="mailboxlist" id="mailboxlist" class="treelist listing" folder_filter="mail" unreadwrap="%s" />
+	<roundcube:object name="mailboxlist" id="mailboxlist" class="treelist listing folderlist" folder_filter="mail" unreadwrap="%s" />
 </div>
 <div id="folderlist-footer" class="boxfooter">
 	<roundcube:button name="mailboxmenulink" id="mailboxmenulink" type="link" title="folderactions" class="listbutton groupactions" onclick="UI.toggle_popup('mailboxmenu',event);return false" innerClass="inner" content="&#9881;" aria-haspopup="true" aria-expanded="false" aria-owns="mailboxoptionsmenu" />

--
Gitblit v1.9.1