From ac4cbfc4269da0c94198fd908cbc8b6df543d423 Mon Sep 17 00:00:00 2001 From: alec Date: Tue, 18 May 2010 07:39:31 +0000 Subject: - Added threads tree icons - css/js fixes and improvements in (messages) list code git-svn-id: https://svn.roundcube.net/trunk@3625 208e9e7b-5314-0410-a742-e7e81cd9613c --- roundcubemail/CHANGELOG | 1 + roundcubemail/THREADS | 5 +- roundcubemail/program/js/app.js | 208 +++++++++++++++++++++------- roundcubemail/program/js/common.js | 74 +++++----- roundcubemail/program/js/list.js | 77 ++++------ roundcubemail/program/steps/mail/func.inc | 6 + roundcubemail/skins/default/iehacks.css | 6 + roundcubemail/skins/default/images/tree.gif | Bin 0 -> 92 bytes roundcubemail/skins/default/mail.css | 131 +++++++++--------- roundcubemail/skins/default/safari.css | 6 + 10 files changed, 311 insertions(+), 203 deletions(-) create mode 100644 roundcubemail/skins/default/images/tree.gif diff --git a/roundcubemail/CHANGELOG b/roundcubemail/CHANGELOG index b24932fc3..7f3adcefe 100644 --- a/roundcubemail/CHANGELOG +++ b/roundcubemail/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG RoundCube Webmail =========================== +- Added thread tree icons - Extend contact groups support (#1486682) - Fix check-recent action issues and performance (#1486526) - Fix messages order after checking for recent (#1484664) diff --git a/roundcubemail/THREADS b/roundcubemail/THREADS index faa608db3..2b1bf89f8 100644 --- a/roundcubemail/THREADS +++ b/roundcubemail/THREADS @@ -2,12 +2,13 @@ TODO (must have): - threads caching - - (better) updating threaded message list on message delete and check-recent + - better updating of threaded message list after message(s) deletion (?), + in some cases when some children rows has been removed threads needs + to be reordered TODO (other): - button in #listcontrols to mark all messages in current thread (with selected root or child message), - - icons for thread tree structure KNOWN ISSUES: - IE6: message, flag, attachment icons are not displayed in diff --git a/roundcubemail/program/js/app.js b/roundcubemail/program/js/app.js index 9c5867975..71c0fcde8 100644 --- a/roundcubemail/program/js/app.js +++ b/roundcubemail/program/js/app.js @@ -87,7 +87,7 @@ function rcube_webmail() if (sel) button_prop.sel = sel; if (over) button_prop.over = over; - this.buttons[command][this.buttons[command].length] = button_prop; + this.buttons[command].push(button_prop); }; // register a specific gui object @@ -121,7 +121,7 @@ function rcube_webmail() // execute the given script on load this.add_onload = function(f) { - this.onloads[this.onloads.length] = f; + this.onloads.push(f); }; // initialize webmail client @@ -389,7 +389,7 @@ function rcube_webmail() // execute all foreign onload scripts // @deprecated - for (var i=0; i= 0) @@ -1537,6 +1537,7 @@ function rcube_webmail() } if (!row.depth && row.has_children && (expando = document.getElementById('rcmexpando'+row.uid))) { + row.expando = expando; expando.onmousedown = function(e) { return self.expand_message_row(e, uid); }; } @@ -1549,11 +1550,6 @@ function rcube_webmail() if (!this.gui_objects.messagelist || !this.message_list) return false; - if (this.message_list.background) - var tbody = this.message_list.background; - else - var tbody = this.gui_objects.messagelist.tBodies[0]; - if (!this.env.messages[uid]) this.env.messages[uid] = {}; @@ -1566,14 +1562,15 @@ function rcube_webmail() flagged: flags.flagged?1:0, has_children: flags.has_children?1:0, depth: flags.depth?flags.depth:0, - unread_children: flags.unread_children, - parent_uid: flags.parent_uid, + unread_children: flags.unread_children?flags.unread_children:0, + parent_uid: flags.parent_uid?flags.parent_uid:0, selected: this.select_all_mode || this.message_list.in_selection(uid) }); var c, tree = expando = '', list = this.message_list, rows = list.rows, + tbody = this.gui_objects.messagelist.tBodies[0], rowcount = tbody.rows.length, even = rowcount%2, message = this.env.messages[uid], @@ -1656,7 +1653,7 @@ function rcube_webmail() } // add each submitted col - for (var n = 0; n < this.env.coltypes.length; n++) { + for (var n in this.env.coltypes) { c = this.env.coltypes[n]; col = document.createElement('td'); col.className = String(c).toLowerCase(); @@ -1969,6 +1966,99 @@ function rcube_webmail() } }; + // Initializes threads indicators/expanders after list update + this.init_threads = function(roots) + { + for (var n=0, len=roots.length; n=0; i--) { + len = tmp[i].length; + if (len > r.depth) { + pos = len - r.depth; + if (!(tmp[i][pos] & 2)) + tmp[i][pos] = tmp[i][pos] ? tmp[i][pos]+2 : 2; + } + else if (len == r.depth) { + if (!(tmp[i][0] & 2)) + tmp[i][0] += 2; + } + if (r.depth > len) + break; + } + + tmp.push(new Array(r.depth)); + tmp[tmp.length-1][0] = 1; + uid.push(r.uid); + } + else { + if (tmp.length) { + for (i in tmp) { + this.set_tree_icons(uid[i], tmp[i]); + } + tmp = []; + uid = []; + } + if (root && row != rows[root].obj) + break; + } + } + row = row.nextSibling; + } + + if (tmp.length) { + for (i in tmp) { + this.set_tree_icons(uid[i], tmp[i]); + } + } + }; + + // adds tree icons to specified message row + this.set_tree_icons = function(uid, tree) + { + var i, divs = [], html = '', len = tree.length; + + for (i=0; i 2) + divs.push({'class': 'l3', width: 15}); + else if (tree[i] > 1) + divs.push({'class': 'l2', width: 15}); + else if (tree[i] > 0) + divs.push({'class': 'l1', width: 15}); + // separator div + else if (divs.length && !divs[divs.length-1]['class']) + divs[divs.length-1].width += 15; + else + divs.push({'class': null, width: 15}); + } + + for (i=divs.length-1; i>=0; i--) { + if (divs[i]['class']) + html += '
'; + else + html += '
'; + } + + if (html) + $('#rcmtab'+uid).html(html); + }; + // update parent in a thread this.update_thread_root = function(uid, flag) { @@ -2029,7 +2119,8 @@ function rcube_webmail() break; r.depth--; // move left - $('#rcmtab'+r.uid).width(r.depth * 15); + // reset width and clear the content of a tab, icons will be added later + $('#rcmtab'+r.uid).width(r.depth * 15).html(''); if (!r.depth) { // a new root count++; // increase roots count r.parent_uid = 0; @@ -2042,7 +2133,7 @@ function rcube_webmail() function(e) { return e.data.p.expand_message_row(e, e.data.uid); }); r.unread_children = 0; - roots[roots.length] = r; + roots.push(r); } // show if it was hidden if (r.obj.style.display == 'none') @@ -2180,7 +2271,7 @@ function rcube_webmail() { var row = this.message_list.rows[uid]; - if (row.parent_uid || !row.has_children) + if (row.parent_uid) return; if (!row.unread && row.unread_children && !row.expanded) @@ -2199,17 +2290,15 @@ function rcube_webmail() if (!mbox || mbox == this.env.mailbox || (!this.env.uid && (!this.message_list || !this.message_list.get_selection().length))) return; - var add_url = '&_target_mbox='+urlencode(mbox)+'&_from='+(this.env.action ? this.env.action : ''); - var a_uids = []; + var a_uids = [], + add_url = '&_target_mbox='+urlencode(mbox)+'&_from='+(this.env.action ? this.env.action : ''); if (this.env.uid) a_uids[0] = this.env.uid; else { var selection = this.message_list.get_selection(); - var id; - for (var n=0; n|'+delim+')', 'i') : new RegExp('^'+addr_spec+'$', 'i'); - + var qtext = '[^\\x0d\\x22\\x5c\\x80-\\xff]'; + var dtext = '[^\\x0d\\x5b-\\x5d\\x80-\\xff]'; + var atom = '[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+'; + var quoted_pair = '\\x5c[\\x00-\\x7f]'; + var domain_literal = '\\x5b('+dtext+'|'+quoted_pair+')*\\x5d'; + var quoted_string = '\\x22('+qtext+'|'+quoted_pair+')*\\x22'; + var sub_domain = '('+atom+'|'+domain_literal+')'; + var word = '('+atom+'|'+quoted_string+')'; + var domain = sub_domain+'(\\x2e'+sub_domain+')*'; + var local_part = word+'(\\x2e'+word+')*'; + var addr_spec = local_part+'\\x40'+domain; + var delim = '[,;\s\n]'; + var reg1 = inline ? new RegExp('(^|<|'+delim+')'+addr_spec+'($|>|'+delim+')', 'i') : new RegExp('^'+addr_spec+'$', 'i'); return reg1.test(input) ? true : false; } return false; @@ -510,8 +510,8 @@ function rcube_find_object(id, d) // determine whether the mouse is over the given object or not function rcube_mouse_is_over(ev, obj) { - var mouse = rcube_event.get_mouse_pos(ev), - pos = $(obj).offset(); + var mouse = rcube_event.get_mouse_pos(ev); + var pos = $(obj).offset(); return ((mouse.x >= pos.left) && (mouse.x < (pos.left + obj.offsetWidth)) && (mouse.y >= pos.top) && (mouse.y < (pos.top + obj.offsetHeight))); @@ -531,22 +531,18 @@ function setCookie(name, value, expires, path, domain, secure) function getCookie(name) { - var dc = document.cookie, - prefix = name + "=", - end, begin = dc.indexOf("; " + prefix); - + var dc = document.cookie; + var prefix = name + "="; + var begin = dc.indexOf("; " + prefix); if (begin == -1) { begin = dc.indexOf(prefix); - if (begin != 0) - return null; + if (begin != 0) return null; } else begin += 2; - - end = document.cookie.indexOf(";", begin); + var end = document.cookie.indexOf(";", begin); if (end == -1) end = dc.length; - return unescape(dc.substring(begin + prefix.length, end)); }; diff --git a/roundcubemail/program/js/list.js b/roundcubemail/program/js/list.js index 480cc6243..42149d6a1 100644 --- a/roundcubemail/program/js/list.js +++ b/roundcubemail/program/js/list.js @@ -76,11 +76,10 @@ init: function() this.rows = []; this.rowcount = 0; - var row, r; + var r, len, rows = this.list.tBodies[0].rows; - for (r=0; r=0; i--) - if(rows[i].id && String(rows[i].id).match(/rcmrow([a-z0-9\-_=\+\/]+)/i) && this.rows[RegExp.$1] != null) - - return RegExp.$1; + for (i=rows.length-1; i>=0; i--) + if (rows[i].id && String(rows[i].id).match(/rcmrow([a-z0-9\-_=\+\/]+)/i) && this.rows[RegExp.$1] != null) + return RegExp.$1; } return null; @@ -756,15 +751,14 @@ shift_select: function(id, control) if (!this.rows[this.shift_start] || !this.selection.length) this.shift_start = id; - var from_rowIndex = this.rows[this.shift_start].obj.rowIndex; - var to_rowIndex = this.rows[id].obj.rowIndex; - - var i = ((from_rowIndex < to_rowIndex)? from_rowIndex : to_rowIndex); - var j = ((from_rowIndex > to_rowIndex)? from_rowIndex : to_rowIndex); + var from_rowIndex = this.rows[this.shift_start].obj.rowIndex, + to_rowIndex = this.rows[id].obj.rowIndex, + i = ((from_rowIndex < to_rowIndex)? from_rowIndex : to_rowIndex), + j = ((from_rowIndex > to_rowIndex)? from_rowIndex : to_rowIndex); // iterate through the entire message list for (var n in this.rows) { - if ((this.rows[n].obj.rowIndex >= i) && (this.rows[n].obj.rowIndex <= j)) { + if (this.rows[n].obj.rowIndex >= i && this.rows[n].obj.rowIndex <= j) { if (!this.in_selection(n)) { this.highlight_row(n, true); } @@ -804,11 +798,11 @@ select_all: function(filter) this.selection = []; for (var n in this.rows) { - if (!filter || (this.rows[n] && this.rows[n][filter] == true)) { + if (!filter || this.rows[n][filter] == true) { this.last_selected = n; this.highlight_row(n, true); } - else if (this.rows[n]) { + else { $(this.rows[n].obj).removeClass('selected').removeClass('unfocused'); } } @@ -856,7 +850,7 @@ clear_selection: function(id) // one row if (id) { - for (var n=0; n12) { names += '...'; @@ -1372,20 +1365,6 @@ column_replace: function(from, to) this.subject_col = to > from ? to - 1 : to; this.triggerEvent('column_replace'); -}, - - -/** - * Creating the list in background - */ -set_background_mode: function(flag) -{ - if (flag) { - this.background = document.createElement('tbody'); - } else if (this.background) { - this.list.replaceChild(this.background, this.list.tBodies[0]); - this.background = null; - } } }; diff --git a/roundcubemail/program/steps/mail/func.inc b/roundcubemail/program/steps/mail/func.inc index 01b7c1f00..00a8edf95 100644 --- a/roundcubemail/program/steps/mail/func.inc +++ b/roundcubemail/program/steps/mail/func.inc @@ -285,6 +285,8 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $head_replace=FAL if ($header->depth) $a_msg_flags['depth'] = $header->depth; + else if ($header->has_children) + $roots[] = $header->uid; if ($header->parent_uid) $a_msg_flags['parent_uid'] = $header->parent_uid; if ($header->has_children) @@ -311,6 +313,10 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $head_replace=FAL $a_msg_flags, $insert_top); } + + if ($IMAP->threading && $a_headers) { + $OUTPUT->command('init_threads', (array) $roots); + } } diff --git a/roundcubemail/skins/default/iehacks.css b/roundcubemail/skins/default/iehacks.css index 49db2d281..0586268a7 100644 --- a/roundcubemail/skins/default/iehacks.css +++ b/roundcubemail/skins/default/iehacks.css @@ -156,6 +156,12 @@ input, textarea border-collapse: collapse; } +#messagelist thead tr td, +#messagelist tbody tr td +{ + height: 18px; +} + #messagelist tbody tr.unroot td.subject { text-decoration: underline; diff --git a/roundcubemail/skins/default/images/tree.gif b/roundcubemail/skins/default/images/tree.gif new file mode 100644 index 000000000..c78f15ef5 Binary files /dev/null and b/roundcubemail/skins/default/images/tree.gif differ diff --git a/roundcubemail/skins/default/mail.css b/roundcubemail/skins/default/mail.css index 14beb074e..3ed0420ca 100644 --- a/roundcubemail/skins/default/mail.css +++ b/roundcubemail/skins/default/mail.css @@ -397,6 +397,7 @@ td.formlinks a:visited list-style-type: none; overflow: hidden; white-space: nowrap; + background-color: #FFF; } #mailboxlist li @@ -506,7 +507,7 @@ td.formlinks a:visited border-top: 1px solid #EBEBEB; padding-left: 15px; background-position: 25px 1px; - background-color: #F9F9F9; + background-color: #FFF; color: blue; font-weight: normal; } @@ -671,10 +672,7 @@ body.messagelist #messagelist thead tr td { height: 20px; - padding-top: 0px; - padding-bottom: 0px; - padding-left: 2px; - padding-right: 4px; + padding: 0 4px 0 2px; vertical-align: middle; border-bottom: 1px solid #999999; color: #333333; @@ -708,12 +706,23 @@ body.messagelist text-decoration: none; } +#messagelist thead tr td.size +{ + text-align: left; +} + +#messagelist thead tr td.subject +{ + padding-left: 18px; +} + #messagelist tbody tr td { - height: 16px; - padding: 2px; + height: 20px; + padding: 0; font-size: 11px; overflow: hidden; + vertical-align: middle; white-space: nowrap; text-overflow: ellipsis; -o-text-overflow: ellipsis; @@ -729,75 +738,45 @@ body.messagelist cursor: inherit; } -#messagelist tbody tr td.subject a +#messagelist tr td.icon, +#messagelist tr td.threads, +#messagelist tr td.attachment, +#messagelist tr td.flag { - cursor: default; + width: 20px; + padding: 0px 1px 1px 1px; } -#messagelist col +#messagelist tbody td span.branch, +#messagelist tbody td img { - display: table-column; - text-align: left; - vertical-align: middle; -} - -#messagelist thead tr td.subject -{ - padding-left: 22px; -} - -#messagelist thead tr td.icon, -#messagelist thead tr td.flag, -#messagelist thead tr td.threads -{ - width: 22px; - padding: 0; - text-align: center; -} - -#messagelist thead tr td.threads -{ - width: 18px; -} - -#messagelist tbody tr td.flag -{ - padding: 2px 3px 2px 3px; vertical-align: middle; - cursor: pointer; -} - -#messagelist tr td span.branch -{ display: inline-block; - width: 15px; - height: 15px; } #messagelist tbody td img.msgicon { - vertical-align: middle; - position: relative; - top: 0px; - margin-right: 5px; + margin-right: 2px; } #messagelist tr td div.collapsed, #messagelist tr td div.expanded, #messagelist tr td img.flagicon, -#messagelist tr td img.msgicon +#messagelist tr td img.msgicon, +#messagelist tbody tr td.flag, +#messagelist tbody tr td.subject a { cursor: pointer; } #messagelist tr td div.collapsed { - background: url(images/messageactions.png) -1px -91px no-repeat; + background: url(images/messageactions.png) 1px -91px no-repeat; } #messagelist tr td div.expanded { - background: url(images/messageactions.png) -1px -109px no-repeat; + background: url(images/messageactions.png) 1px -109px no-repeat; } #messagelist tbody tr td.flag img:hover, @@ -806,10 +785,8 @@ body.messagelist background: url(images/icons/unflagged.png) center no-repeat; } -#messagelist tr td.subject +#messagelist tbody tr td.subject { - overflow: hidden; - vertical-align: middle; width: 99%; } @@ -821,14 +798,9 @@ body.messagelist #messagelist tr td.size { - width: 70px; + width: 60px; text-align: right; - vertical-align: middle; -} - -#messagelist thead tr td.size -{ - text-align: left; + padding: 0 2px; } #messagelist tr td.from, @@ -837,18 +809,18 @@ body.messagelist #messagelist tr td.replyto { width: 180px; - vertical-align: middle; + padding: 0 2px; } #messagelist tr td.date { width: 118px; - vertical-align: middle; + padding: 0 2px; } #messagelist tr.message { - background-color: #FFFFFF; + background-color: #FFF; } /* @@ -898,6 +870,37 @@ body.messagelist color: #CCCCCC; } +/***** tree indicators *****/ + +td span.branch div +{ + float: left; + height: 16px; +} + +td span.branch div.tree +{ + height: 17px; + width: 15px; + background: url(images/tree.gif) 0px 0px no-repeat; +} + +td span.branch div.l1 +{ + background-position: 0px 0px; /* L */ +} + +td span.branch div.l2 +{ + background-position: -30px 0px; /* | */ +} + +td span.branch div.l3 +{ + background-position: -15px 0px; /* |- */ +} + + .quota_text { text-align: center; font-size: 10px; diff --git a/roundcubemail/skins/default/safari.css b/roundcubemail/skins/default/safari.css index 942cf256b..a1be85ab4 100644 --- a/roundcubemail/skins/default/safari.css +++ b/roundcubemail/skins/default/safari.css @@ -14,3 +14,9 @@ div.message-part div.pre { word-wrap: break-word; } + +#messagelist thead tr td, +#messagelist tbody tr td +{ + height: 18px; +} -- cgit v1.2.3