[FIX] web: html field in list view
Before this commit, in a list view, html fields in readonly mode were
not rendered correctly. It displayed unprocessed HTML.
For the value :
<div>Hello</div>
Before this commit, it was displaying:
<div>Hello</div>
After this commit, we display:
Hello
closes odoo/odoo#101253
X-original-commit: a6292c17b886996c82c797e562b725d63d4a5b7e
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
@@ -8,6 +8,8 @@ import { escape, intersperse, nbsp, sprintf } from "@web/core/utils/strings";
|
||||
import { isBinarySize } from "@web/core/utils/binary";
|
||||
import { session } from "@web/session";
|
||||
|
||||
const { markup } = owl;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -121,7 +123,13 @@ export function formatBinary(value) {
|
||||
* @returns {string}
|
||||
*/
|
||||
export function formatBoolean(value) {
|
||||
return value ? _t("True") : _t("False");
|
||||
return markup(`
|
||||
<div class="o-checkbox d-inline-block me-2">
|
||||
<input id="boolean_checkbox" type="checkbox" class="form-check-input" disabled ${
|
||||
value ? "checked" : ""
|
||||
}/>
|
||||
<label for="boolean_checkbox" class="form-check-label"/>
|
||||
</div>`);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -287,7 +295,7 @@ export function formatMany2one(value, options) {
|
||||
if (!value) {
|
||||
value = "";
|
||||
} else {
|
||||
value = value[1];
|
||||
value = value[1] || "";
|
||||
}
|
||||
if (options && options.escape) {
|
||||
value = encodeURIComponent(value);
|
||||
|
||||
@@ -234,7 +234,7 @@ export class KanbanCompiler extends ViewCompiler {
|
||||
if (!el.hasAttribute("widget")) {
|
||||
// fields without a specified widget are rendered as simple spans in kanban records
|
||||
const fieldName = el.getAttribute("name");
|
||||
compiled = createElement("span", { "t-esc": `record["${fieldName}"].value` });
|
||||
compiled = createElement("span", { "t-out": `record["${fieldName}"].value` });
|
||||
} else {
|
||||
compiled = super.compileField(el, params);
|
||||
const fieldId = el.getAttribute("field_id") || el.getAttribute("name");
|
||||
|
||||
@@ -348,9 +348,7 @@ export class ListRenderer extends Component {
|
||||
}
|
||||
|
||||
canUseFormatter(column, record) {
|
||||
return (
|
||||
!record.isInEdition && !column.widget && record.fields[column.name].type !== "boolean"
|
||||
);
|
||||
return !record.isInEdition && !column.widget;
|
||||
}
|
||||
|
||||
focusCell(column, forward = true) {
|
||||
|
||||
@@ -225,7 +225,7 @@
|
||||
data-tooltip-delay="1000"
|
||||
t-on-click="(ev) => this.onCellClicked(record, column, ev)" tabindex="-1">
|
||||
<t t-if="!evalModifier(column.modifiers.invisible, record)">
|
||||
<t t-if="canUseFormatter(column, record)" t-esc="getFormattedValue(column, record)"/>
|
||||
<t t-if="canUseFormatter(column, record)" t-out="getFormattedValue(column, record)"/>
|
||||
<Field t-else="" name="column.name" record="record" type="column.widget" class="getFieldClass(column)" fieldInfo="props.archInfo.fieldNodes[column.name]" setDirty="(isDirty) => this.setDirty(isDirty)"/>
|
||||
</t>
|
||||
</td>
|
||||
|
||||
@@ -239,29 +239,6 @@ QUnit.module("Fields", (hooks) => {
|
||||
3,
|
||||
"should still have only 3 checked input"
|
||||
);
|
||||
|
||||
// Re-Edit the line to check the checkbox back but this time click on
|
||||
// the checkbox directly in readonly mode.
|
||||
// This should not toggle the checkbox and only pass the record in edition.
|
||||
cell = target.querySelector("tr.o_data_row td:not(.o_list_record_selector)");
|
||||
await click(cell, ".o_field_boolean");
|
||||
|
||||
assert.notOk(
|
||||
cell.querySelector(".o-checkbox input").disabled,
|
||||
"input should not have the disabled property in edit mode"
|
||||
);
|
||||
assert.containsN(
|
||||
target,
|
||||
"tbody td:not(.o_list_record_selector) .o-checkbox",
|
||||
5,
|
||||
"should still have 5 checkboxes"
|
||||
);
|
||||
assert.containsN(
|
||||
target,
|
||||
"tbody td:not(.o_list_record_selector) .o-checkbox input:checked",
|
||||
3,
|
||||
"should still have only 3 checked input"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("readonly boolean field", async function (assert) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { editInput, getFixture } from "@web/../tests/helpers/utils";
|
||||
import { click, editInput, getFixture } from "@web/../tests/helpers/utils";
|
||||
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { HtmlField } from "@web/views/fields/html/html_field";
|
||||
@@ -34,7 +34,7 @@ QUnit.module("Fields", ({ beforeEach }) => {
|
||||
|
||||
QUnit.module("HtmlField");
|
||||
|
||||
QUnit.test("html fields are correctly rendered (readonly)", async (assert) => {
|
||||
QUnit.test("html fields are correctly rendered in form view (readonly)", async (assert) => {
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
@@ -68,4 +68,46 @@ QUnit.module("Fields", ({ beforeEach }) => {
|
||||
await editInput(textarea, null, BLUE_TEXT);
|
||||
assert.strictEqual(textarea.value, BLUE_TEXT);
|
||||
});
|
||||
|
||||
QUnit.test("html fields are correctly rendered in list view", async (assert) => {
|
||||
await makeView({
|
||||
type: "list",
|
||||
resModel: "partner",
|
||||
serverData,
|
||||
arch: `
|
||||
<tree editable="top">
|
||||
<field name="txt"/>
|
||||
</tree>`,
|
||||
});
|
||||
const txt = target.querySelector(".o_data_row [name='txt']");
|
||||
assert.strictEqual(txt.textContent, "some text");
|
||||
assert.strictEqual(txt.querySelector(".kek").style.color, "red");
|
||||
|
||||
await click(target.querySelector(".o_data_row [name='txt']"));
|
||||
assert.strictEqual(
|
||||
target.querySelector(".o_data_row [name='txt'] textarea").value,
|
||||
'<div class="kek" style="color:red">some text</div>'
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("html fields are correctly rendered in kanban view", async (assert) => {
|
||||
await makeView({
|
||||
type: "kanban",
|
||||
resModel: "partner",
|
||||
serverData,
|
||||
arch: `
|
||||
<kanban class="o_kanban_test">
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div>
|
||||
<field name="txt"/>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>`,
|
||||
});
|
||||
const txt = target.querySelector(".kek");
|
||||
assert.strictEqual(txt.textContent, "some text");
|
||||
assert.strictEqual(txt.style.color, "red");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11103,7 +11103,7 @@ QUnit.module("Fields", (hooks) => {
|
||||
// the next line should be displayed below the newly added one
|
||||
assert.containsN(target, ".o_data_row", 2, "should have 2 records");
|
||||
assert.deepEqual(
|
||||
getNodesTextContent(target.querySelectorAll(".o_data_cell")),
|
||||
[...target.querySelectorAll(".o_data_cell")].map(el => el.textContent.trim()),
|
||||
["pi", "", "kawa", ""],
|
||||
"should display the correct records on page 1"
|
||||
);
|
||||
|
||||
@@ -9800,8 +9800,9 @@ QUnit.module("Views", (hooks) => {
|
||||
</kanban>`,
|
||||
});
|
||||
|
||||
assert.containsN(target, ".o_kanban_record:contains(True)", 3);
|
||||
assert.containsOnce(target, ".o_kanban_record:contains(False)");
|
||||
assert.containsN(target, ".o_kanban_record input:disabled", 4);
|
||||
assert.containsN(target, ".o_kanban_record input:checked", 3);
|
||||
assert.containsOnce(target, ".o_kanban_record input:not(:checked)");
|
||||
});
|
||||
|
||||
QUnit.test("kanban view with boolean widget", async (assert) => {
|
||||
|
||||
@@ -15125,6 +15125,7 @@ QUnit.module("Views", (hooks) => {
|
||||
|
||||
assert.verifySteps(["create"]);
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"classNames given to a field are set on the right field directly",
|
||||
async function (assert) {
|
||||
@@ -15139,7 +15140,7 @@ QUnit.module("Views", (hooks) => {
|
||||
</tree>`,
|
||||
});
|
||||
assert.doesNotHaveClass(
|
||||
target.querySelector(".o_field_cell:nth-child(2)"),
|
||||
target.querySelectorAll(".o_field_cell")[2],
|
||||
"d-flex align-items-center",
|
||||
"classnames are not set on the first cell"
|
||||
);
|
||||
@@ -15148,15 +15149,10 @@ QUnit.module("Views", (hooks) => {
|
||||
"d-flex align-items-center",
|
||||
"classnames are set on the corresponding field div directly"
|
||||
);
|
||||
assert.doesNotHaveClass(
|
||||
target.querySelector(".o_field_cell:nth-child(3)"),
|
||||
"d-none",
|
||||
"classnames are not set on the second cell"
|
||||
);
|
||||
assert.hasClass(
|
||||
target.querySelector(".o_field_boolean"),
|
||||
target.querySelectorAll(".o_field_cell")[3],
|
||||
"d-none",
|
||||
"classnames are set on the second field div directly"
|
||||
"classnames are set on the second cell"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user