diff --git a/addons/web/static/src/core/dropdown/dropdown.js b/addons/web/static/src/core/dropdown/dropdown.js index d2ef3a86d4c..753412d31e1 100644 --- a/addons/web/static/src/core/dropdown/dropdown.js +++ b/addons/web/static/src/core/dropdown/dropdown.js @@ -261,7 +261,11 @@ export class Dropdown extends Component { * @param {DropdownStateChangedPayload} args */ onDropdownStateChanged(args) { - if (!this.rootRef.el || this.rootRef.el.contains(args.emitter.rootRef.el)) { + if ( + !this.rootRef.el || + this.rootRef.el.contains(args.emitter.rootRef.el) || + args.emitter.myActiveEl !== this.myActiveEl + ) { // Do not listen to events emitted by self or children return; } diff --git a/addons/web/static/tests/core/dropdown_tests.js b/addons/web/static/tests/core/dropdown_tests.js index 64c7f0cd5b5..3769aec5f36 100644 --- a/addons/web/static/tests/core/dropdown_tests.js +++ b/addons/web/static/tests/core/dropdown_tests.js @@ -11,7 +11,7 @@ import { hotkeyService } from "@web/core/hotkeys/hotkey_service"; import { registry } from "@web/core/registry"; import { uiService } from "@web/core/ui/ui_service"; import { registerCleanup } from "../helpers/cleanup"; -import { makeTestEnv } from "../helpers/mock_env"; +import { clearRegistryWithCleanup, makeTestEnv } from "../helpers/mock_env"; import { makeFakeLocalizationService } from "../helpers/mock_services"; import { click, @@ -28,6 +28,8 @@ import { import { makeParent } from "./tooltip/tooltip_service_tests"; import { getPickerCell } from "./datetime/datetime_test_helpers"; import { datetimePickerService } from "@web/core/datetime/datetimepicker_service"; +import { Dialog } from "@web/core/dialog/dialog"; +import { dialogService } from "@web/core/dialog/dialog_service"; const serviceRegistry = registry.category("services"); @@ -1385,4 +1387,65 @@ QUnit.module("Components", ({ beforeEach }) => { ` My checkbox item ` ); }); + + QUnit.test("don't close dropdown outside the active element", async (assert) => { + // This test checks that if a dropdown element opens a dialog with a dropdown inside, + // opening this dropdown will not close the first dropdown. + class CustomDialog extends Component {} + CustomDialog.template = xml` + + + Item + +
Outside Dialog
+
`; + CustomDialog.components = { Dialog, Dropdown, DropdownItem }; + + const mainComponentRegistry = registry.category("main_components"); + clearRegistryWithCleanup(mainComponentRegistry); + serviceRegistry.add("dialog", dialogService); + serviceRegistry.add("l10n", makeFakeLocalizationService()); + + class PseudoWebClient extends Component { + setup() { + this.Components = mainComponentRegistry.getEntries(); + } + clicked() { + env.services.dialog.add(CustomDialog); + } + } + PseudoWebClient.template = xml` +
+
+ + + +
+
+ + + +
Outside Parent
+
+
+ `; + PseudoWebClient.components = { Dropdown }; + + env = await makeTestEnv(); + await mount(PseudoWebClient, target, { env }); + await click(target, "button.dropdown-toggle"); + assert.containsOnce(target, ".dropdown-menu"); + await click(target, "button.click-me"); + assert.containsOnce(target, ".modal-dialog"); + await click(target, ".modal-dialog button.dropdown-toggle"); + assert.containsN(target, ".dropdown-menu", 2); + await click(target, ".outside_dialog"); + assert.containsOnce(target, ".modal-dialog"); + assert.containsN(target, ".dropdown-menu", 1); + await click(target, ".modal-dialog .btn-primary"); + assert.containsNone(target, ".modal-dialog"); + assert.containsN(target, ".dropdown-menu", 1); + await click(target, ".outside_parent"); + assert.containsNone(target, ".dropdown-menu"); + }); });