diff options
-rw-r--r-- | plugins/acl/acl.php | 6 | ||||
-rw-r--r-- | plugins/password/config.inc.php.dist | 5 | ||||
-rw-r--r-- | plugins/password/drivers/gearman.php | 50 | ||||
-rw-r--r-- | program/js/app.js | 306 | ||||
-rw-r--r-- | program/js/treelist.js | 36 | ||||
-rw-r--r-- | program/lib/Roundcube/rcube_imap.php | 14 | ||||
-rw-r--r-- | program/lib/Roundcube/rcube_imap_generic.php | 16 | ||||
-rw-r--r-- | program/steps/settings/edit_folder.inc | 36 | ||||
-rw-r--r-- | program/steps/settings/folders.inc | 112 | ||||
-rw-r--r-- | program/steps/settings/func.inc | 17 | ||||
-rw-r--r-- | program/steps/settings/save_folder.inc | 10 | ||||
-rw-r--r-- | skins/classic/common.css | 154 | ||||
-rw-r--r-- | skins/classic/mail.css | 146 | ||||
-rw-r--r-- | skins/classic/settings.css | 30 | ||||
-rw-r--r-- | skins/classic/templates/folders.html | 2 | ||||
-rw-r--r-- | skins/classic/templates/mail.html | 2 | ||||
-rw-r--r-- | skins/larry/mail.css | 218 | ||||
-rw-r--r-- | skins/larry/settings.css | 13 | ||||
-rw-r--r-- | skins/larry/styles.css | 218 | ||||
-rw-r--r-- | skins/larry/templates/folders.html | 2 | ||||
-rw-r--r-- | skins/larry/templates/mail.html | 2 |
21 files changed, 747 insertions, 648 deletions
diff --git a/plugins/acl/acl.php b/plugins/acl/acl.php index 3e3bca9e1..5c4deb770 100644 --- a/plugins/acl/acl.php +++ b/plugins/acl/acl.php @@ -696,10 +696,8 @@ class acl extends rcube_plugin } // add UID field to fieldmap, so it will be returned in a record with name - $config['fieldmap'] = array( - 'name' => $name_field, - 'uid' => $uid_field, - ); + $config['fieldmap']['name'] = $name_field; + $config['fieldmap']['uid'] = $uid_field; // search in UID and name fields $config['search_fields'] = array_values($config['fieldmap']); diff --git a/plugins/password/config.inc.php.dist b/plugins/password/config.inc.php.dist index 16b7f9317..d979a1901 100644 --- a/plugins/password/config.inc.php.dist +++ b/plugins/password/config.inc.php.dist @@ -367,3 +367,8 @@ $config['password_expect_params'] = ''; $config['password_smb_host'] = 'localhost'; // Location of smbpasswd binary $config['password_smb_cmd'] = '/usr/bin/smbpasswd'; + +// gearman driver options +// --------------------- +// Gearman host (default: localhost) +$config['password_gearman_host'] = 'localhost'; diff --git a/plugins/password/drivers/gearman.php b/plugins/password/drivers/gearman.php new file mode 100644 index 000000000..6c1ad3cf0 --- /dev/null +++ b/plugins/password/drivers/gearman.php @@ -0,0 +1,50 @@ +<?php +/** + * Gearman Password Driver + * + * Payload is json string containing username, oldPassword and newPassword + * Return value is a json string saying result: true if success. + * + * @version 1.0 + * @author Mohammad Anwari <mdamt@mdamt.net> + */ + +class rcube_gearman_password +{ + function save($currpass, $newpass) + { + $user = $_SESSION['username']; + $rcmail = rcmail::get_instance(); + + if (extension_loaded('gearman')) { + $success = false; + $gmc= new GearmanClient(); + + $gmc->addServer($rcmail->config->get('password_gearman_host')); + $payload = array("username" => $user, "oldPassword" => $currpass, "newPassword" => $newpass); + $result = $gmc->doNormal("setPassword", json_encode($payload)); + $success = json_decode($result); + if ($success->result == 1) { + return PASSWORD_SUCCESS; + } else { + rcube::raise_error(array( + 'code' => 600, + 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Password plugin: Gearman authentication failed for user $user: $error" + ), true, false); + } + } + else { + rcube::raise_error(array( + 'code' => 600, + 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Password plugin: PECL Gearman module not loaded" + ), true, false); + } + + return PASSWORD_ERROR; + } +} +?> diff --git a/program/js/app.js b/program/js/app.js index a47d971d6..895671a86 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -544,7 +544,7 @@ function rcube_webmail() // 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 @@ function rcube_webmail() 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]; - - return !source[2] - && dest_name != source_name.replace(ref.last_sub_rx, '') - && !dest_name.startsWith(source_name + ref.env.delimiter); + 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 && !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 @@ function rcube_webmail() 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 @@ function rcube_webmail() // 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 @@ function rcube_webmail() 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> </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 @@ function rcube_webmail() }; // 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); - // 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(/^ /, ''); - } - else { - for (i=level; i<0; i++) - dispname = ' ' + dispname; - } - $('.name', row).html(dispname); - this.env.subscriptionrows[id][1] = dispname; - } - } - - // update list widget - this.init_subscription_list(); - }; + subfolders[newid] = folder; + delete ref.env.subscriptionrows[fname]; + }); - // remove the table row of a specific mailbox from the table - this.remove_folder_row = function(folder, subs) - { - var n, len, list = [], id = this.get_folder_row_id(folder); + // get row off the list + row = $(row).detach(); - // get subfolders if any - if (subs) - list = this.get_subfolders(folder); + delete this.env.subscriptionrows[oldid]; - // remove old row - this._remove_folder_row(id); + // 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(); + } - // remove subfolders - for (n=0, len=list.length; n<len; n++) - this._remove_folder_row(list[n]); + // move the existing table row + this.add_folder_row(id, name, display_name, is_protected, subscribed, class_name, row, subfolders); }; - this._remove_folder_row = function(id) + // remove the table row of a specific mailbox from the table + this.remove_folder_row = function(folder) { - this.subscription_list.remove(id.replace(/^rcmli/, '')); - $('#' + id).remove(); - delete this.env.subscriptionrows[id]; - }; + var list = [], row = this.subscription_list.get_item(folder, true); - this.get_subfolders = function(folder) - { - var name, list = [], - prefix = folder + this.env.delimiter, - row = $('#'+this.get_folder_row_id(folder)).get(0); + // get subfolders if any + $('li', row).each(function() { list.push(ref.folder_id2name(this.id)); }); - 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; - } - } + // remove folder row (and subfolders) + this.subscription_list.remove(folder); - return list; + // update local list variable + list.push(folder); + $.each(list, function(i, v) { delete ref.env.subscriptionrows[v]; }); }; this.subscribe = function(folder) @@ -6108,15 +6119,6 @@ function rcube_webmail() } }; - // 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 this.show_folder = function(folder, path, force) { @@ -6140,9 +6142,9 @@ function rcube_webmail() // 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 6a5518a7b..ab1363030 100644 --- a/program/js/treelist.js +++ b/program/js/treelist.js @@ -68,6 +68,8 @@ function rcube_treelist_widget(node, p) 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 rcube_treelist_widget(node, p) /** * */ - function reset() + function reset(keep_content) { select(''); @@ -478,7 +480,22 @@ function rcube_treelist_widget(node, p) 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 @@ function rcube_treelist_widget(node, p) { 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 @@ function rcube_treelist_widget(node, p) { 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/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php index 858db7b5b..9a07711c2 100644 --- a/program/lib/Roundcube/rcube_imap.php +++ b/program/lib/Roundcube/rcube_imap.php @@ -3298,12 +3298,14 @@ class rcube_imap extends rcube_storage // request \Subscribed flag in LIST response as performance improvement for folder_exists() $folders = $this->conn->listMailboxes('', '*', array('SUBSCRIBED'), array('SPECIAL-USE')); - foreach ($folders as $folder) { - if ($flags = $this->conn->data['LIST'][$folder]) { - foreach ($types as $type) { - if (in_array($type, $flags)) { - $type = strtolower(substr($type, 1)); - $special[$type] = $folder; + if (!empty($folders)) { + foreach ($folders as $folder) { + if ($flags = $this->conn->data['LIST'][$folder]) { + foreach ($types as $type) { + if (in_array($type, $flags)) { + $type = strtolower(substr($type, 1)); + $special[$type] = $folder; + } } } } diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index 99fb6d861..d76014f89 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -1296,8 +1296,8 @@ class rcube_imap_generic * @param array $return_opts (see self::_listMailboxes) * @param array $select_opts (see self::_listMailboxes) * - * @return array List of mailboxes or hash of options if $return_opts argument - * is non-empty. + * @return array|bool List of mailboxes or hash of options if STATUS/MYROGHTS response + * is requested, False on error. */ function listMailboxes($ref, $mailbox, $return_opts=array(), $select_opts=array()) { @@ -1311,8 +1311,8 @@ class rcube_imap_generic * @param string $mailbox Mailbox name * @param array $return_opts (see self::_listMailboxes) * - * @return array List of mailboxes or hash of options if $return_opts argument - * is non-empty. + * @return array|bool List of mailboxes or hash of options if STATUS/MYROGHTS response + * is requested, False on error. */ function listSubscribed($ref, $mailbox, $return_opts=array()) { @@ -1332,8 +1332,8 @@ class rcube_imap_generic * Possible: SUBSCRIBED, RECURSIVEMATCH, REMOTE, * SPECIAL-USE (RFC6154) * - * @return array List of mailboxes or hash of options if $status_ops argument - * is non-empty. + * @return array|bool List of mailboxes or hash of options if STATUS/MYROGHTS response + * is requested, False on error. */ protected function _listMailboxes($ref, $mailbox, $subscribed=false, $return_opts=array(), $select_opts=array()) @@ -1355,7 +1355,9 @@ class rcube_imap_generic $args[] = $this->escape($mailbox); if (!empty($return_opts) && $this->getCapability('LIST-EXTENDED')) { - $rets = array_intersect($return_opts, array('SUBSCRIBED', 'CHILDREN')); + $ext_opts = array('SUBSCRIBED', 'CHILDREN'); + $rets = array_intersect($return_opts, $ext_opts); + $return_opts = array_diff($return_opts, $rets); } if (!empty($return_opts) && $this->getCapability('LIST-STATUS')) { diff --git a/program/steps/settings/edit_folder.inc b/program/steps/settings/edit_folder.inc index 51f4d8d72..172a953ff 100644 --- a/program/steps/settings/edit_folder.inc +++ b/program/steps/settings/edit_folder.inc @@ -38,22 +38,20 @@ function rcmail_folder_form($attrib) $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 @@ function rcmail_folder_form($attrib) } else { $options = array(); - $path = $parent_imap; + $path = $parent; // allow creating subfolders of INBOX folder if ($path == 'INBOX') { @@ -88,7 +86,7 @@ function rcmail_folder_form($attrib) // Location (name) if ($options['protected']) { - $foldername = str_replace($delimiter, ' » ', rcube::Q($RCMAIL->localize_folderpath($mbox_imap))); + $foldername = str_replace($delimiter, ' » ', rcube::Q($RCMAIL->localize_folderpath($mbox))); } else if ($options['norename']) { $foldername = rcube::Q($folder); @@ -101,7 +99,7 @@ function rcmail_folder_form($attrib) $foldername = $foldername->show($folder); if ($options['special']) { - $foldername .= ' (' . rcube::Q($RCMAIL->localize_foldername($mbox_imap)) .')'; + $foldername .= ' (' . rcube::Q($RCMAIL->localize_foldername($mbox)) .')'; } } @@ -122,7 +120,7 @@ function rcmail_folder_form($attrib) } 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 @@ function rcmail_folder_form($attrib) ); // 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 @@ function rcmail_folder_form($attrib) 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 @@ function rcmail_folder_form($attrib) '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 @@ function rcmail_folder_form($attrib) // 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 @@ function rcmail_folder_form($attrib) $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 ad5f37d95..19c4457a1 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 @@ if ($RCMAIL->action == 'subscribe') { } // 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 @@ else if ($RCMAIL->action == 'unsubscribe') { } // 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 @@ else if ($RCMAIL->action == 'delete-folder') { 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 @@ else if ($RCMAIL->action == 'delete-folder') { } // 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); - - 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'); + $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) && strlen($oldname)) { $rename = rcmail_rename_folder($oldname, $name); } @@ -121,8 +116,7 @@ else if ($RCMAIL->action == 'rename-folder') { } // 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 @@ else if ($RCMAIL->action == 'purge') { $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 @@ function rcube_subscription_form($attrib) $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 @@ function rcube_subscription_form($attrib) $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(' ', $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 @@ function rcube_subscription_form($attrib) } } - $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, + 'protected' => $protected || $folder['virtual'], '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' : '')) + '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', ' ') - ) + $root = array( + 'idx' => rcube_utils::html_identifier('*', true), + 'folder_imap' => '*', + 'folder' => '', + 'display' => '', + 'protected' => true, + 'class' => 'root', + 'content' => '<span> </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'), ' ') + . 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 8a96ada6b..619710f32 100644 --- a/program/steps/settings/func.inc +++ b/program/steps/settings/func.inc @@ -1302,23 +1302,20 @@ function rcmail_update_folder_row($name, $oldname=null, $subscribe=false, $class $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(' ', $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 a054224f1..9bb6bf3ab 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 @@ else { } // 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 13f4e6483..c50d1c7af 100644 --- a/skins/classic/common.css +++ b/skins/classic/common.css @@ -290,9 +290,9 @@ body > #message div.loading, 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 @@ ul.treelist li.droptarget 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 58db795cb..1eeba491a 100644 --- a/skins/classic/mail.css +++ b/skins/classic/mail.css @@ -409,162 +409,16 @@ 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 { position: relative; diff --git a/skins/classic/settings.css b/skins/classic/settings.css index 3b084de87..fb4303f2b 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 66bec6243..7ca4ac49f 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 b73398b95..7f1e1b8bd 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 2083cb9b0..05dd87749 100644 --- a/skins/larry/mail.css +++ b/skins/larry/mail.css @@ -137,240 +137,26 @@ a.iconbutton.threadmode.selected { 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 { position: absolute; top: 3px; diff --git a/skins/larry/settings.css b/skins/larry/settings.css index 0493e3018..03067ef70 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 b0ff04f31..5b76a4f1d 100644 --- a/skins/larry/styles.css +++ b/skins/larry/styles.css @@ -2606,6 +2606,224 @@ ul.toolbarmenu li span.copy { 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 f36479259..034f35ab3 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="⚙" aria-haspopup="true" aria-expanded="false" aria-owns="mailboxoptionsmenu" /> diff --git a/skins/larry/templates/mail.html b/skins/larry/templates/mail.html index f2dc6778f..6da2cf6f6 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="⚙" aria-haspopup="true" aria-expanded="false" aria-owns="mailboxoptionsmenu" /> |