diff --git a/CHANGELOG b/CHANGELOG index 541069004..04ec31d47 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,8 @@ CHANGELOG Roundcube Webmail =========================== +- Call resize handler in intervals to prevent lags and double onresize calls in Chrome (#1489005) +- Fix javascript error in IE9 when loading form with placeholders into an iframe (#1489008) - Fix handling of some conditional comment tags in HTML message (#1489004) - Add rel="noreferrer" for links in displayed messages (#1484686) - Fix so forward as attachment works if additional attachment is added by message_compose hook (#1489000) diff --git a/program/include/rcmail_output_html.php b/program/include/rcmail_output_html.php index 6100269b9..d8996edbf 100644 --- a/program/include/rcmail_output_html.php +++ b/program/include/rcmail_output_html.php @@ -873,6 +873,7 @@ class rcmail_output_html extends rcmail_output // include a file case 'include': $old_base_path = $this->base_path; + if (!empty($attrib['skin_path'])) $attrib['skinpath'] = $attrib['skin_path']; if ($path = $this->get_skin_file($attrib['file'], $skin_path, $attrib['skinpath'])) { $this->base_path = preg_replace('!plugins/\w+/!', '', $skin_path); // set base_path to core skin directory (not plugin's skin) $path = realpath($path); diff --git a/program/js/app.js b/program/js/app.js index 0f1a72448..d194b7326 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -178,6 +178,11 @@ function rcube_webmail() parent.rcmail.env.frame_lock = null; } + // Makes that reference to document.activeElement do not throw + // "unspecified error" in IE9 (#1489008) + if (this.env.framed && bw.ie) + document.documentElement.focus(); + // enable general commands this.enable_command('close', 'logout', 'mail', 'addressbook', 'settings', 'save-pref', 'compose', 'undo', 'about', 'switch-task', 'menu-open', 'menu-save', true); diff --git a/program/js/common.js b/program/js/common.js index f9e945c05..1075225b4 100644 --- a/program/js/common.js +++ b/program/js/common.js @@ -720,10 +720,12 @@ jQuery.fn.placeholder = function(text) { var elem = $(this); this.title = text; + // Try HTML5 placeholder attribute first if ('placeholder' in this) { - elem.attr('placeholder', text); // Try HTML5 placeholder attribute first + elem.attr('placeholder', text); } - else { // Fallback to Javascript emulation of placeholder + // Fallback to Javascript emulation of placeholder + else { this._placeholder = text; elem.blur(function(e) { if ($.trim(elem.val()) == "") @@ -740,7 +742,8 @@ jQuery.fn.placeholder = function(text) { elem[(active ? 'addClass' : 'removeClass')]('placeholder').attr('spellcheck', active); }); - if (this != document.activeElement) // Do not blur currently focused element + // Do not blur currently focused element + if (this != document.activeElement) elem.blur(); } }); diff --git a/program/lib/Roundcube/rcube_db.php b/program/lib/Roundcube/rcube_db.php index 49bbe5c6e..4e6684c51 100644 --- a/program/lib/Roundcube/rcube_db.php +++ b/program/lib/Roundcube/rcube_db.php @@ -444,17 +444,20 @@ class rcube_db * * @param mixed $result Optional query handle * @return mixed Number of rows or false on failure + * @deprecated This method shows very poor performance and should be avoided. */ public function num_rows($result = null) { if ($result || ($result === null && ($result = $this->last_result))) { // repeat query with SELECT COUNT(*) ... - if (preg_match('/^SELECT\s+(?:ALL\s+|DISTINCT\s+)?(?:.*?)\s+FROM\s+(.*)$/i', $result->queryString, $m)) { + if (preg_match('/^SELECT\s+(?:ALL\s+|DISTINCT\s+)?(?:.*?)\s+FROM\s+(.*)$/ims', $result->queryString, $m)) { $query = $this->dbh->query('SELECT COUNT(*) FROM ' . $m[1], PDO::FETCH_NUM); return $query ? intval($query->fetchColumn(0)) : false; } else { - return count($result->fetchAll()); + $num = count($result->fetchAll()); + $result->execute(); // re-execute query because there's no seek(0) + return $num; } } diff --git a/program/lib/Roundcube/rcube_mime.php b/program/lib/Roundcube/rcube_mime.php index b70d681c9..7cd520752 100644 --- a/program/lib/Roundcube/rcube_mime.php +++ b/program/lib/Roundcube/rcube_mime.php @@ -769,11 +769,35 @@ class rcube_mime // fallback to some well-known types most important for daily emails if (empty($mime_types)) { - $mime_extensions = @include(RCUBE_CONFIG_DIR . '/mimetypes.php'); - $mime_extensions += array('gif' => 'image/gif', 'png' => 'image/png', 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'tif' => 'image/tiff'); + $mime_extensions = (array) @include(RCUBE_CONFIG_DIR . '/mimetypes.php'); - foreach ($mime_extensions as $ext => $mime) + foreach ($mime_extensions as $ext => $mime) { $mime_types[$mime][] = $ext; + } + } + + // Add some known aliases that aren't included by some mime.types (#1488891) + // the order is important here so standard extensions have higher prio + $aliases = array( + 'image/gif' => array('gif'), + 'image/png' => array('png'), + 'image/x-png' => array('png'), + 'image/jpeg' => array('jpg', 'jpeg', 'jpe'), + 'image/jpg' => array('jpg', 'jpeg', 'jpe'), + 'image/pjpeg' => array('jpg', 'jpeg', 'jpe'), + 'image/tiff' => array('tif'), + 'message/rfc822' => array('eml'), + 'text/x-mail' => array('eml'), + ); + + foreach ($aliases as $mime => $exts) { + $mime_types[$mime] = array_unique(array_merge((array) $mime_types[$mime], $exts)); + + foreach ($exts as $ext) { + if (!isset($mime_extensions[$ext])) { + $mime_extensions[$ext] = $mime; + } + } } return $mimetype ? $mime_types[$mimetype] : $mime_extensions; diff --git a/skins/larry/ui.js b/skins/larry/ui.js index b787dbb8d..58e03fbdc 100644 --- a/skins/larry/ui.js +++ b/skins/larry/ui.js @@ -287,28 +287,36 @@ function rcube_mail_ui() /** * Update UI on window resize */ - function resize() + function resize(e) { - if (rcmail.env.task == 'mail') { - if (rcmail.env.action == 'show' || rcmail.env.action == 'preview') - layout_messageview(); - else if (rcmail.env.action == 'compose') - layout_composeview(); - } + // resize in intervals to prevent lags and double onresize calls in Chrome (#1489005) + var interval = e ? 10 : 0; - // make iframe footer buttons float if scrolling is active - $('body.iframe .footerleft').each(function(){ - var footer = $(this), - body = $(document.body), - floating = footer.hasClass('floating'), - overflow = body.outerHeight(true) > $(window).height(); - - if (overflow != floating) { - var action = overflow ? 'addClass' : 'removeClass'; - footer[action]('floating'); - body[action]('floatingbuttons'); + if (rcmail.resize_timeout) + window.clearTimeout(rcmail.resize_timeout); + + rcmail.resize_timeout = window.setTimeout(function() { + if (rcmail.env.task == 'mail') { + if (rcmail.env.action == 'show' || rcmail.env.action == 'preview') + layout_messageview(); + else if (rcmail.env.action == 'compose') + layout_composeview(); } - }); + + // make iframe footer buttons float if scrolling is active + $('body.iframe .footerleft').each(function(){ + var footer = $(this), + body = $(document.body), + floating = footer.hasClass('floating'), + overflow = body.outerHeight(true) > $(window).height(); + + if (overflow != floating) { + var action = overflow ? 'addClass' : 'removeClass'; + footer[action]('floating'); + body[action]('floatingbuttons'); + } + }); + }, interval); } /**