diff --git a/addons/web/static/src/views/view_compiler.js b/addons/web/static/src/views/view_compiler.js index 6e3ab652d8b..46efb8f954c 100644 --- a/addons/web/static/src/views/view_compiler.js +++ b/addons/web/static/src/views/view_compiler.js @@ -453,7 +453,7 @@ export function useViewCompiler(ViewCompiler, templates, params) { const compiledTemplates = {}; let compiler; for (const tname in templates) { - const key = templates[tname].outerHTML; + const key = `${ViewCompiler.name}/${templates[tname].outerHTML}`; if (!templateCache[key]) { compiler = compiler || new ViewCompiler(templates); templateCache[key] = xml`${compiler.compile(tname, params).outerHTML}`; diff --git a/addons/web/static/tests/views/kanban/kanban_view_tests.js b/addons/web/static/tests/views/kanban/kanban_view_tests.js index 95fd0840d3c..66734632841 100644 --- a/addons/web/static/tests/views/kanban/kanban_view_tests.js +++ b/addons/web/static/tests/views/kanban/kanban_view_tests.js @@ -46,6 +46,8 @@ import { AnimatedNumber } from "@web/views/view_components/animated_number"; import { Component, onRendered, onWillRender, xml } from "@odoo/owl"; import { SampleServer } from "@web/model/sample_server"; import { KanbanRenderer } from "@web/views/kanban/kanban_renderer"; +import { KanbanCompiler } from "@web/views/kanban/kanban_compiler"; +import { KanbanRecord } from "@web/views/kanban/kanban_record"; import { patchDialog, @@ -14150,4 +14152,76 @@ QUnit.module("Views", (hooks) => { assert.containsN(target, ".o_kanban_group:nth-child(2) .o_kanban_record", 0); assert.containsN(target, ".o_kanban_group:nth-child(3) .o_kanban_record", 2); }); + + QUnit.test("kanbans with basic and custom compiler, same arch", async (assert) => { + // In this test, the exact same arch will be rendered by 2 different kanban renderers: + // once with the basic one, and once with a custom renderer having a custom compiler. The + // purpose of the test is to ensure that the template is compiled twice, once by each + // compiler, even though the arch is the same. + class MyKanbanCompiler extends KanbanCompiler { + setup() { + super.setup(); + this.compilers.push({ selector: "div", fn: this.compileDiv }); + } + + compileDiv(node, params) { + const compiledNode = this.compileGenericNode(node, params); + compiledNode.setAttribute("class", "my_kanban_compiler"); + return compiledNode; + } + } + class MyKanbanRecord extends KanbanRecord {} + MyKanbanRecord.Compiler = MyKanbanCompiler; + class MyKanbanRenderer extends KanbanRenderer {} + MyKanbanRenderer.components = { + ...KanbanRenderer.components, + KanbanRecord: MyKanbanRecord, + }; + viewRegistry.add("my_kanban", { + ...kanbanView, + Renderer: MyKanbanRenderer, + }); + + serverData.models.partner.fields.one2many = { + type: "one2many", + name: "o2m", + relation: "partner", + }; + serverData.models.partner.records[0].one2many = [1]; + serverData.views = { + "partner,false,form": `
`, + "partner,false,search": ``, + "partner,false,kanban": ` + + +
+
+
+
`, + }; + + const webClient = await createWebClient({ serverData }); + await doAction(webClient, { + res_model: "partner", + type: "ir.actions.act_window", + views: [ + [false, "kanban"], + [false, "form"], + ], + }); + + // main kanban, custom view + assert.containsOnce(target, ".o_kanban_view"); + assert.containsOnce(target, ".o_my_kanban_view"); + assert.containsN(target, ".my_kanban_compiler", 4); + + // switch to form + await click(target.querySelector(".o_kanban_record")); + assert.containsOnce(target, ".o_form_view"); + assert.containsOnce(target, ".o_form_view .o_field_widget[name=one2many]"); + + // x2many kanban, basic renderer + assert.containsOnce(target, ".o_kanban_record:not(.o_kanban_ghost)"); + assert.containsNone(target, ".my_kanban_compiler"); + }); });