[FIX] web: DropdownMenu autoclose behavior should match Bootstrap
Before this commit, with an opened DropdownMenu component, when the user clicks on a Bootstrap's dropdown the DropdownMenu doesn't close. This issue is due to a conflict between the global click listener registered to close the DropdownMenu and the listener registered by the Bootstrap dropdown: the last one prevents the event from bubbling up to the `window` element and be handled by the first one. This commit fixes it by enabling the `capture` flag on the DropdownMenu global click listener, giving it the opportunity to handling it properly and close the DropdownMenu. Note: this commit also fixes an issue when a dialog is opened from a DropdownMenu (like the favorite's delete action) and prevents it from closing in the background (e.g. when the dialog is still opened). opw-1879566 closes odoo/odoo#60928 X-original-commit: 7f1bcc8ceb78729725f65585e923b08f94bf75b5 Signed-off-by: Pierre Paridans <pparidans@users.noreply.github.com>
This commit is contained in:
@@ -35,7 +35,7 @@ odoo.define('web.DropdownMenu', function (require) {
|
||||
this.dropdownMenu = useRef('dropdown');
|
||||
this.state = useState({ open: false });
|
||||
|
||||
useExternalListener(window, 'click', this._onWindowClick);
|
||||
useExternalListener(window, 'click', this._onWindowClick, true);
|
||||
useExternalListener(window, 'keydown', this._onWindowKeydown);
|
||||
}
|
||||
|
||||
@@ -147,6 +147,13 @@ odoo.define('web.DropdownMenu', function (require) {
|
||||
!this.el.contains(ev.target) &&
|
||||
!this.el.contains(document.activeElement)
|
||||
) {
|
||||
if (document.body.classList.contains("modal-open")) {
|
||||
// retrieve the active modal and check if the dropdown is a child of this modal
|
||||
const modal = document.querySelector('.modal:not(.o_inactive_modal)');
|
||||
if (!modal.contains(this.el)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.state.open = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,62 @@ odoo.define('web.dropdown_menu_tests', function (require) {
|
||||
dropdown.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('only one dropdown rendering at same time (owl vs bootstrap dropdown)', async function (assert) {
|
||||
assert.expect(12);
|
||||
|
||||
const bsDropdown = document.createElement('div');
|
||||
bsDropdown.innerHTML = `<div class="dropdown">
|
||||
<button class="btn dropdown-toggle" type="button"
|
||||
data-toggle="dropdown" aria-expanded="false">
|
||||
BS Dropdown button
|
||||
</button>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" href="#">BS Action</a>
|
||||
</div>
|
||||
</div>`;
|
||||
document.body.append(bsDropdown);
|
||||
|
||||
const dropdown = await createComponent(DropdownMenu, {
|
||||
props: {
|
||||
items: this.items,
|
||||
title: "Dropdown",
|
||||
},
|
||||
});
|
||||
|
||||
await testUtils.dom.click(dropdown.el.querySelector('button'));
|
||||
|
||||
assert.hasClass(dropdown.el.querySelector('.dropdown-menu'), 'show');
|
||||
assert.doesNotHaveClass(bsDropdown.querySelector('.dropdown-menu'), 'show');
|
||||
|
||||
assert.isVisible(dropdown.el.querySelector('.dropdown-menu'),
|
||||
"owl dropdown menu should be visible");
|
||||
assert.isNotVisible(bsDropdown.querySelector('.dropdown-menu'),
|
||||
"bs dropdown menu should not be visible");
|
||||
|
||||
await testUtils.dom.click(bsDropdown.querySelector('.btn.dropdown-toggle'));
|
||||
|
||||
assert.doesNotHaveClass(dropdown.el, 'show');
|
||||
assert.containsNone(dropdown.el, '.dropdown-menu',
|
||||
"owl dropdown menu should not be set inside the dom");
|
||||
|
||||
assert.hasClass(bsDropdown.querySelector('.dropdown-menu'), 'show');
|
||||
assert.isVisible(bsDropdown.querySelector('.dropdown-menu'),
|
||||
"bs dropdown menu should be visible");
|
||||
|
||||
await testUtils.dom.click(document.body);
|
||||
|
||||
assert.doesNotHaveClass(dropdown.el, 'show');
|
||||
assert.containsNone(dropdown.el, '.dropdown-menu',
|
||||
"owl dropdown menu should not be set inside the dom");
|
||||
|
||||
assert.doesNotHaveClass(bsDropdown.querySelector('.dropdown-menu'), 'show');
|
||||
assert.isNotVisible(bsDropdown.querySelector('.dropdown-menu'),
|
||||
"bs dropdown menu should not be visible");
|
||||
|
||||
bsDropdown.remove();
|
||||
dropdown.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('click on an item without options should toggle it', async function (assert) {
|
||||
assert.expect(7);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user