[FIX] web: Adds missing placeholders to fields with an input

This commit adds the ability to pass a placeholder to all fields
containing an input.

This commit tests the ability to use a placeholder in all fields
containing an input.

closes odoo/odoo#95309

Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
FrancoisGe
2022-07-06 10:36:28 +02:00
parent 102136f2ae
commit f1856cce24
21 changed files with 286 additions and 10 deletions
@@ -16,6 +16,12 @@ export class EmailField extends Component {
EmailField.template = "web.EmailField";
EmailField.props = {
...standardFieldProps,
placeholder: { type: String, optional: true },
};
EmailField.extractProps = (fieldName, record, attrs) => {
return {
placeholder: attrs.placeholder,
};
};
EmailField.displayName = _lt("Email");
@@ -53,6 +53,7 @@ FloatField.props = {
step: { type: Number, optional: true },
digits: { type: Array, optional: true },
invalidate: { type: Function, optional: true },
placeholder: { type: String, optional: true },
};
FloatField.defaultProps = {
inputType: "text",
@@ -73,6 +74,7 @@ FloatField.extractProps = (fieldName, record, attrs) => {
digits:
(attrs.digits ? JSON.parse(attrs.digits) : attrs.options.digits) ||
record.fields[fieldName].digits,
placeholder: attrs.placeholder,
};
};
@@ -3,7 +3,7 @@
<t t-name="web.FloatField" owl="1">
<span t-if="props.readonly" t-esc="getFormattedValue()" />
<input t-else="" t-att-id="props.id" t-ref="numpadDecimal" t-att-type="props.inputType" inputmode="numeric" class="o_input" t-on-change="onChange" t-att-step="props.step" />
<input t-else="" t-att-id="props.id" t-ref="numpadDecimal" t-att-placeholder="props.placeholder" t-att-type="props.inputType" inputmode="numeric" class="o_input" t-on-change="onChange" t-att-step="props.step" />
</t>
</templates>
@@ -29,6 +29,7 @@ FloatTimeField.template = "web.FloatTimeField";
FloatTimeField.props = {
...standardFieldProps,
invalidate: { type: Function, optional: true },
placeholder: { type: String, optional: true },
};
FloatTimeField.defaultProps = {
invalidate: () => {},
@@ -38,9 +39,10 @@ FloatTimeField.displayName = _lt("Time");
FloatTimeField.supportedTypes = ["float"];
FloatTimeField.isEmpty = () => false;
FloatTimeField.extractProps = (fieldName, record) => {
FloatTimeField.extractProps = (fieldName, record, attrs) => {
return {
invalidate: () => record.setInvalidField(fieldName),
placeholder: attrs.placeholder,
};
};
@@ -3,7 +3,7 @@
<t t-name="web.FloatTimeField" owl="1">
<span t-if="props.readonly" t-esc="formattedValue" />
<input t-else="" t-att-id="props.id" t-ref="numpadDecimal" inputmode="numeric" class="o_input" />
<input t-else="" t-att-id="props.id" t-ref="numpadDecimal" t-att-placeholder="props.placeholder" inputmode="numeric" class="o_input" />
</t>
</templates>
@@ -32,6 +32,7 @@ PercentageField.props = {
...standardFieldProps,
invalidate: { type: Function, optional: true },
digits: { type: Array, optional: true },
placeholder: { type: String, optional: true },
};
PercentageField.defaultProps = {
invalidate: () => {},
@@ -46,6 +47,7 @@ PercentageField.extractProps = (fieldName, record, attrs) => {
digits:
(attrs.digits ? JSON.parse(attrs.digits) : attrs.options.digits) ||
record.fields[fieldName].digits,
placeholder: attrs.placeholder,
};
};
@@ -10,6 +10,7 @@
<input
t-ref="numpadDecimal"
t-attf-class="o_input"
t-att-placeholder="props.placeholder"
type="text"
inputmode="numeric"
/>
@@ -1015,4 +1015,27 @@ QUnit.module("Fields", (hooks) => {
);
}
);
QUnit.test("char field with placeholder", async function (assert) {
serverData.models.partner.fields.foo.default = false;
await makeView({
type: "form",
resModel: "partner",
serverData,
arch: `
<form>
<sheet>
<group>
<field name="foo" placeholder="Placeholder" />
</group>
</sheet>
</form>`,
});
assert.strictEqual(
target.querySelector(".o_field_widget[name='foo'] input").placeholder,
"Placeholder"
);
});
});
@@ -163,11 +163,12 @@ QUnit.module("Fields", (hooks) => {
<form>
<sheet>
<group>
<field name="empty_string" widget="email"/>
<field name="empty_string" widget="email" placeholder="Placeholder"/>
</group>
</sheet>
</form>`,
});
assert.strictEqual(target.querySelector(".o_field_email input").placeholder, "Placeholder");
await click(target.querySelector(".o_form_button_save"));
const mailtoLink = target.querySelector(".o_field_email a");
@@ -239,4 +240,27 @@ QUnit.module("Fields", (hooks) => {
);
}
);
QUnit.test("email field with placeholder", async function (assert) {
serverData.models.partner.fields.foo.default = false;
await makeView({
type: "form",
resModel: "partner",
serverData,
arch: `
<form>
<sheet>
<group>
<field name="foo" placeholder="New Placeholder" />
</group>
</sheet>
</form>`,
});
assert.strictEqual(
target.querySelector(".o_field_widget[name='foo'] input").placeholder,
"New Placeholder"
);
});
});
@@ -1,9 +1,9 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { makeFakeLocalizationService } from "@web/../tests/helpers/mock_services";
import { click, editInput, getFixture } from "@web/../tests/helpers/utils";
import { click, editInput, getFixture, triggerEvent } from "@web/../tests/helpers/utils";
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
import { registry } from "@web/core/registry";
let serverData;
let target;
@@ -447,4 +447,21 @@ QUnit.module("Fields", (hooks) => {
"Float value must be formatted if input type isn't number."
);
});
QUnit.test("float_field field with placeholder", async function (assert) {
await makeView({
type: "form",
resModel: "partner",
serverData,
arch: '<form><field name="float_field" placeholder="Placeholder"/></form>',
});
const input = target.querySelector(".o_field_widget[name='float_field'] input");
input.value = "";
await triggerEvent(input, null, "input");
assert.strictEqual(
target.querySelector(".o_field_widget[name='float_field'] input").placeholder,
"Placeholder"
);
});
});
@@ -1,6 +1,6 @@
/** @odoo-module **/
import { click, editInput, getFixture } from "@web/../tests/helpers/utils";
import { click, editInput, getFixture, triggerEvent } from "@web/../tests/helpers/utils";
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
let serverData;
@@ -164,4 +164,24 @@ QUnit.module("Fields", (hooks) => {
"date field should not be displayed as invalid now"
);
});
QUnit.test("float_time field with placeholder", async function (assert) {
await makeView({
serverData,
type: "form",
resModel: "partner",
arch: `
<form>
<field name="qux" widget="float_time" placeholder="Placeholder"/>
</form>`,
});
const input = target.querySelector(".o_field_widget[name='qux'] input");
input.value = "";
await triggerEvent(input, null, "input");
assert.strictEqual(
target.querySelector(".o_field_widget[name='qux'] input").placeholder,
"Placeholder"
);
});
});
@@ -36,7 +36,7 @@ QUnit.module("Fields", (hooks) => {
serverData,
type: "form",
resModel: "partner",
arch: '<form><field name="fonts" widget="font"/></form>',
arch: '<form><field name="fonts" widget="font" placeholder="Placeholder"/></form>',
});
const options = target.querySelectorAll('.o_field_widget[name="fonts"] option');
@@ -46,6 +46,12 @@ QUnit.module("Fields", (hooks) => {
"Widget font should be default (Lato)"
);
assert.strictEqual(options[0].value, "false", "Unselected option has no value");
assert.strictEqual(
options[0].textContent,
"Placeholder",
"Unselected option is the placeholder"
);
assert.strictEqual(
options[1].style.fontFamily,
"Lato",
@@ -2,7 +2,13 @@
import { localization } from "@web/core/l10n/localization";
import { defaultLocalization } from "@web/../tests/helpers/mock_services";
import { click, editInput, getFixture, patchWithCleanup } from "@web/../tests/helpers/utils";
import {
click,
editInput,
getFixture,
patchWithCleanup,
triggerEvent,
} from "@web/../tests/helpers/utils";
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
let serverData;
@@ -299,4 +305,21 @@ QUnit.module("Fields", (hooks) => {
"The new value should be saved and displayed properly."
);
});
QUnit.test("IntegerField field with placeholder", async function (assert) {
await makeView({
type: "form",
resModel: "partner",
serverData,
arch: `<form><field name="int_field" placeholder="Placeholder"/></form>`,
});
const input = target.querySelector(".o_field_widget[name='int_field'] input");
input.value = "";
await triggerEvent(input, null, "input");
assert.strictEqual(
target.querySelector(".o_field_widget[name='int_field'] input").placeholder,
"Placeholder"
);
});
});
@@ -1525,4 +1525,19 @@ QUnit.module("Fields", (hooks) => {
);
assert.containsOnce(row, ".o-autocomplete--input");
});
QUnit.test("Many2ManyTagsField with placeholder", async function (assert) {
await makeView({
type: "form",
resModel: "partner",
serverData,
arch:
'<form><field name="timmy" widget="many2many_tags" placeholder="Placeholder"/></form>',
});
assert.strictEqual(
target.querySelector(".o_field_widget[name='timmy'] input").placeholder,
"Placeholder"
);
});
});
@@ -224,4 +224,19 @@ QUnit.module("Fields", (hooks) => {
"/web/image/user/17/avatar_128"
);
});
QUnit.test("Many2OneAvatar with placeholder", async function (assert) {
await makeView({
type: "form",
resModel: "partner",
serverData,
arch:
'<form><field name="user_id" widget="many2one_avatar" placeholder="Placeholder"/></form>',
});
assert.strictEqual(
target.querySelector(".o_field_widget[name='user_id'] input").placeholder,
"Placeholder"
);
});
});
@@ -4034,4 +4034,18 @@ QUnit.module("Fields", (hooks) => {
"Should contain 2 breadcrumbs after the clicking on the link"
);
});
QUnit.test("Many2oneField with placeholder", async function (assert) {
await makeView({
type: "form",
resModel: "partner",
serverData,
arch: '<form><field name="trululu" placeholder="Placeholder"/></form>',
});
assert.strictEqual(
target.querySelector(".o_field_widget[name='trululu'] input").placeholder,
"Placeholder"
);
});
});
@@ -9,6 +9,7 @@ import {
editInput,
getFixture,
patchWithCleanup,
triggerEvent,
} from "@web/../tests/helpers/utils";
import { session } from "@web/session";
@@ -1112,4 +1113,25 @@ QUnit.module("Fields", (hooks) => {
"The currency symbol is not displayed"
);
});
QUnit.test("monetary field with placeholder", async function (assert) {
await makeView({
type: "form",
resModel: "partner",
serverData,
arch: `
<form>
<field name="float_field" widget="monetary" placeholder="Placeholder"/>
<field name="currency_id" invisible="1"/>
</form>`,
});
const input = target.querySelector(".o_field_widget[name='float_field'] input");
input.value = "";
await triggerEvent(input, null, "input");
assert.strictEqual(
target.querySelector(".o_field_widget[name='float_field'] input").placeholder,
"Placeholder"
);
});
});
@@ -1,6 +1,6 @@
/** @odoo-module **/
import { click, editInput, getFixture } from "@web/../tests/helpers/utils";
import { click, editInput, getFixture, triggerEvent } from "@web/../tests/helpers/utils";
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
let serverData;
@@ -77,4 +77,24 @@ QUnit.module("Fields", (hooks) => {
"The new value should be formatted properly."
);
});
QUnit.test("percentage field with placeholder", async function (assert) {
await makeView({
type: "form",
resModel: "partner",
serverData,
arch: `
<form>
<field name="float_field" widget="percentage" placeholder="Placeholder"/>
</form>`,
});
const input = target.querySelector(".o_field_widget[name='float_field'] input");
input.value = "";
await triggerEvent(input, null, "input");
assert.strictEqual(
target.querySelector(".o_field_widget[name='float_field'] input").placeholder,
"Placeholder"
);
});
});
@@ -162,4 +162,27 @@ QUnit.module("Fields", (hooks) => {
"foo should be focused"
);
});
QUnit.test("phone field with placeholder", async function (assert) {
serverData.models.partner.fields.foo.default = false;
await makeView({
type: "form",
resModel: "partner",
serverData,
arch: `
<form>
<sheet>
<group>
<field name="foo" widget="phone" placeholder="Placeholder"/>
</group>
</sheet>
</form>`,
});
assert.strictEqual(
target.querySelector(".o_field_widget[name='foo'] input").placeholder,
"Placeholder"
);
});
});
@@ -395,4 +395,22 @@ QUnit.module("Fields", (hooks) => {
"Two options in second selection as it is now required"
);
});
QUnit.test("selection field with placeholder", async function (assert) {
await makeView({
type: "form",
resModel: "partner",
serverData,
arch: `
<form>
<field name="trululu" widget="selection" placeholder="Placeholder"/>
</form>`,
});
const placeholderOption = target.querySelector(
".o_field_widget[name='trululu'] select option"
);
assert.strictEqual(placeholderOption.textContent, "Placeholder");
assert.strictEqual(placeholderOption.value, "false");
});
});
@@ -296,4 +296,27 @@ QUnit.module("Fields", (hooks) => {
target.querySelector(".o_field_widget[name=foo]").textContent
);
});
QUnit.test("url field with placeholder", async function (assert) {
serverData.models.partner.fields.foo.default = false;
await makeView({
type: "form",
resModel: "partner",
serverData,
arch: `
<form>
<sheet>
<group>
<field name="foo" widget="url" placeholder="Placeholder"/>
</group>
</sheet>
</form>`,
});
assert.strictEqual(
target.querySelector(".o_field_widget[name='foo'] input").placeholder,
"Placeholder"
);
});
});