[IMP] web: Add params to useAutofocus
This commit introduces an object parameter to the "useAutofocus" hook, that has 2 new optional keys: - "refName": to override the ref "autofocus" (effectively allows to run the hook multiple times) - "selectAll": selects the whole value of the input/textarea (instead of putting the cursor at the end). Part-of: odoo/odoo#97411
This commit is contained in:
@@ -27,11 +27,14 @@ const { status, useComponent, useEffect, useRef, onWillUnmount } = owl;
|
||||
* Focus an element referenced by a t-ref="autofocus" in the current 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]
|
||||
* @param {string} [params.refName] override the ref name "autofocus"
|
||||
* @param {boolean} [params.selectAll] if true, will select the entire text value.
|
||||
* @returns {Object} the element reference
|
||||
*/
|
||||
export function useAutofocus() {
|
||||
export function useAutofocus({ refName, selectAll } = {}) {
|
||||
const comp = useComponent();
|
||||
const ref = useRef("autofocus");
|
||||
const ref = useRef(refName || "autofocus");
|
||||
// Prevent autofocus in mobile
|
||||
if (comp.env.isSmall) {
|
||||
return ref;
|
||||
@@ -45,8 +48,9 @@ export function useAutofocus() {
|
||||
(el) => {
|
||||
if (el) {
|
||||
el.focus();
|
||||
if (["INPUT", "TEXTAREA"].includes(el.tagName) && el.type !== 'number') {
|
||||
el.selectionStart = el.selectionEnd = el.value.length;
|
||||
if (["INPUT", "TEXTAREA"].includes(el.tagName) && el.type !== "number") {
|
||||
el.selectionEnd = el.value.length;
|
||||
el.selectionStart = selectAll ? 0 : el.value.length;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
} from "@web/../tests/helpers/utils";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { Component, onMounted, xml } = owl;
|
||||
const { Component, onMounted, useState, xml } = owl;
|
||||
const serviceRegistry = registry.category("services");
|
||||
|
||||
QUnit.module("utils", () => {
|
||||
@@ -47,30 +47,33 @@ QUnit.module("utils", () => {
|
||||
assert.strictEqual(document.activeElement, comp.inputRef.el);
|
||||
});
|
||||
|
||||
QUnit.test("useAutofocus: simple usecase when input type is number", async function (assert) {
|
||||
class MyComponent extends Component {
|
||||
setup() {
|
||||
this.inputRef = useAutofocus();
|
||||
QUnit.test(
|
||||
"useAutofocus: simple usecase when input type is number",
|
||||
async function (assert) {
|
||||
class MyComponent extends Component {
|
||||
setup() {
|
||||
this.inputRef = useAutofocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
MyComponent.template = xml`
|
||||
MyComponent.template = xml`
|
||||
<span>
|
||||
<input type="number" t-ref="autofocus" />
|
||||
</span>
|
||||
`;
|
||||
|
||||
registry.category("services").add("ui", uiService);
|
||||
registry.category("services").add("ui", uiService);
|
||||
|
||||
const env = await makeTestEnv();
|
||||
const target = getFixture();
|
||||
const comp = await mount(MyComponent, target, { env });
|
||||
const env = await makeTestEnv();
|
||||
const target = getFixture();
|
||||
const comp = await mount(MyComponent, target, { env });
|
||||
|
||||
assert.strictEqual(document.activeElement, comp.inputRef.el);
|
||||
assert.strictEqual(document.activeElement, comp.inputRef.el);
|
||||
|
||||
comp.render();
|
||||
await nextTick();
|
||||
assert.strictEqual(document.activeElement, comp.inputRef.el);
|
||||
});
|
||||
comp.render();
|
||||
await nextTick();
|
||||
assert.strictEqual(document.activeElement, comp.inputRef.el);
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test("useAutofocus: conditional autofocus", async function (assert) {
|
||||
class MyComponent extends Component {
|
||||
@@ -124,7 +127,7 @@ QUnit.module("utils", () => {
|
||||
|
||||
const fakeUIService = {
|
||||
start(env) {
|
||||
let ui = {};
|
||||
const ui = {};
|
||||
Object.defineProperty(env, "isSmall", {
|
||||
get() {
|
||||
return true;
|
||||
@@ -142,6 +145,64 @@ QUnit.module("utils", () => {
|
||||
await mount(MyComponent, target, { env });
|
||||
});
|
||||
|
||||
QUnit.test("supports different ref names", async (assert) => {
|
||||
class MyComponent extends Component {
|
||||
setup() {
|
||||
this.secondRef = useAutofocus({ refName: "second" });
|
||||
this.firstRef = useAutofocus({ refName: "first" });
|
||||
|
||||
this.state = useState({ showSecond: true });
|
||||
}
|
||||
}
|
||||
MyComponent.template = xml`
|
||||
<span>
|
||||
<input type="text" t-ref="first" />
|
||||
<input t-if="state.showSecond" type="text" t-ref="second" />
|
||||
</span>
|
||||
`;
|
||||
|
||||
registry.category("services").add("ui", uiService);
|
||||
|
||||
const env = await makeTestEnv();
|
||||
const target = getFixture();
|
||||
const comp = await mount(MyComponent, target, { env });
|
||||
await nextTick();
|
||||
|
||||
// "first" is focused first since it has the last call to "useAutofocus"
|
||||
assert.strictEqual(document.activeElement, comp.firstRef.el);
|
||||
|
||||
comp.state.showSecond = false;
|
||||
await nextTick();
|
||||
comp.state.showSecond = true;
|
||||
await nextTick();
|
||||
|
||||
assert.strictEqual(document.activeElement, comp.secondRef.el);
|
||||
});
|
||||
|
||||
QUnit.test("can select an entire text", async (assert) => {
|
||||
class MyComponent extends Component {
|
||||
setup() {
|
||||
this.inputRef = useAutofocus({ selectAll: true });
|
||||
}
|
||||
}
|
||||
MyComponent.template = xml`
|
||||
<span>
|
||||
<input type="text" value="abcdefghij" t-ref="autofocus" />
|
||||
</span>
|
||||
`;
|
||||
|
||||
registry.category("services").add("ui", uiService);
|
||||
|
||||
const env = await makeTestEnv();
|
||||
const target = getFixture();
|
||||
const comp = await mount(MyComponent, target, { env });
|
||||
await nextTick();
|
||||
|
||||
assert.strictEqual(document.activeElement, comp.inputRef.el);
|
||||
assert.strictEqual(comp.inputRef.el.selectionStart, 0);
|
||||
assert.strictEqual(comp.inputRef.el.selectionEnd, 10);
|
||||
});
|
||||
|
||||
QUnit.module("useBus");
|
||||
|
||||
QUnit.test("useBus hook: simple usecase", async function (assert) {
|
||||
|
||||
Reference in New Issue
Block a user