[FIX] web: prevent command palette to lose focus

The command palette has the priority when useAutoFocus is call.
Like that, the command palette will not lose focus when clicking
on an app on the home menu and then directly opening the command
palette before the app mounting

TASK ID: 3338117

closes odoo/odoo#139124

X-original-commit: 660d27ac38c225559ea3697a24a34ac70ede8ec1
Signed-off-by: Florent Dardenne (dafl) <dafl@odoo.com>
This commit is contained in:
Bastien PIERRE
2023-10-19 02:28:10 +00:00
parent bb1ea07920
commit 38260f3262
2 changed files with 46 additions and 2 deletions
+4 -2
View File
@@ -29,7 +29,7 @@ import { status, useComponent, useEffect, useRef, onWillUnmount } from "@odoo/ow
// -----------------------------------------------------------------------------
/**
* Focus an element referenced by a t-ref="autofocus" in the current component
* Focus an element referenced by a t-ref="autofocus" in the active component
* as soon as it appears in the DOM and if it was not displayed before.
* If it is an input/textarea, set the selection at the end.
* @param {Object} [params]
@@ -41,6 +41,8 @@ import { status, useComponent, useEffect, useRef, onWillUnmount } from "@odoo/ow
export function useAutofocus({ refName, selectAll, mobile } = {}) {
const comp = useComponent();
const ref = useRef(refName || "autofocus");
const uiService = useService("ui");
// Prevent autofocus in mobile
if (!mobile && comp.env.isSmall) {
return ref;
@@ -52,7 +54,7 @@ export function useAutofocus({ refName, selectAll, mobile } = {}) {
// LEGACY
useEffect(
(el) => {
if (el) {
if (el && (!uiService.activeElement || uiService.activeElement.contains(el))) {
el.focus();
if (["INPUT", "TEXTAREA"].includes(el.tagName) && el.type !== "number") {
el.selectionEnd = el.value.length;
@@ -14,6 +14,9 @@ import { makeTestEnv } from "@web/../tests/helpers/mock_env";
import { destroy, getFixture, makeDeferred, mount, nextTick } from "@web/../tests/helpers/utils";
import { Component, onMounted, useState, xml } from "@odoo/owl";
import { dialogService } from "@web/core/dialog/dialog_service";
import { hotkeyService } from "@web/core/hotkeys/hotkey_service";
import { CommandPalette } from "@web/core/commands/command_palette";
const serviceRegistry = registry.category("services");
QUnit.module("utils", () => {
@@ -273,6 +276,45 @@ QUnit.module("utils", () => {
assert.strictEqual(comp.inputRef.el.selectionEnd, 10);
});
QUnit.test("useAutofocus: autofocus outside of active element doesn't work (CommandPalette)", async function (assert) {
class MyComponent extends Component {
setup() {
this.inputRef = useAutofocus();
}
get OverlayContainer() {
return registry.category("main_components").get("OverlayContainer");
}
}
MyComponent.template = xml`
<div>
<input type="text" t-ref="autofocus" />
<div class="o_dialog_container"/>
<t t-component="OverlayContainer.Component" t-props="OverlayContainer.props" />
</div>
`;
registry.category("services").add("ui", uiService);
registry.category("services").add("dialog", dialogService);
registry.category("services").add("hotkey", hotkeyService);
const config = { providers: [] };
const env = await makeTestEnv();
const target = getFixture();
const comp = await mount(MyComponent, target , { env });
await nextTick();
assert.strictEqual(document.activeElement, comp.inputRef.el);
env.services.dialog.add(CommandPalette, { config });
await nextTick();
assert.containsOnce(target, ".o_command_palette");
assert.notStrictEqual(document.activeElement, comp.inputRef.el);
comp.render();
await nextTick();
assert.notStrictEqual(document.activeElement, comp.inputRef.el);
});
QUnit.module("useBus");
QUnit.test("useBus hook: simple usecase", async function (assert) {