From ddef3926aac2b36a22d87b8efb558047bb584f01 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Mon, 25 Mar 2019 09:26:23 +0100 Subject: [PATCH 01/45] Fix TinyMCE download location (#6694) --- CHANGELOG | 1 + jsdeps.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 00f78b728..02df4c5ad 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,7 @@ CHANGELOG Roundcube Webmail - Elastic: Changed "Move to..." icon (#6637) - Elastic: Add hide/show for advanced preferences (#6632) - Elastic: Fix bug where toolbar disappears on attachment menu use in Chrome (#6677) +- Fix TinyMCE download location (#6694) - Fix so "Open in new window" consistently displays "external window" interface (#6659) - Fix bug where next row wasn't selected after deleting a collapsed thread (#6655) - Fix bug where external content (e.g. mail body) was passed to templates parsing code (#6640) diff --git a/jsdeps.json b/jsdeps.json index 53454801e..906bf872e 100644 --- a/jsdeps.json +++ b/jsdeps.json @@ -37,7 +37,7 @@ { "lib": "tinymce", "version": "4.8.2", - "url": "http://download.ephox.com/tinymce/community/tinymce_$v.zip", + "url": "https://download.tiny.cloud/tinymce/community/tinymce_$v.zip", "dest": "program/js", "sha1": "d7fced05acdeeb78299585ea9909b0de2b3d759d", "license": "LGPL", From 00cc13a1b939e4463d6cae2a603688e909d6fc1b Mon Sep 17 00:00:00 2001 From: dsoares Date: Tue, 26 Mar 2019 15:10:43 +0000 Subject: [PATCH 02/45] Fix bug where HTML messages with a xml:namespace tag were not rendered. --- program/lib/Roundcube/rcube_washtml.php | 3 +++ tests/Framework/Washtml.php | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/program/lib/Roundcube/rcube_washtml.php b/program/lib/Roundcube/rcube_washtml.php index 497a1c3e4..dfb57cac2 100644 --- a/program/lib/Roundcube/rcube_washtml.php +++ b/program/lib/Roundcube/rcube_washtml.php @@ -605,6 +605,8 @@ class rcube_washtml '/^(\0\0\xFE\xFF|\xFF\xFE\0\0|\xFE\xFF|\xFF\xFE|\xEF\xBB\xBF)/', // washtml/DOMDocument cannot handle xml namespaces '/]+>/i', + // washtml/DOMDocument cannot handle xml namespaces + '/<\?xml:namespace\s[^>]+>/i', ); $html_replace = array( @@ -613,6 +615,7 @@ class rcube_washtml '', '', '', + '', ); $html = preg_replace($html_search, $html_replace, $html); diff --git a/tests/Framework/Washtml.php b/tests/Framework/Washtml.php index eebd80de5..1dbb87a93 100644 --- a/tests/Framework/Washtml.php +++ b/tests/Framework/Washtml.php @@ -430,4 +430,18 @@ class Framework_Washtml extends PHPUnit_Framework_TestCase $this->assertContains('for="testmy-other-id"', $washed); $this->assertContains('class="testmy-class1 testmy-class2"', $washed); } + + /** + * Test removing xml:namespace tag + */ + function test_xml_namespace() + { + $html = '

'; + + $washer = new rcube_washtml; + $washed = $this->cleanupResult($washer->wash($html)); + + $this->assertNotContains('<?xml:namespace"', $washed); + $this->assertSame($washed, '

'); + } } From 347b92f8cf207353251233a99202d74d56d2d8b8 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sat, 30 Mar 2019 13:51:07 +0100 Subject: [PATCH 03/45] Update tinymce languages url --- jsdeps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsdeps.json b/jsdeps.json index 906bf872e..04064b44c 100644 --- a/jsdeps.json +++ b/jsdeps.json @@ -57,7 +57,7 @@ { "lib": "tinymce-langs", "version": "4.8.2", - "url": "https://tinymce-services.azurewebsites.net/1/i18n/download?langs=ar,hy,az,eu,be,bs,bg_BG,ca,zh_CN,zh_TW,hr,cs,cs_CZ,da,nl,en_CA,en_GB,eo,et,fo,fi,fr_FR,fr_CH,gd,gl,ka_GE,de,de_AT,el,he_IL,hi_IN,hu_HU,is_IS,id,ga,it,ja,kab,km_KH,ko_KR,ku,ku_IQ,lv,lt,lb,mk_MK,ml_IN,nb_NO,oc,fa,fa_IR,pl,pt_BR,pt_PT,ro,ru,sk,sl_SI,es,es_MX,sv_SE,tg,ta,ta_IN,tt,th_TH,tr,tr_TR,ug,uk,uk_UA,vi,vi_VN,cy&extension=.zip", + "url": "https://www.tiny.cloud/docs-4x/language/tinymce4x_languages.zip", "dest": "program/js/tinymce" }, { From a35699637d60cb873825a0063e23efdaa96c40f1 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 2 Apr 2019 12:35:25 +0200 Subject: [PATCH 04/45] Fix PHP error when using Net_LDAP3 from master get_entry() method signature has changed. We don't really needed that override in rcube_ldap_generic, so it's now removed. --- program/lib/Roundcube/rcube_ldap.php | 15 +++++++++++---- program/lib/Roundcube/rcube_ldap_generic.php | 13 ------------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/program/lib/Roundcube/rcube_ldap.php b/program/lib/Roundcube/rcube_ldap.php index 24ec5b992..defb92d36 100644 --- a/program/lib/Roundcube/rcube_ldap.php +++ b/program/lib/Roundcube/rcube_ldap.php @@ -1017,7 +1017,7 @@ class rcube_ldap extends rcube_addressbook if ($this->ready && $dn) { $dn = self::dn_decode($dn); - if ($rec = $this->ldap->get_entry($dn)) { + if ($rec = $this->ldap->get_entry($dn, $this->prop['attributes'])) { $rec = array_change_key_case($rec, CASE_LOWER); } @@ -1538,8 +1538,15 @@ class rcube_ldap extends rcube_addressbook foreach ($fieldmap as $rf => $lf) { - for ($i=0; $i < $rec[$lf]['count']; $i++) { - if (!($value = $rec[$lf][$i])) + // we might be dealing with normalized and non-normalized data + $entry = $rec[$lf]; + if (!is_array($entry) || !isset($entry['count'])) { + $entry = (array) $entry; + $entry['count'] = count($entry); + } + + for ($i=0; $i < $entry['count']; $i++) { + if (!($value = $entry[$i])) continue; list($col, $subtype) = explode(':', $rf); @@ -1551,7 +1558,7 @@ class rcube_ldap extends rcube_addressbook $out['address' . ($subtype ? ':' : '') . $subtype][$i][$col] = $value; else if ($col == 'address' && strpos($value, '$') !== false) // address data is represented as string separated with $ list($out[$rf][$i]['street'], $out[$rf][$i]['locality'], $out[$rf][$i]['zipcode'], $out[$rf][$i]['country']) = explode('$', $value); - else if ($rec[$lf]['count'] > 1) + else if ($entry['count'] > 1) $out[$rf][] = $value; else $out[$rf] = $value; diff --git a/program/lib/Roundcube/rcube_ldap_generic.php b/program/lib/Roundcube/rcube_ldap_generic.php index a2befbea7..ab7b6784a 100644 --- a/program/lib/Roundcube/rcube_ldap_generic.php +++ b/program/lib/Roundcube/rcube_ldap_generic.php @@ -54,19 +54,6 @@ class rcube_ldap_generic extends Net_LDAP3 return parent::connect($host); } - /** - * Get a specific LDAP entry, identified by its DN - * - * @param string $dn Record identifier - * @param array $attributes Attributes to return - * - * @return array Hash array - */ - function get_entry($dn, $attributes = array()) - { - return parent::get_entry($dn, !empty($attributes) ? $attributes : $this->attributes); - } - /** * Prints debug/error info to the log */ From 4d1b3e263aba3fc7adae877309e9e929de363f2f Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 2 Apr 2019 15:58:31 +0200 Subject: [PATCH 05/45] Elastic: Fix folders list scrolling on touch devices (#6706) --- CHANGELOG | 1 + skins/elastic/ui.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 02df4c5ad..ee7a9b95f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,7 @@ CHANGELOG Roundcube Webmail - Elastic: Changed "Move to..." icon (#6637) - Elastic: Add hide/show for advanced preferences (#6632) - Elastic: Fix bug where toolbar disappears on attachment menu use in Chrome (#6677) +- Elastic: Fix folders list scrolling on touch devices (#6706) - Fix TinyMCE download location (#6694) - Fix so "Open in new window" consistently displays "external window" interface (#6659) - Fix bug where next row wasn't selected after deleting a collapsed thread (#6655) diff --git a/skins/elastic/ui.js b/skins/elastic/ui.js index f7cc6a690..4658b2087 100644 --- a/skins/elastic/ui.js +++ b/skins/elastic/ui.js @@ -499,7 +499,7 @@ function rcube_elastic_ui() function init() { // Additional functionality on list widgets - $('table[data-list]').each(function() { + $('[data-list]').filter('ul,table').each(function() { var button, table = $(this), list = table.data('list'); From ae59269f274ff36639ed8a74c020f74dfc4a2489 Mon Sep 17 00:00:00 2001 From: Laurent Declercq Date: Thu, 4 Apr 2019 12:43:54 +0200 Subject: [PATCH 06/45] Make use of rcube::raise_error() function for error handling in bin/install-jsdeps.sh (#6704) --- CHANGELOG | 1 + bin/install-jsdeps.sh | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ee7a9b95f..56e7439a9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,7 @@ CHANGELOG Roundcube Webmail - Fix bug where next row wasn't selected after deleting a collapsed thread (#6655) - Fix bug where external content (e.g. mail body) was passed to templates parsing code (#6640) - Fix bug where attachment preview didn't work with x_frame_options=deny (#6688) +- Make use of rcube::raise_error() function for error handling in bin/install-jsdeps.sh (#6704) RELEASE 1.4-rc1 --------------- diff --git a/bin/install-jsdeps.sh b/bin/install-jsdeps.sh index 727de7b56..ececc7c27 100755 --- a/bin/install-jsdeps.sh +++ b/bin/install-jsdeps.sh @@ -13,7 +13,7 @@ | | | PURPOSE: | | Utility script to fetch and install all 3rd party javascript | - | libraries unsed in Roundcube from source. | + | libraries used in Roundcube from source. | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | +-----------------------------------------------------------------------+ @@ -24,13 +24,13 @@ define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' ); require_once INSTALL_PATH . 'program/include/clisetup.php'; if (!function_exists('exec')) { - die("PHP exec() function is required. Check disable_functions in php.ini\n"); + rcube::raise_error('PHP exec() function is required. Check disable_functions in php.ini.', false, true); } $SOURCES = json_decode(file_get_contents(INSTALL_PATH . 'jsdeps.json'), true); if (empty($SOURCES['dependencies'])) { - die("ERROR: Failed to read sources from " . INSTALL_PATH . "jsdeps.json\n"); + rcube::raise_error("ERROR: Failed to read sources from " . INSTALL_PATH . 'jsdeps.json', false, true); } $CURL = trim(`which curl`); @@ -116,7 +116,7 @@ function fetch_from_source($package, $useCache = true, &$filetype = null) if (!is_readable($cache_file) || !$useCache) { if (empty($CURL) && empty($WGET)) { - die("ERROR: Required program 'wget' or 'curl' not found\n"); + rcube::raise_error("Required program 'wget' or 'curl' not found.", false, true); } $url = str_replace('$v', $package['version'], $package['url']); @@ -133,7 +133,7 @@ function fetch_from_source($package, $useCache = true, &$filetype = null) $url = str_replace('$v', $package['version'], $package['api_url']); $header = 'Accept:application/vnd.github.v3.raw'; - echo "Fetching failed. Using Github API on $url\n"; + rcube::raise_error("Fetching failed. Using Github API on $url"); if ($CURL) exec(sprintf('%s -L -H %s -s %s -o %s', $CURL, escapeshellarg($header), escapeshellarg($url), $cache_file), $out, $retval); @@ -142,7 +142,7 @@ function fetch_from_source($package, $useCache = true, &$filetype = null) } if ($retval !== 0) { - die("ERROR: Failed to download source file from " . $url . "\n"); + rcube::raise_error("Failed to download source file from $url", false, true); } } @@ -160,7 +160,7 @@ function extract_filetype($package, &$filetype = null) $cache_file = $CACHEDIR . '/' . $package['lib'] . '-' . $package['version'] . '.' . $filetype; if (empty($FILEINFO)) { - die("ERROR: Required program 'file' not found\n"); + rcube::raise_error("Required program 'file' not found.", false, true); } // detect downloaded/cached file type @@ -207,7 +207,7 @@ function compose_destfile($package, $srcfile) echo "Wrote file " . INSTALL_PATH . $package['dest'] . "\n"; } else { - die("ERROR: Failed to write destination file " . INSTALL_PATH . $package['dest'] . "\n"); + rcube::raise_error("Failed to write destination file " . INSTALL_PATH . $package['dest'], false, true); } } @@ -219,7 +219,7 @@ function extract_zipfile($package, $srcfile) global $UNZIP, $CACHEDIR; if (empty($UNZIP)) { - die("ERROR: Required program 'unzip' not found\n"); + rcube::raise_error("Required program 'unzip' not found.", false, true); } $destdir = INSTALL_PATH . $package['dest']; @@ -228,7 +228,7 @@ function extract_zipfile($package, $srcfile) } if (!is_writeable($destdir)) { - die("ERROR: Cannot write to destination directory $destdir\n"); + rcube::raise_error("Cannot write to destination directory $destdir", false, true); } // pick files from zip archive @@ -237,7 +237,7 @@ function extract_zipfile($package, $srcfile) echo "Extracting files $pattern into $destdir\n"; exec(sprintf('%s -o %s %s -d %s', $UNZIP, escapeshellarg($srcfile), escapeshellarg($pattern), $destdir), $out, $retval); if ($retval !== 0) { - echo "ERROR: Failed to unpack $pattern; " . join('; ' . $out) . "\n"; + rcube::raise_error("Failed to unpack $pattern; " . join('; ' . $out)); } } } @@ -273,7 +273,7 @@ function extract_zipfile($package, $srcfile) exec(sprintf('mv -f %s/%s %s/%s', $sourcedir, $src, $destdir, $dest), $out, $retval); if ($retval !== 0) { - echo "ERROR: Failed to move $src into $destdir/$dest; " . join('; ' . $out) . "\n"; + rcube::raise_error("Failed to move $src into $destdir/$dest; " . join('; ' . $out)); } } @@ -285,7 +285,7 @@ function extract_zipfile($package, $srcfile) echo "Extracting zip archive into $destdir\n"; exec(sprintf('%s -o %s -d %s', $UNZIP, escapeshellarg($srcfile), $destdir), $out, $retval); if ($retval !== 0) { - echo "ERROR: Failed to unzip $srcfile; " . join('; ' . $out) . "\n"; + rcube::raise_error("Failed to unzip $srcfile; " . join('; ' . $out)); } } @@ -357,7 +357,7 @@ foreach ($SOURCES['dependencies'] as $package) { } if (!empty($package['sha1']) && ($sum = sha1_file($srcfile)) !== $package['sha1']) { - die("ERROR: Incorrect sha1 sum of $srcfile. Expected: {$package['sha1']}, got: $sum\n"); + rcube::raise_error("Incorrect sha1 sum of $srcfile. Expected: {$package['sha1']}, got: $sum", false, true); } if ($args['extract']) { From f045812fcc6ba80868e8379b1dbe6e2a97c22291 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sun, 7 Apr 2019 08:04:49 +0200 Subject: [PATCH 07/45] Bump masterminds/html5 version up --- composer.json-dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json-dist b/composer.json-dist index 7fe7a2e0d..d0e9c8579 100644 --- a/composer.json-dist +++ b/composer.json-dist @@ -18,7 +18,7 @@ "pear/crypt_gpg": "~1.6.3", "pear/net_sieve": "~1.4.3", "roundcube/plugin-installer": "~0.1.6", - "masterminds/html5": "~2.3.0", + "masterminds/html5": "~2.5.0", "endroid/qr-code": "~1.6.5" }, "require-dev": { From 2f05533710976ca8f2077b4bece24d68671c4508 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sun, 7 Apr 2019 08:17:52 +0200 Subject: [PATCH 08/45] Small code improvements --- CHANGELOG | 2 +- bin/install-jsdeps.sh | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 56e7439a9..c6dac6cc7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,7 +14,7 @@ CHANGELOG Roundcube Webmail - Fix bug where next row wasn't selected after deleting a collapsed thread (#6655) - Fix bug where external content (e.g. mail body) was passed to templates parsing code (#6640) - Fix bug where attachment preview didn't work with x_frame_options=deny (#6688) -- Make use of rcube::raise_error() function for error handling in bin/install-jsdeps.sh (#6704) +- Fix so bin/install-jsdeps.sh returns error code on error (#6704) RELEASE 1.4-rc1 --------------- diff --git a/bin/install-jsdeps.sh b/bin/install-jsdeps.sh index ececc7c27..baac19f60 100755 --- a/bin/install-jsdeps.sh +++ b/bin/install-jsdeps.sh @@ -24,13 +24,14 @@ define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' ); require_once INSTALL_PATH . 'program/include/clisetup.php'; if (!function_exists('exec')) { - rcube::raise_error('PHP exec() function is required. Check disable_functions in php.ini.', false, true); + rcube::raise_error("PHP exec() function is required. Check disable_functions in php.ini.", false, true); } -$SOURCES = json_decode(file_get_contents(INSTALL_PATH . 'jsdeps.json'), true); +$cfgfile = INSTALL_PATH . 'jsdeps.json'; +$SOURCES = json_decode(file_get_contents($cfgfile), true); if (empty($SOURCES['dependencies'])) { - rcube::raise_error("ERROR: Failed to read sources from " . INSTALL_PATH . 'jsdeps.json', false, true); + rcube::raise_error("ERROR: Failed to read dependencies list from $cfgfile", false, true); } $CURL = trim(`which curl`); @@ -116,7 +117,7 @@ function fetch_from_source($package, $useCache = true, &$filetype = null) if (!is_readable($cache_file) || !$useCache) { if (empty($CURL) && empty($WGET)) { - rcube::raise_error("Required program 'wget' or 'curl' not found.", false, true); + rcube::raise_error("Required 'wget' or 'curl' program not found.", false, true); } $url = str_replace('$v', $package['version'], $package['url']); @@ -219,7 +220,7 @@ function extract_zipfile($package, $srcfile) global $UNZIP, $CACHEDIR; if (empty($UNZIP)) { - rcube::raise_error("Required program 'unzip' not found.", false, true); + rcube::raise_error("Required 'unzip' program not found.", false, true); } $destdir = INSTALL_PATH . $package['dest']; @@ -228,7 +229,7 @@ function extract_zipfile($package, $srcfile) } if (!is_writeable($destdir)) { - rcube::raise_error("Cannot write to destination directory $destdir", false, true); + rcube::raise_error("Cannot write to destination directory: $destdir", false, true); } // pick files from zip archive From a07c44804a20d0e8d033030d548dc0a79d1fa189 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sun, 7 Apr 2019 08:22:01 +0200 Subject: [PATCH 09/45] Update changelog --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index c6dac6cc7..cd6db45e7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,7 @@ CHANGELOG Roundcube Webmail - Elastic: Add hide/show for advanced preferences (#6632) - Elastic: Fix bug where toolbar disappears on attachment menu use in Chrome (#6677) - Elastic: Fix folders list scrolling on touch devices (#6706) +- Fix bug where HTML messages with a xml:namespace tag were not rendered (#6697) - Fix TinyMCE download location (#6694) - Fix so "Open in new window" consistently displays "external window" interface (#6659) - Fix bug where next row wasn't selected after deleting a collapsed thread (#6655) From 23978006da7c3254a02bd63397ccfe16125ee822 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sun, 7 Apr 2019 08:35:01 +0200 Subject: [PATCH 10/45] Add note about IIS and woff fonts (#6710) --- INSTALL | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/INSTALL b/INSTALL index 57551b264..29d37d2b0 100644 --- a/INSTALL +++ b/INSTALL @@ -296,3 +296,9 @@ SELINUX. Here's some sample commands for SELINUX: $ semanage fcontext -a -t httpd_sys_rw_content_t "/path_to_roundcube/logs(/.*)?" $ semanage fcontext -a -t httpd_sys_rw_content_t "/path_to_roundcube/temp(/.*)?" $ restorecon -Rv /path_to_roundcube/ + +Microsoft IIS Server by default does not support WOFF fonts used in Elastic skin. It might be +needed to add following MIME Types definitions (via web.config or IIS Manager): + + .woff application/font-woff + .woff2 application/font-woff2 From b8f27af8cb5b07e5f187e21aef011c36547d818e Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sun, 7 Apr 2019 11:55:39 +0200 Subject: [PATCH 11/45] Elastic: Fix non-working pretty selects in Chrome browser (#6705) --- CHANGELOG | 1 + skins/elastic/ui.js | 23 +++++++++++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index cd6db45e7..72ef3208e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,7 @@ CHANGELOG Roundcube Webmail - Elastic: Add hide/show for advanced preferences (#6632) - Elastic: Fix bug where toolbar disappears on attachment menu use in Chrome (#6677) - Elastic: Fix folders list scrolling on touch devices (#6706) +- Elastic: Fix non-working pretty selects in Chrome browser (#6705) - Fix bug where HTML messages with a xml:namespace tag were not rendered (#6697) - Fix TinyMCE download location (#6694) - Fix so "Open in new window" consistently displays "external window" interface (#6659) diff --git a/skins/elastic/ui.js b/skins/elastic/ui.js index 4658b2087..23da95fa4 100644 --- a/skins/elastic/ui.js +++ b/skins/elastic/ui.js @@ -19,6 +19,7 @@ function rcube_elastic_ui() mode = 'normal', // one of: large, normal, small, phone touch = false, ios = false, + popups_close_lock, is_framed = rcmail.is_framed(), env = { config: { @@ -2384,6 +2385,11 @@ function rcube_elastic_ui() */ function popups_close(e) { + // Ignore some of propagated click events (see pretty_select()) + if (popups_close_lock && popups_close_lock > (new Date().getTime() - 250)) { + return; + } + $('.popover.show').each(function() { var popup = $('.popover-body', this), button = popup.children().first().data('button'); @@ -3424,6 +3430,9 @@ function rcube_elastic_ui() max_height *= 0.5; } + // close other popups + popups_close(e); + $('option', select).each(function() { var label = $(this).text(), link = $('') @@ -3442,6 +3451,7 @@ function rcube_elastic_ui() var list = $('