diff options
-rw-r--r-- | CHANGELOG | 2 | ||||
-rw-r--r-- | program/include/rcube_addressbook.php | 5 | ||||
-rw-r--r-- | program/include/rcube_ldap.php | 59 | ||||
-rw-r--r-- | program/include/rcube_vcard.php | 24 | ||||
-rw-r--r-- | program/js/app.js | 26 | ||||
-rw-r--r-- | program/localization/en_US/labels.inc | 3 | ||||
-rw-r--r-- | program/steps/mail/func.inc | 88 | ||||
-rw-r--r-- | program/steps/settings/folders.inc | 60 | ||||
-rw-r--r-- | skins/larry/ie7hacks.css | 10 | ||||
-rw-r--r-- | skins/larry/iehacks.css | 4 | ||||
-rw-r--r-- | skins/larry/images/contactpic_32px.png | bin | 3422 -> 333 bytes | |||
-rw-r--r-- | skins/larry/images/contactpic_48px.png | bin | 3812 -> 409 bytes | |||
-rw-r--r-- | skins/larry/mail.css | 147 | ||||
-rw-r--r-- | skins/larry/svggradients.css | 4 | ||||
-rw-r--r-- | skins/larry/templates/message.html | 56 | ||||
-rw-r--r-- | skins/larry/templates/messageerror.html | 16 | ||||
-rw-r--r-- | skins/larry/templates/messagepreview.html | 13 | ||||
-rw-r--r-- | skins/larry/ui.js | 35 |
18 files changed, 338 insertions, 214 deletions
@@ -1,6 +1,8 @@ CHANGELOG Roundcube Webmail =========================== +- Force fonts in compose fields to be all the same (#1488690) +- Fix handling vCard entries with TEL;TYPE=CELL (#1488728) - Integrated zipdownload plugin to download all attachments (#1445509) - Fix HTML special characters handling in message list/header display (#1488523) - List related text/html part as attachment in plain text mode (#1488677) diff --git a/program/include/rcube_addressbook.php b/program/include/rcube_addressbook.php index f4f255322..892ae263a 100644 --- a/program/include/rcube_addressbook.php +++ b/program/include/rcube_addressbook.php @@ -434,6 +434,11 @@ abstract class rcube_addressbook } } + // remove duplicates + if ($flat && !empty($out)) { + $out = array_unique($out); + } + return $out; } diff --git a/program/include/rcube_ldap.php b/program/include/rcube_ldap.php index ad2ccddeb..b9b6490fa 100644 --- a/program/include/rcube_ldap.php +++ b/program/include/rcube_ldap.php @@ -109,24 +109,22 @@ class rcube_ldap extends rcube_addressbook if (!is_array($this->coltypes[$col])) { $subtypes = $type ? array($type) : null; - $this->coltypes[$col] = array('limit' => $limit, 'subtypes' => $subtypes); + $this->coltypes[$col] = array('limit' => $limit, 'subtypes' => $subtypes, 'attributes' => array($lf)); } elseif ($type) { $this->coltypes[$col]['subtypes'][] = $type; + $this->coltypes[$col]['attributes'][] = $lf; $this->coltypes[$col]['limit'] += $limit; } if ($delim) $this->coltypes[$col]['serialized'][$type] = $delim; - if ($type && !$this->fieldmap[$col]) - $this->fieldmap[$col] = $lf; - - $this->fieldmap[$colv] = $lf; + $this->fieldmap[$colv] = $lf; } // support for composite address - if ($this->fieldmap['street'] && $this->fieldmap['locality']) { + if ($this->coltypes['street'] && $this->coltypes['locality']) { $this->coltypes['address'] = array( 'limit' => max(1, $this->coltypes['locality']['limit'] + $this->coltypes['address']['limit']), 'subtypes' => array_merge((array)$this->coltypes['address']['subtypes'], (array)$this->coltypes['locality']['subtypes']), @@ -134,7 +132,7 @@ class rcube_ldap extends rcube_addressbook ) + (array)$this->coltypes['address']; foreach (array('street','locality','zipcode','region','country') as $childcol) { - if ($this->fieldmap[$childcol]) { + if ($this->coltypes[$childcol]) { $this->coltypes['address']['childs'][$childcol] = array('type' => 'text'); unset($this->coltypes[$childcol]); // remove address child col from global coltypes list } @@ -468,8 +466,8 @@ class rcube_ldap extends rcube_addressbook */ function set_sort_order($sort_col, $sort_order = null) { - if ($this->fieldmap[$sort_col]) - $this->sort_col = $this->fieldmap[$sort_col]; + if ($this->coltypes[$sort_col]['attributes']) + $this->sort_col = $this->coltypes[$sort_col]['attributes'][0]; } @@ -858,8 +856,13 @@ class rcube_ldap extends rcube_addressbook { foreach ((array)$fields as $idx => $field) { $val = is_array($value) ? $value[$idx] : $value; - if ($f = $this->_map_field($field)) { - $filter .= "($f=$wp" . $this->_quote_string($val) . "$ws)"; + if ($attrs = $this->_map_field($field)) { + if (count($attrs) > 1) + $filter .= '(|'; + foreach ($attrs as $f) + $filter .= "($f=$wp" . $this->_quote_string($val) . "$ws)"; + if (count($attrs) > 1) + $filter .= ')'; } } } @@ -867,9 +870,16 @@ class rcube_ldap extends rcube_addressbook // add required (non empty) fields filter $req_filter = ''; - foreach ((array)$required as $field) - if ($f = $this->_map_field($field)) - $req_filter .= "($f=*)"; + foreach ((array)$required as $field) { + if ($attrs = $this->_map_field($field)) { + if (count($attrs) > 1) + $req_filter .= '(|'; + foreach ($attrs as $f) + $req_filter .= "($f=*)"; + if (count($attrs) > 1) + $req_filter .= ')'; + } + } if (!empty($req_filter)) $filter = '(&' . $req_filter . $filter . ')'; @@ -1498,7 +1508,7 @@ class rcube_ldap extends rcube_addressbook list($col, $subtype) = explode(':', $rf); $out['_raw_attrib'][$lf][$i] = $value; - if ($rf == 'email' && $this->mail_domain && !strpos($value, '@')) + if ($col == 'email' && $this->mail_domain && !strpos($value, '@')) $out[$rf][] = sprintf('%s@%s', $value, $this->mail_domain); else if (in_array($col, array('street','zipcode','locality','country','region'))) $out['address'.($subtype?':':'').$subtype][$i][$col] = $value; @@ -1521,11 +1531,11 @@ class rcube_ldap extends rcube_addressbook /** - * Return real field name (from fields map) + * Return LDAP attribute(s) for the given field */ private function _map_field($field) { - return $this->fieldmap[$field]; + return (array)$this->coltypes[$field]['attributes']; } @@ -1558,8 +1568,19 @@ class rcube_ldap extends rcube_addressbook } $ldap_data = array(); - foreach ($this->fieldmap as $col => $fld) { - $val = $save_cols[$col]; + foreach ($this->fieldmap as $rf => $fld) { + $val = $save_cols[$rf]; + + // check for value in base field (eg.g email instead of email:foo) + list($col, $subtype) = explode(':', $rf); + if (!$val && !empty($save_cols[$col])) { + $val = $save_cols[$col]; + unset($save_cols[$col]); // only use this value once + } + else if (!$val && !$subtype) { // extract values from subtype cols + $val = $this->get_col_values($col, $save_cols, true); + } + if (is_array($val)) $val = array_filter($val); // remove empty entries if ($fld && $val) { diff --git a/program/include/rcube_vcard.php b/program/include/rcube_vcard.php index 49b312c5c..00903c257 100644 --- a/program/include/rcube_vcard.php +++ b/program/include/rcube_vcard.php @@ -50,7 +50,7 @@ class rcube_vcard 'spouse' => 'X-SPOUSE', 'edit' => 'X-AB-EDIT', ); - private $typemap = array('iPhone' => 'mobile', 'CELL' => 'mobile', 'WORK,FAX' => 'workfax'); + private $typemap = array('IPHONE' => 'mobile', 'CELL' => 'mobile', 'WORK,FAX' => 'workfax'); private $phonetypemap = array('HOME1' => 'HOME', 'BUSINESS1' => 'WORK', 'BUSINESS2' => 'WORK2', 'BUSINESSFAX' => 'WORK,FAX'); private $addresstypemap = array('BUSINESS' => 'WORK'); private $immap = array('X-JABBER' => 'jabber', 'X-ICQ' => 'icq', 'X-MSN' => 'msn', 'X-AIM' => 'aim', 'X-YAHOO' => 'yahoo', 'X-SKYPE' => 'skype', 'X-SKYPE-USERNAME' => 'skype'); @@ -159,7 +159,18 @@ class rcube_vcard if (!empty($raw['type'])) { $combined = join(',', self::array_filter((array)$raw['type'], 'internet,pref', true)); - $subtype = $typemap[$combined] ? $typemap[$combined] : ($typemap[$raw['type'][++$k]] ? $typemap[$raw['type'][$k]] : strtolower($raw['type'][$k])); + $combined = strtoupper($combined); + + if ($typemap[$combined]) { + $subtype = $typemap[$combined]; + } + else if ($typemap[$raw['type'][++$k]]) { + $subtype = $typemap[$raw['type'][$k]]; + } + else { + $subtype = strtolower($raw['type'][$k]); + } + while ($k < count($raw['type']) && ($subtype == 'internet' || $subtype == 'pref')) $subtype = $typemap[$raw['type'][++$k]] ? $typemap[$raw['type'][$k]] : strtolower($raw['type'][$k]); } @@ -167,8 +178,11 @@ class rcube_vcard // read vcard 2.1 subtype if (!$subtype) { foreach ($raw as $k => $v) { - if (!is_numeric($k) && $v === true && !in_array(strtolower($k), array('pref','internet','voice','base64'))) { - $subtype = $typemap[$k] ? $typemap[$k] : strtolower($k); + if (!is_numeric($k) && $v === true && ($k = strtolower($k)) + && !in_array($k, array('pref','internet','voice','base64')) + ) { + $k_uc = strtoupper($k); + $subtype = $typemap[$k_uc] ? $typemap[$k_uc] : $k; break; } } @@ -335,7 +349,7 @@ class rcube_vcard $index = count($this->raw[$tag]); $this->raw[$tag][$index] = (array)$value; if ($type) - $this->raw[$tag][$index]['type'] = explode(',', ($typemap[$type] ? $typemap[$type] : $type)); + $this->raw[$tag][$index]['type'] = explode(',', ($typemap[$type_uc] ? $typemap[$type_uc] : $type)); } break; } diff --git a/program/js/app.js b/program/js/app.js index 4d784e532..06eb9295c 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -5624,6 +5624,32 @@ function rcube_webmail() this.messages = {}; }; + // open a jquery UI dialog with the given content + this.show_popup_dialog = function(html, title) + { + // forward call to parent window + if (this.is_framed()) { + parent.rcmail.show_popup_dialog(html, title); + return; + } + + var popup = $('<div class="popup">') + .html(html) + .dialog({ + title: title, + modal: true, + resizable: true, + width: 580, + close: function(event, ui) { $(this).remove() } + }); + + // resize and center popup + var win = $(window), w = win.width(), h = win.height(), + width = popup.width(), height = popup.height(); + popup.dialog('option', { height: Math.min(h-40, height+50), width: Math.min(w-20, width+50) }) + .dialog('option', 'position', ['center', 'center']); // only works in a separate call (!?) + }; + // enable/disable buttons for page shifting this.set_page_buttons = function() { diff --git a/program/localization/en_US/labels.inc b/program/localization/en_US/labels.inc index 9882c19b5..fbc154b88 100644 --- a/program/localization/en_US/labels.inc +++ b/program/localization/en_US/labels.inc @@ -236,6 +236,9 @@ $labels['nosubject'] = '(no subject)'; $labels['showimages'] = 'Display images'; $labels['alwaysshow'] = 'Always show images from $sender'; $labels['isdraft'] = 'This is a draft message.'; +$labels['andnmore'] = '$nr more...'; +$labels['togglemoreheaders'] = 'Show more message headers'; +$labels['togglefullheaders'] = 'Toggle raw message headers'; $labels['htmltoggle'] = 'HTML'; $labels['plaintoggle'] = 'Plain text'; diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 8bf80a6ee..e3866aa57 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -319,7 +319,7 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null $col_name = $col == 'fromto' ? $smart_col : $col; if (in_array($col_name, array('from', 'to', 'cc', 'replyto'))) - $cont = Q(rcmail_address_string($header->$col_name, 3, false, null, $header->charset), 'show'); + $cont = rcmail_address_string($header->$col_name, 3, false, null, $header->charset); else if ($col == 'subject') { $cont = trim(rcube_mime::decode_header($header->$col, $header->charset)); if (!$cont) $cont = rcube_label('nosubject'); @@ -957,6 +957,8 @@ function rcmail_message_headers($attrib, $headers=NULL) $output_headers = array(); foreach ($standard_headers as $hkey) { + $ishtml = false; + if ($headers[$hkey]) $value = $headers[$hkey]; else if ($headers['others'][$hkey]) @@ -967,6 +969,8 @@ function rcmail_message_headers($attrib, $headers=NULL) if (in_array($hkey, $exclude_headers)) continue; + $header_title = rcube_label(preg_replace('/(^mail-|-)/', '', $hkey)); + if ($hkey == 'date') { if ($PRINT_MODE) $header_value = format_date($value, $RCMAIL->config->get('date_long', 'x')); @@ -981,32 +985,41 @@ function rcmail_message_headers($attrib, $headers=NULL) continue; } else if ($hkey == 'replyto') { - if ($headers['replyto'] != $headers['from']) - $header_value = rcmail_address_string($value, null, true, $attrib['addicon'], $headers['charset']); + if ($headers['replyto'] != $headers['from']) { + $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title); + $ishtml = true; + } else continue; } else if ($hkey == 'mail-reply-to') { if ($headers['mail-replyto'] != $headers['reply-to'] && $headers['reply-to'] != $headers['from'] - ) - $header_value = rcmail_address_string($value, null, true, $attrib['addicon'], $headers['charset']); + ) { + $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title); + $ishtml = true; + } else continue; } else if ($hkey == 'mail-followup-to') { - $header_value = rcmail_address_string($value, null, true, $attrib['addicon'], $headers['charset']); + $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title); + $ishtml = true; + } + else if (in_array($hkey, array('from', 'to', 'cc', 'bcc'))) { + $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title); + $ishtml = true; } - else if (in_array($hkey, array('from', 'to', 'cc', 'bcc'))) - $header_value = rcmail_address_string($value, null, true, $attrib['addicon'], $headers['charset']); else if ($hkey == 'subject' && empty($value)) $header_value = rcube_label('nosubject'); else $header_value = trim(rcube_mime::decode_header($value, $headers['charset'])); $output_headers[$hkey] = array( - 'title' => rcube_label(preg_replace('/(^mail-|-)/', '', $hkey)), - 'value' => $header_value, 'raw' => $value + 'title' => $header_title, + 'value' => $header_value, + 'raw' => $value, + 'html' => $ishtml, ); } @@ -1022,7 +1035,7 @@ function rcmail_message_headers($attrib, $headers=NULL) foreach ($plugin['output'] as $hkey => $row) { $table->add(array('class' => 'header-title'), Q($row['title'])); - $table->add(array('class' => 'header '.$hkey), Q($row['value'], ($hkey == 'subject' ? 'strict' : 'show'))); + $table->add(array('class' => 'header '.$hkey), $row['html'] ? $row['value'] : Q($row['value'], ($hkey == 'subject' ? 'strict' : 'show'))); } return $table->show($attrib); @@ -1055,17 +1068,12 @@ function rcmail_message_full_headers($attrib, $headers=NULL) global $OUTPUT; $html = html::div(array('id' => "all-headers", 'class' => "all", 'style' => 'display:none'), html::div(array('id' => 'headers-source'), '')); - - if (!get_boolean($attrib['no-switch'])) { - $html .= html::div(array('class' => "more-headers show-headers", 'onclick' => "return ".JS_OBJECT_NAME.".command('show-headers','',this)"), ''); - } - - unset($attrib['no-switch']); + $html .= html::div(array('class' => "more-headers show-headers", 'onclick' => "return ".JS_OBJECT_NAME.".command('show-headers','',this)", 'title' => rcube_label('togglefullheaders')), ''); $OUTPUT->add_gui_object('all_headers_row', 'all-headers'); $OUTPUT->add_gui_object('all_headers_box', 'headers-source'); - return count($attrib) > 1 ? html::div($attrib, $html) : $html; + return html::div($attrib, $html); } @@ -1399,7 +1407,7 @@ function rcmail_alter_html_link($matches) /** * decode address string and re-format it as HTML links */ -function rcmail_address_string($input, $max=null, $linked=false, $addicon=null, $default_charset=null) +function rcmail_address_string($input, $max=null, $linked=false, $addicon=null, $default_charset=null, $title=null) { global $RCMAIL, $PRINT_MODE, $CONFIG; @@ -1411,6 +1419,7 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null, $c = count($a_parts); $j = 0; $out = ''; + $allvalues = array(); if ($addicon && !isset($_SESSION['writeable_abook'])) { $_SESSION['writeable_abook'] = $RCMAIL->get_address_sources(true) ? true : false; @@ -1418,7 +1427,6 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null, foreach ($a_parts as $part) { $j++; - $name = $part['name']; $mailto = $part['mailto']; $string = $part['string']; @@ -1449,7 +1457,7 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null, } if ($addicon && $_SESSION['writeable_abook']) { - $address = html::span(null, $address . html::a(array( + $address .= html::a(array( 'href' => "#add", 'onclick' => sprintf("return %s.command('add-contact','%s',this)", JS_OBJECT_NAME, $string), 'title' => rcube_label('addtoaddressbook'), @@ -1458,26 +1466,46 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null, html::img(array( 'src' => $CONFIG['skin_path'] . $addicon, 'alt' => "Add contact", - )))); + ))); } - $out .= $address; } else { + $address = ''; if ($name) - $out .= Q($name); + $address .= Q($name); if ($mailto) - $out .= (strlen($out) ? ' ' : '') . sprintf('<%s>', Q($mailto)); + $address .= (strlen($address) ? ' ' : '') . sprintf('<%s>', Q($mailto)); } - if ($c>$j) - $out .= ','.($max ? ' ' : ' '); + $address = html::span('adr', $address); + $allvalues[] = $address; - if ($max && $j==$max && $c>$j) { - $out .= '...'; - break; + if (!$moreadrs) + $out .= ($out ? ', ' : '') . $address; + + if ($max && $j == $max && $c > $j) { + if ($linked) { + $moreadrs = $c - $j; + } + else { + $out .= '...'; + break; + } } } + if ($moreadrs) { + $out .= ' ' . html::a(array( + 'href' => '#more', + 'class' => 'morelink', + 'onclick' => sprintf("return %s.show_popup_dialog('%s','%s')", + JS_OBJECT_NAME, + JQ(join(', ', $allvalues)), + JQ($title)) + ), + Q(rcube_label(array('name' => 'andnmore', 'vars' => array('nr' => $moreadrs))))); + } + return $out; } diff --git a/program/steps/settings/folders.inc b/program/steps/settings/folders.inc index 3231ed644..12e449e80 100644 --- a/program/steps/settings/folders.inc +++ b/program/steps/settings/folders.inc @@ -299,40 +299,44 @@ function rcube_subscription_form($attrib) $disabled = (($protected && $subscribed) || $noselect); - // check if the folder is a namespace prefix, then disable subscription option on it - if (!$disabled && $folder['virtual'] && $folder['level'] == 0 && !empty($namespace)) { - $fname = $folder['id'] . $delimiter; - foreach ($namespace as $ns) { - if (is_array($ns)) { - foreach ($ns as $item) { - if ($item[0] === $fname) { - $disabled = true; - break 2; + // Below we will disable subscription option for "virtual" folders + // according to namespaces, but only if they aren't already subscribed. + // User should be able to unsubscribe from the folder + // even if it doesn't exists or is not accessible (OTRS:1000059) + if (!$subscribed && !$disabled && !empty($namespace) && $folder['virtual']) { + // check if the folder is a namespace prefix, then disable subscription option on it + if (!$disabled && $folder['level'] == 0) { + $fname = $folder['id'] . $delimiter; + foreach ($namespace as $ns) { + if (is_array($ns)) { + foreach ($ns as $item) { + if ($item[0] === $fname) { + $disabled = true; + break 2; + } } } } } - } - // check if the folder is an other users virtual-root folder, then disable subscription option on it - if (!$disabled && $folder['virtual'] && $folder['level'] == 1 - && !empty($namespace) && !empty($namespace['other']) - ) { - $parts = explode($delimiter, $folder['id']); - $fname = $parts[0] . $delimiter; - foreach ($namespace['other'] as $item) { - if ($item[0] === $fname) { - $disabled = true; - break; + // check if the folder is an other users virtual-root folder, then disable subscription option on it + if (!$disabled && $folder['level'] == 1 && !empty($namespace['other'])) { + $parts = explode($delimiter, $folder['id']); + $fname = $parts[0] . $delimiter; + foreach ($namespace['other'] as $item) { + if ($item[0] === $fname) { + $disabled = true; + break; + } } } - } - // check if the folder is shared, then disable subscription option on it (if not subscribed already) - if (!$disabled && !$subscribed && $folder['virtual'] && !empty($namespace)) { - $tmp_ns = array_merge((array)$namespace['other'], (array)$namespace['shared']); - foreach ($tmp_ns as $item) { - if (strpos($folder['id'], $item[0]) === 0) { - $disabled = true; - break; + // check if the folder is shared, then disable subscription option on it (if not subscribed already) + if (!$disabled) { + $tmp_ns = array_merge((array)$namespace['other'], (array)$namespace['shared']); + foreach ($tmp_ns as $item) { + if (strpos($folder['id'], $item[0]) === 0) { + $disabled = true; + break; + } } } } diff --git a/skins/larry/ie7hacks.css b/skins/larry/ie7hacks.css index 935a504fe..893ffdfef 100644 --- a/skins/larry/ie7hacks.css +++ b/skins/larry/ie7hacks.css @@ -29,7 +29,7 @@ a.deletebutton, .boxfooter .listbutton .inner, .attachmentslist li a.delete, .attachmentslist li a.cancelupload, -#messageheader .iconlink { +.previewheader .iconlink { /* workaround for text-indent which also offsets the background image */ text-indent: 0; font-size: 0; @@ -45,7 +45,7 @@ a.deletebutton, .pagenav a.button, .pagenav a.button span.inner, -#messageheader .iconlink, +.previewheader .iconlink, #uploadform a.iconlink { display: inline; } @@ -58,6 +58,10 @@ a.deletebutton, right: -2px; } +#login-form .box-inner form { + margin: 0; +} + #login-form #message div { float: left; display: block; @@ -67,7 +71,7 @@ a.deletebutton, text-align: left; } -#messageheader .iconlink { +#messageheader.previewheader .iconlink { color: #fff; height: 14px; } diff --git a/skins/larry/iehacks.css b/skins/larry/iehacks.css index bba93dc33..93f483c11 100644 --- a/skins/larry/iehacks.css +++ b/skins/larry/iehacks.css @@ -143,8 +143,8 @@ ul.toolbarmenu li a.active:hover, filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#005d76', endColorstr='#004558', GradientType=0); } -#partheader, #composeheaders { - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e9e9e9', GradientType=0); +#messageheader, #partheader, #composeheaders { + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f0f0f0', GradientType=0); } #previewheaderstoggle { diff --git a/skins/larry/images/contactpic_32px.png b/skins/larry/images/contactpic_32px.png Binary files differindex 25a81418d..233bb1496 100644 --- a/skins/larry/images/contactpic_32px.png +++ b/skins/larry/images/contactpic_32px.png diff --git a/skins/larry/images/contactpic_48px.png b/skins/larry/images/contactpic_48px.png Binary files differindex 9cd3bceaf..e536ddf0e 100644 --- a/skins/larry/images/contactpic_48px.png +++ b/skins/larry/images/contactpic_48px.png diff --git a/skins/larry/mail.css b/skins/larry/mail.css index 04f56e134..a2756638d 100644 --- a/skins/larry/mail.css +++ b/skins/larry/mail.css @@ -38,6 +38,10 @@ bottom: 28px; } +#mailview-top.fullheight { + border-radius: 4px 4px 0 0; +} + #mailview-bottom { position: absolute; left: 0; @@ -46,10 +50,6 @@ height: 26px; } -#mailview-top.fullheight { - border-radius: 4px 4px 0 0; -} - #folderlist-header { width: 100%; height: 12px; @@ -675,24 +675,33 @@ a.iconbutton.threadmode.selected { #messagecontent { position: absolute; - top: 0; + top: 110px; left: 0; width: 100%; - bottom: 28px; + bottom: 27px; overflow: auto; - border-radius: 4px 4px 0 0; } +#messageheader, #partheader, #composeheaders { position: relative; padding: 3px 0; background: #f9f9f9; - background: -moz-linear-gradient(top, #fff 0%, #e9e9e9 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#fff), color-stop(100%,#e9e9e9)); - background: -o-linear-gradient(top, #fff 0%, #e9e9e9 100%); - background: -ms-linear-gradient(top, #fff 0%, #e9e9e9 100%); - background: linear-gradient(top, #fff 0%, #e9e9e9 100%); + background: -moz-linear-gradient(top, #fff 0%, #f0f0f0 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#fff), color-stop(100%,#f0f0f0)); + background: -o-linear-gradient(top, #fff 0%, #f0f0f0 100%); + background: -ms-linear-gradient(top, #fff 0%, #f0f0f0 100%); + background: linear-gradient(top, #fff 0%, #f0f0f0 100%); + border-bottom: 1px solid #dfdfdf; +} + +#mailview-right #messageheader { + border-radius: 4px 4px 0 0; + padding-left: 78px; + /* avoid headers eating up all the vertical space */ + max-height: 50%; + overflow: auto; } h2.subject { @@ -704,9 +713,13 @@ h2.subject { text-overflow: ellipsis; } +#mailview-right #messageheader h2.subject { + margin-left: -56px; +} + h3.subject { font-size: 14px; - margin: 0 13em 0 0; + margin: 0 8em 0 0; padding: 8px 8px 4px 8px; white-space: nowrap; overflow: hidden; @@ -718,16 +731,23 @@ h3.subject { padding: 2px 8px; } -.headers-table td.header { +.headers-table td.header, +.ui-dialog-content.popup span.adr { font-weight: bold; } -.headers-table td.header a { +.headers-table td.header-title { + white-space: nowrap; +} + +.headers-table td.header a, +.ui-dialog-content.popup span.adr a { color: #666; text-decoration: none; } -.headers-table td.header a:hover { +.headers-table td.header a:hover, +.ui-dialog-content.popup span.adr a:hover { text-decoration: underline; } @@ -737,8 +757,15 @@ h3.subject { font-weight: bold; } -.headers-table td.header span { +.headers-table td.header span, +.ui-dialog-content.popup span.adr { + white-space: nowrap; +} + +.headers-table td.header a.morelink { + color: #0069a6; white-space: nowrap; + font-weight: normal; } .rcmaddcontact { @@ -796,29 +823,40 @@ h3.subject { #previewheaderstoggle.remove .iconlink { top: auto; - bottom: 15px; + bottom: 5px; background-position: -5px -242px; } -#previewheaderstoggle .iconlink.allheaders { - display: none; +#full-headers { + position: relative; } -#previewheaderstoggle.remove .iconlink.allheaders { - top: auto; - bottom: 2px; - display: inline-block; - background-position: -27px -242px; +div.more-headers { + position: absolute; + top: -12px; + right: 10px; + width: 12px; + height: 10px; + cursor: pointer; + background: url(images/buttons.png) center -1619px no-repeat; +} + +div.hide-headers { + background-position: center -1629px; } #all-headers { position: relative; - margin: 2px 0; + margin: 4px 10px; padding: 0; height: 180px; - background-color: #f0f0f0; - overflow: hidden; + border: 1px solid #ccc; border-radius: 4px; + background: #fdfdfd; + -moz-box-shadow: inset 0 0 1px 1px rgba(0,0,0, 0.1); + -webkit-box-shadow: inset 0 0 1px 1px rgba(0,0,0, 0.1); + -o-box-shadow: inset 0 0 1px 1px rgba(0,0,0, 0.1); + box-shadow: inset 0 0 1px 1px rgba(0,0,0, 0.1); } #headers-source { @@ -828,31 +866,28 @@ h3.subject { left: 0; right: 0; bottom: 0; - padding: 2px; + padding: 3px 6px; overflow: auto; text-align: left; - color: #666; + color: #333; +} + +#messageheader.previewheader #all-headers { + margin-left: 0; } -#messageheader { +#messageheader.previewheader { position: relative; height: auto; min-height: 52px; - margin: 0 8px 0 0; - padding: 0 0 0 72px; - border-bottom: 2px solid #f0f0f0; -} - -#messagecontent #messageheader { - padding: 0 0 0 90px; - min-height: 68px; + padding: 0 0 3px 72px; } -#messageheader h3.subject { +#messageheader.previewheader h3.subject { padding: 8px 8px 2px 0; } -#messageheader #contactphoto { +#messageheader.previewheader #contactphoto { display: block; position: absolute; top: 11px; @@ -864,22 +899,26 @@ h3.subject { border-radius: 3px; } -#messageheader #contactphoto img { +#messageheader.previewheader #contactphoto img { width: 32px; height: auto; border-radius: 3px; } -#messagecontent #messageheader #contactphoto { - top: 11px; - left: 31px; +#messageheader #contactphoto { + display: block; + position: absolute; + top: 34px; + left: 30px; width: 48px; height: 48px; - background: url(images/contactpic_48px.png) center center no-repeat #fff; + overflow: hidden; border-radius: 4px; + border: 1px solid #e6e6e6; + background: url(images/contactpic_48px.png) center center no-repeat #fff; } -#messagecontent #messageheader #contactphoto img { +#messageheader #contactphoto img { width: 48px; height: auto; border-radius: 4px; @@ -888,16 +927,25 @@ h3.subject { #messageheader #countcontrols { position: absolute; top: 8px; - right: 0; + right: 8px; + width: 20em; text-align: right; white-space: nowrap; } +#messageheader .pagenav .countdisplay { + min-width: 0; + padding-right: 0.5em; + white-space: nowrap; +} + +#messagecontent .leftcol, #messagepreview .leftcol { margin-right: 252px; overflow-x: auto; } +#messagecontent .rightcol, #messagepreview .rightcol { float: right; /* @@ -1110,6 +1158,7 @@ div.message-part blockquote blockquote blockquote { -webkit-box-shadow: 0 2px 3px 0 #999; -moz-box-shadow: 0 2px 3px 0 #999; box-shadow: 0 2px 3px 0 #999; + border-bottom: 0; } #composebuttons { @@ -1168,6 +1217,8 @@ div.message-part blockquote blockquote blockquote { .compose-headers td input { width: 100%; resize: none; + font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; + font-size: 11px; } #compose-cc, #compose-bcc, #compose-replyto, #compose-followupto { diff --git a/skins/larry/svggradients.css b/skins/larry/svggradients.css index 4f1dd8a05..5b3fedbfc 100644 --- a/skins/larry/svggradients.css +++ b/skins/larry/svggradients.css @@ -133,8 +133,8 @@ ul.toolbarmenu li a.active:hover, background-image: url(svggradient.php?c=005d76;004558); } -#partheader, #composeheaders { - background-image: url(svggradient.php?c=ffffff;e9e9e9); +#messageheader, #partheader, #composeheaders { + background-image: url(svggradient.php?c=ffffff;f0f0f0); } #previewheaderstoggle { diff --git a/skins/larry/templates/message.html b/skins/larry/templates/message.html index 89b7bd808..e99f2066a 100644 --- a/skins/larry/templates/message.html +++ b/skins/larry/templates/message.html @@ -24,38 +24,21 @@ <!-- folders list --> <div id="mailboxcontainer" class="uibox listbox"> - <div class="scroller"> - <roundcube:object name="mailboxlist" id="mailboxlist" class="listing" folder_filter="mail" unreadwrap="%s" /> - </div> +<div class="scroller"> +<roundcube:object name="mailboxlist" id="mailboxlist" class="listing" folder_filter="mail" unreadwrap="%s" /> +</div> </div> -</div><!-- end mailview-left --> - -<div id="mailview-right" class="uibox" style="top: 42px"> +</div> -<div id="messagecontent"> +<div id="mailview-right" class="offset uibox"> <div id="messageheader"> -<h3 class="subject"><roundcube:object name="messageHeaders" valueOf="subject" /></h3> - -<a href="#details" id="previewheaderstoggle"><span class="iconlink"></span><span id="headerstoggleall" class="iconlink allheaders"></span></a> - -<div id="contactphoto"><roundcube:object name="contactphoto" /></div> +<span id="previewheaderstoggle"></span> -<table class="headers-table" id="preview-shortheaders"><tbody><tr> -<roundcube:if condition="env:mailbox == config:drafts_mbox || env:mailbox == config:sent_mbox"> - <td class="header-title"><roundcube:label name="to" /></td> - <td class="header from"><roundcube:object name="messageHeaders" valueOf="to" addicon="/images/addcontact.png" /></td> -<roundcube:else /> - <td class="header-title"><roundcube:label name="from" /></td> - <td class="header from"><roundcube:object name="messageHeaders" valueOf="from" addicon="/images/addcontact.png" /></td> -<roundcube:endif /> - <td class="header-title"><roundcube:label name="date" /></td> - <td class="header from"><roundcube:object name="messageHeaders" valueOf="date" /></td> -</tr></tbody></table> - -<roundcube:object name="messageHeaders" id="preview-allheaders" class="headers-table" addicon="/images/addcontact.png" exclude="subject,replyto" /> -<roundcube:object name="messageFullHeaders" no-switch="true" /> +<h2 class="subject"><roundcube:object name="messageHeaders" valueOf="subject" /></h2> +<roundcube:object name="messageHeaders" class="headers-table" addicon="/images/addcontact.png" exclude="subject" max="20" /> +<roundcube:object name="messageFullHeaders" id="full-headers" /> <!-- record navigation --> <div id="countcontrols" class="pagenav"> @@ -64,19 +47,18 @@ <roundcube:button command="nextmessage" type="link" class="button nextpage disabled" classAct="button nextpage" classSel="button nextpage pressed" innerClass="inner" title="nextmessage" content="&gt;" /> </div> -</div><!-- end messageheader --> - -<div id="messagepreview"> - <div class="rightcol"> - <roundcube:object name="messageAttachments" id="attachment-list" class="attachmentslist" /> - </div> - <div class="leftcol"> - <roundcube:object name="messageObjects" id="message-objects" /> - <roundcube:object name="messageBody" id="messagebody" /> - </div> +<div id="contactphoto"><roundcube:object name="contactphoto" /></div> </div> -</div><!-- end messagecontent --> +<div id="messagecontent"> +<div class="rightcol"> +<roundcube:object name="messageAttachments" id="attachment-list" class="attachmentslist" /> +</div> +<div class="leftcol"> +<roundcube:object name="messageObjects" id="message-objects" /> +<roundcube:object name="messageBody" id="messagebody" /> +</div> +</div> <roundcube:object name="message" id="message" class="statusbar" /> diff --git a/skins/larry/templates/messageerror.html b/skins/larry/templates/messageerror.html index 2f5243200..3c3c9acdb 100644 --- a/skins/larry/templates/messageerror.html +++ b/skins/larry/templates/messageerror.html @@ -16,6 +16,13 @@ <div id="mainscreen"> +<!-- toolbar --> +<div id="messagetoolbar" class="fullwidth"> + <div id="mailtoolbar" class="toolbar"> + <roundcube:button command="list" type="link" class="button back disabled" classAct="button back" classSel="button back pressed" label="back" /> + </div> +</div> + <div id="mailview-left"> <!-- folders list --> @@ -27,14 +34,7 @@ </div> -<!-- toolbar --> -<div id="messagetoolbar" class="fullwidth"> - <div id="mailtoolbar" class="toolbar"> - <roundcube:button command="list" type="link" class="button back disabled" classAct="button back" classSel="button back pressed" label="back" /> - </div> -</div> - -<div id="mailview-right" class="uibox" style="top: 42px"> +<div id="mailview-right" class="offset uibox"> <div id="messagecontent" class="watermark"></div> diff --git a/skins/larry/templates/messagepreview.html b/skins/larry/templates/messagepreview.html index 74c414b0d..de02b050b 100644 --- a/skins/larry/templates/messagepreview.html +++ b/skins/larry/templates/messagepreview.html @@ -6,26 +6,27 @@ </head> <body class="iframe fullheight"> -<div id="messageheader"> +<div id="messageheader" class="previewheader"> <h3 class="subject"><roundcube:object name="messageHeaders" valueOf="subject" /></h3> -<a href="#details" id="previewheaderstoggle"><span class="iconlink"></span><span id="headerstoggleall" class="iconlink allheaders"></a> +<a href="#details" id="previewheaderstoggle"><span class="iconlink" title="<roundcube:label name='togglemoreheaders' />"></span></a> <div id="contactphoto"><roundcube:object name="contactphoto" /></div> <table class="headers-table" id="preview-shortheaders"><tbody><tr> <roundcube:if condition="env:mailbox == config:drafts_mbox || env:mailbox == config:sent_mbox"> <td class="header-title"><roundcube:label name="to" /></td> - <td class="header from"><roundcube:object name="messageHeaders" valueOf="to" addicon="/images/addcontact.png" /></td> + <td class="header from"><roundcube:object name="messageHeaders" valueOf="to" max="3" addicon="/images/addcontact.png" /></td> <roundcube:else /> <td class="header-title"><roundcube:label name="from" /></td> <td class="header from"><roundcube:object name="messageHeaders" valueOf="from" addicon="/images/addcontact.png" /></td> <roundcube:endif /> <td class="header-title"><roundcube:label name="date" /></td> - <td class="header from"><roundcube:object name="messageHeaders" valueOf="date" /></td> + <td class="header date"><span><roundcube:object name="messageHeaders" valueOf="date" /></span></td> </tr></tbody></table> -<roundcube:object name="messageHeaders" id="preview-allheaders" class="headers-table" addicon="/images/addcontact.png" exclude="subject,replyto" /> -<roundcube:object name="messageFullHeaders" no-switch="true" /> +<roundcube:object name="messageHeaders" id="preview-allheaders" class="headers-table" addicon="/images/addcontact.png" max="10" exclude="subject,replyto" /> + +<roundcube:object name="messageFullHeaders" id="full-headers" /> <!-- record navigation --> <div id="countcontrols" class="pagenav"> diff --git a/skins/larry/ui.js b/skins/larry/ui.js index c221b8681..9b5d8309c 100644 --- a/skins/larry/ui.js +++ b/skins/larry/ui.js @@ -73,9 +73,9 @@ function rcube_mail_ui() } if (rcmail.env.action == 'show' || rcmail.env.action == 'preview') { - layout_messageview(); - $('#previewheaderstoggle').click(function(e){ toggle_preview_headers(this); return false; }); - $('#headerstoggleall').click(function(e){ toggle_all_headers(this); return false; }); + rcmail.addEventListener('aftershow-headers', function() { layout_messageview(); }); + rcmail.addEventListener('afterhide-headers', function() { layout_messageview(); }); + $('#previewheaderstoggle').click(function(e){ toggle_preview_headers(this); return false }); } else if (rcmail.env.action == 'compose') { rcmail.addEventListener('aftertoggle-editor', function(){ window.setTimeout(function(){ layout_composeview() }, 200); }); @@ -320,6 +320,7 @@ function rcube_mail_ui() */ function layout_messageview() { + $('#messagecontent').css('top', ($('#messageheader').outerHeight() + 1) + 'px'); $('#message-objects div a').addClass('button'); if (!$('#attachment-list li').length) { @@ -512,31 +513,13 @@ function rcube_mail_ui() { $('#preview-shortheaders').toggle(); var full = $('#preview-allheaders').toggle(), - button = $('#previewheaderstoggle'); - - if (!$('#headerstoggleall').length) - $('#all-headers').toggle(); + button = $('a#previewheaderstoggle'); // add toggle button to full headers table - if (full.is(':visible')) { - button.attr('href', '#hide').removeClass('add').addClass('remove'); - } - else { - button.attr('href', '#details').removeClass('remove').addClass('add'); - } - } - - - /** - * Show/hide all message headers - */ - function toggle_all_headers(button) - { - rcmail.command('show-headers', '', button); - $(button).remove(); - $('#previewheaderstoggle span').css({bottom: '5px'}); - - return false; + if (full.is(':visible')) + button.attr('href', '#hide').removeClass('add').addClass('remove') + else + button.attr('href', '#details').removeClass('remove').addClass('add') } |