[FIX] web: classes handling for x2many fields
Since c857473 the Kanban arch parser do not take into account the root node class attribute anymore. This lead to an issue regarding the x2many fields making use of kanban views. This commit brings the following changes: - the kanban and list arch parsers now share the class attribute in their arch infos. - the x2many field adds the className from arch infos to its root node. closes odoo/odoo#115534 X-original-commit: 980244fa8bf2b720527e457f22c4039c450eed5b Signed-off-by: Aaron Bohy (aab) <aab@odoo.com> Signed-off-by: Bruno Boi (boi) <boi@odoo.com>
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="web.X2ManyField" owl="1">
|
||||
<div t-attf-class="o_field_x2many o_field_x2many_{{props.viewMode}}">
|
||||
<div t-att-class="{ [archInfo.className]: archInfo.className }" t-attf-class="o_field_x2many o_field_x2many_{{props.viewMode}}">
|
||||
<div class="o_x2m_control_panel">
|
||||
<t t-if="displayControlPanelButtons">
|
||||
<div class="o_cp_buttons" role="toolbar" aria-label="Control panel buttons" t-ref="buttons">
|
||||
|
||||
@@ -33,6 +33,7 @@ export class KanbanArchParser extends XMLParser {
|
||||
parse(arch, models, modelName) {
|
||||
const fields = models[modelName];
|
||||
const xmlDoc = this.parseXML(arch);
|
||||
const className = xmlDoc.getAttribute("class") || null;
|
||||
let defaultOrder = stringToOrderBy(xmlDoc.getAttribute("default_order") || null);
|
||||
const defaultGroupBy = xmlDoc.getAttribute("default_group_by");
|
||||
const limit = xmlDoc.getAttribute("limit");
|
||||
@@ -177,6 +178,7 @@ export class KanbanArchParser extends XMLParser {
|
||||
arch,
|
||||
activeActions,
|
||||
activeFields,
|
||||
className,
|
||||
creates,
|
||||
defaultGroupBy,
|
||||
fieldNodes,
|
||||
|
||||
@@ -55,6 +55,7 @@ export class ListArchParser extends XMLParser {
|
||||
|
||||
parse(arch, models, modelName) {
|
||||
const xmlDoc = this.parseXML(arch);
|
||||
const className = xmlDoc.getAttribute("class") || null;
|
||||
const fieldNodes = {};
|
||||
const widgetNodes = {};
|
||||
let widgetNextId = 0;
|
||||
@@ -237,6 +238,7 @@ export class ListArchParser extends XMLParser {
|
||||
}
|
||||
|
||||
return {
|
||||
className,
|
||||
creates,
|
||||
handleField,
|
||||
headerButtons,
|
||||
|
||||
@@ -12601,7 +12601,7 @@ QUnit.module("Fields", (hooks) => {
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
serverData,
|
||||
arch: `
|
||||
arch: /* xml */ `
|
||||
<form>
|
||||
<field name="p">
|
||||
<tree>
|
||||
@@ -12609,7 +12609,7 @@ QUnit.module("Fields", (hooks) => {
|
||||
</tree>
|
||||
<form>
|
||||
<field name="p">
|
||||
<kanban>
|
||||
<kanban class="o-custom-class">
|
||||
<field name="display_name"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
@@ -12625,6 +12625,52 @@ QUnit.module("Fields", (hooks) => {
|
||||
});
|
||||
await click(target, ".o_data_row td[name=display_name]");
|
||||
assert.containsOnce(target, ".modal .o_kanban_record:not(.o_kanban_ghost)");
|
||||
assert.hasClass(target.querySelector(".modal .o_field_x2many_kanban"), "o-custom-class");
|
||||
|
||||
const record = target.querySelector(".modal .o_kanban_record:not(.o_kanban_ghost)");
|
||||
record.focus(); // shortcut for a true click
|
||||
assert.strictEqual(document.activeElement, record);
|
||||
|
||||
await triggerHotkey("ArrowUp");
|
||||
await nextTick();
|
||||
|
||||
assert.containsOnce(target, ".modal .o_kanban_record:not('.o_kanban_ghost')");
|
||||
});
|
||||
|
||||
QUnit.test("kanban one2many in opened view form (with _view_ref)", async (assert) => {
|
||||
serverData.views = {
|
||||
"partner,1234,kanban": /* xml */ `
|
||||
<kanban class="o-custom-class">
|
||||
<field name="display_name"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div><t t-esc="record.display_name.value"/></div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
`,
|
||||
};
|
||||
serverData.models.partner.records[0].p = [1];
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
serverData,
|
||||
arch: /* xml */ `
|
||||
<form>
|
||||
<field name="p">
|
||||
<tree>
|
||||
<field name="display_name"/>
|
||||
</tree>
|
||||
<form>
|
||||
<field name="p" mode="kanban" context="{ 'kanban_view_ref': 1234 }" />
|
||||
</form>
|
||||
</field>
|
||||
</form>`,
|
||||
resId: 1,
|
||||
});
|
||||
await click(target, ".o_data_row td[name=display_name]");
|
||||
assert.containsOnce(target, ".modal .o_kanban_record:not(.o_kanban_ghost)");
|
||||
assert.hasClass(target.querySelector(".modal .o_field_x2many_kanban"), "o-custom-class");
|
||||
|
||||
const record = target.querySelector(".modal .o_kanban_record:not(.o_kanban_ghost)");
|
||||
record.focus(); // shortcut for a true click
|
||||
@@ -12642,7 +12688,7 @@ QUnit.module("Fields", (hooks) => {
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
serverData,
|
||||
arch: `
|
||||
arch: /* xml */ `
|
||||
<form>
|
||||
<field name="p">
|
||||
<tree>
|
||||
@@ -12650,7 +12696,7 @@ QUnit.module("Fields", (hooks) => {
|
||||
</tree>
|
||||
<form>
|
||||
<field name="p">
|
||||
<tree editable="1">
|
||||
<tree editable="1" class="o-custom-class">
|
||||
<field name="display_name"/>
|
||||
</tree>
|
||||
</field>
|
||||
@@ -12661,6 +12707,47 @@ QUnit.module("Fields", (hooks) => {
|
||||
});
|
||||
await click(target.querySelector(".o_data_row td[name=display_name]"));
|
||||
assert.containsOnce(target, ".modal .o_data_row td[name=display_name]");
|
||||
assert.hasClass(target.querySelector(".modal .o_field_x2many_list"), "o-custom-class");
|
||||
|
||||
const header = target.querySelector(".modal thead th[data-name=display_name]");
|
||||
header.focus(); // shortcut but possible via the mouse and keynav;
|
||||
assert.strictEqual(document.activeElement, header);
|
||||
|
||||
await triggerHotkey("ArrowUp");
|
||||
await nextTick();
|
||||
|
||||
assert.containsOnce(target, ".modal .o_data_row td[name=display_name]");
|
||||
});
|
||||
|
||||
QUnit.test("list one2many in opened view form (with _view_ref)", async function (assert) {
|
||||
serverData.views = {
|
||||
"partner,1234,list": /* xml */ `
|
||||
<tree editable="1" class="o-custom-class">
|
||||
<field name="display_name"/>
|
||||
</tree>
|
||||
`,
|
||||
};
|
||||
serverData.models.partner.records[0].p = [1];
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
serverData,
|
||||
arch: /* xml */ `
|
||||
<form>
|
||||
<field name="p">
|
||||
<tree>
|
||||
<field name="display_name"/>
|
||||
</tree>
|
||||
<form>
|
||||
<field name="p" mode="list" context="{ 'list_view_ref': 1234 }" />
|
||||
</form>
|
||||
</field>
|
||||
</form>`,
|
||||
resId: 1,
|
||||
});
|
||||
await click(target.querySelector(".o_data_row td[name=display_name]"));
|
||||
assert.containsOnce(target, ".modal .o_data_row td[name=display_name]");
|
||||
assert.hasClass(target.querySelector(".modal .o_field_x2many_list"), "o-custom-class");
|
||||
|
||||
const header = target.querySelector(".modal thead th[data-name=display_name]");
|
||||
header.focus(); // shortcut but possible via the mouse and keynav;
|
||||
|
||||
Reference in New Issue
Block a user