[FIX] web: fix traceback when shift-tab on list field
**Before** A traceback is raised when pressing shift-tab on the first column of the first row in a focused list field as shown in the vid: https://youtu.be/g97ZTp1QdBE **After** shift-tab on the first column of first row will now unselect the list field and immediately focuses on the previous field. **Additional change** We now allow skipping focus on the dropdown toggler by introducing new props. closes odoo/odoo#103485 X-original-commit: 9ba9977e42d201035b5299bc13ba03211cddbc1f Signed-off-by: Bruno Boi (boi) <boi@odoo.com> Signed-off-by: Joseph Caburnay (jcb) <jcb@odoo.com> Co-authored-by: Bruno Boi <boi@odoo.com>
This commit is contained in:
co-authored by
Bruno Boi
parent
8a2a171aa4
commit
390955b751
@@ -305,6 +305,10 @@ Dropdown.props = {
|
||||
optional: true,
|
||||
validate: (prop) => ["parent"].includes(prop),
|
||||
},
|
||||
skipTogglerTabbing: {
|
||||
type: Boolean,
|
||||
optional: true,
|
||||
},
|
||||
startOpen: {
|
||||
type: Boolean,
|
||||
optional: true,
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
t-att-title="props.title"
|
||||
t-att-data-hotkey="props.hotkey"
|
||||
t-att-data-tooltip="props.tooltip"
|
||||
t-att-tabindex="props.skipTogglerTabbing ? -1 : 0"
|
||||
t-ref="togglerRef"
|
||||
>
|
||||
<t t-slot="toggler" />
|
||||
|
||||
@@ -1256,6 +1256,7 @@ export class ListRenderer extends Component {
|
||||
futureRecord.switchMode("edit");
|
||||
}
|
||||
} else {
|
||||
list.unselectRecord(true);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
<Dropdown t-if="displayOptionalFields"
|
||||
class="'o_optional_columns_dropdown text-center border-top-0'"
|
||||
togglerClass="'btn p-0'"
|
||||
skipTogglerTabbing="true"
|
||||
position="'bottom-end'">
|
||||
<t t-set-slot="toggler">
|
||||
<i class="o_optional_columns_dropdown_toggle oi oi-fw oi-settings-adjust"/>
|
||||
|
||||
@@ -50,7 +50,7 @@ QUnit.module("Components", ({ beforeEach }) => {
|
||||
await mount(Parent, target, { env });
|
||||
assert.strictEqual(
|
||||
target.querySelector(".dropdown").outerHTML,
|
||||
'<div class="o-dropdown dropdown o-dropdown--no-caret"><button class="dropdown-toggle"></button></div>'
|
||||
'<div class="o-dropdown dropdown o-dropdown--no-caret"><button class="dropdown-toggle" tabindex="0"></button></div>'
|
||||
);
|
||||
assert.containsOnce(target, "button.dropdown-toggle");
|
||||
assert.containsNone(target, ".dropdown-menu");
|
||||
|
||||
@@ -489,6 +489,7 @@ export function editSelect(el, selector, value) {
|
||||
* @param {string} hotkey
|
||||
* @param {boolean} addOverlayModParts
|
||||
* @param {KeyboardEventInit} eventAttrs
|
||||
* @returns {{ keydownEvent: KeyboardEvent, keyupEvent: KeyboardEvent }}
|
||||
*/
|
||||
export function triggerHotkey(hotkey, addOverlayModParts = false, eventAttrs = {}) {
|
||||
eventAttrs.key = hotkey.split("+").pop();
|
||||
@@ -517,8 +518,11 @@ export function triggerHotkey(hotkey, addOverlayModParts = false, eventAttrs = {
|
||||
eventAttrs.bubbles = true;
|
||||
}
|
||||
|
||||
document.activeElement.dispatchEvent(new KeyboardEvent("keydown", eventAttrs));
|
||||
document.activeElement.dispatchEvent(new KeyboardEvent("keyup", eventAttrs));
|
||||
const keydownEvent = new KeyboardEvent("keydown", eventAttrs);
|
||||
const keyupEvent = new KeyboardEvent("keyup", eventAttrs);
|
||||
document.activeElement.dispatchEvent(keydownEvent);
|
||||
document.activeElement.dispatchEvent(keyupEvent);
|
||||
return { keydownEvent, keyupEvent };
|
||||
}
|
||||
|
||||
export async function legacyExtraNextTick() {
|
||||
|
||||
@@ -6730,6 +6730,68 @@ QUnit.module("Fields", (hooks) => {
|
||||
await clickSave(target);
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"one2many list editable - should properly unselect the list field after shift+tab",
|
||||
async function (assert) {
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
serverData,
|
||||
arch: /* xml */ `
|
||||
<form>
|
||||
<group>
|
||||
<field name="display_name"/>
|
||||
<field name="turtles">
|
||||
<tree editable="bottom">
|
||||
<field name="turtle_foo"/>
|
||||
<field name="turtle_bar" optional="hide"/>
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
</form>`,
|
||||
resId: 1,
|
||||
});
|
||||
|
||||
await click(target, ".o_data_row td:first-child");
|
||||
assert.containsOnce(target, ".o_selected_row", "should have selected row");
|
||||
const { keydownEvent } = triggerHotkey("Shift+Tab");
|
||||
await nextTick();
|
||||
assert.containsNone(target, ".o_selected_row", "list should not be in edition");
|
||||
// We also check the event is not default prevented, to make sure that the
|
||||
// event flows and selection goes to the previous field.
|
||||
assert.ok(!keydownEvent.defaultPrevented);
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test(
|
||||
"one2many list editable - should not allow tab navigation focus on the optional field toggler",
|
||||
async function (assert) {
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
serverData,
|
||||
arch: /* xml */ `
|
||||
<form>
|
||||
<group>
|
||||
<field name="display_name"/>
|
||||
<field name="turtles">
|
||||
<tree editable="bottom">
|
||||
<field name="turtle_foo"/>
|
||||
<field name="turtle_bar" optional="hide"/>
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
</form>`,
|
||||
resId: 1,
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
target.querySelector(".o_optional_columns_dropdown .dropdown-toggle").tabIndex,
|
||||
-1
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test('one2many list edition, no "Remove" button in modal', async function (assert) {
|
||||
serverData.models.partner.fields.foo.default = false;
|
||||
|
||||
|
||||
@@ -6701,7 +6701,7 @@ QUnit.module("Views", (hooks) => {
|
||||
|
||||
await toggleColumnActions(0);
|
||||
|
||||
assert.containsNone(target, '[tabindex]:not([tabindex="-1"])');
|
||||
assert.containsN(target, ".o_kanban_record", 16);
|
||||
assert.hasClass(document.activeElement, "o_searchview_input");
|
||||
|
||||
await triggerEvent(document.activeElement, null, "keydown", { key: "ArrowDown" });
|
||||
|
||||
Reference in New Issue
Block a user