[FIX] web: correctly restore focus with ConfirmationDialog

When a dialog is closed, the focus is meant to be restored to the
previous focused element.

Before this commit, it did not work for the ConfirmationDialog when the
confirm button was clicked. This was because the focus was lost **before**
the dialog was closed (because the confirm button is disabled when
clicked), and thus the previous focused element was not in the el of the
dialog anymore, and thus the focus was not restored.

closes odoo/odoo#134456

Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
Pierre Rousseau
2023-09-06 13:25:37 +00:00
parent b0bc3d0814
commit d946affe22
2 changed files with 60 additions and 2 deletions
+13 -1
View File
@@ -77,7 +77,19 @@ export function useActiveElement(refName) {
return () => {
uiService.deactivateElement(el);
el.removeEventListener("keydown", trapFocus);
if (el.contains(document.activeElement)) {
/**
* In some cases, the current active element is not
* anymore in el (e.g. with ConfirmationDialog, the
* confirm button is disabled when clicked, so the
* focus is lost). In that case, we also want to restore
* the focus to the previous active element so we
* check if the current active element is the body
*/
if (
el.contains(document.activeElement) ||
document.activeElement === document.body
) {
oldActiveElement.focus();
}
};
@@ -5,8 +5,17 @@ import { uiService } from "@web/core/ui/ui_service";
import { hotkeyService } from "@web/core/hotkeys/hotkey_service";
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
import { makeDialogTestEnv } from "../helpers/mock_env";
import { click, getFixture, makeDeferred, mount, nextTick, triggerHotkey } from "../helpers/utils";
import {
click,
destroy,
getFixture,
makeDeferred,
mount,
nextTick,
triggerHotkey,
} from "../helpers/utils";
import { makeFakeDialogService } from "../helpers/mock_services";
import { Component, xml } from "@odoo/owl";
const serviceRegistry = registry.category("services");
let target;
@@ -193,4 +202,41 @@ QUnit.module("Components", (hooks) => {
await nextTick();
assert.verifySteps(["close"]);
});
QUnit.test("Focus is correctly restored after confirmation", async function (assert) {
const env = await makeDialogTestEnv();
class MyComp extends Component {}
MyComp.template = xml`<div class="my-comp"><input type="text" class="my-input"/></div>`;
await mount(MyComp, target, { env });
target.querySelector(".my-input").focus();
assert.strictEqual(document.activeElement, target.querySelector(".my-input"));
const comp = await mount(ConfirmationDialog, target, {
env,
props: {
body: "Some content",
title: "Confirmation",
confirm: () => {},
close: () => {},
},
});
assert.strictEqual(
document.activeElement,
target.querySelector(".modal-footer .btn-primary")
);
await click(target, ".modal-footer .btn-primary");
assert.strictEqual(
document.activeElement,
document.body,
"As the button is disabled, the focus is now on the body"
);
destroy(comp);
assert.strictEqual(
document.activeElement,
target.querySelector(".my-input"),
"After destruction of the dialog, the focus is restored to the input"
);
});
});