diff --git a/addons/web/static/src/js/fields/abstract_field.js b/addons/web/static/src/js/fields/abstract_field.js index e0b71f088ad..9fb677d42a0 100644 --- a/addons/web/static/src/js/fields/abstract_field.js +++ b/addons/web/static/src/js/fields/abstract_field.js @@ -258,6 +258,16 @@ var AbstractField = Widget.extend({ getFocusableElement: function () { return $(); }, + /** + * Returns whether or not the field is empty and can thus be hidden. This + * method is typically called when the widget is in readonly, to hide it + * (and its label) if it is empty. + * + * @returns {boolean} + */ + isEmpty: function () { + return !this.isSet(); + }, /** * Returns true iff the widget has a visible element that can take the focus * diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js index 500ebf1f609..0bf264aca1d 100644 --- a/addons/web/static/src/js/fields/relational_fields.js +++ b/addons/web/static/src/js/fields/relational_fields.js @@ -2721,6 +2721,21 @@ var FieldStatus = AbstractField.extend({ this.isClickable = !!this.attrs.clickable || !!this.nodeOptions.clickable; }, + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + /** + * Returns false to force the statusbar to be always visible (even the field + * it not set). + * + * @override + * @returns {boolean} always false + */ + isEmpty: function () { + return false; + }, + //-------------------------------------------------------------------------- // Private //-------------------------------------------------------------------------- diff --git a/addons/web/static/src/js/views/basic/basic_renderer.js b/addons/web/static/src/js/views/basic/basic_renderer.js index 8af8540dd57..07edeae343a 100644 --- a/addons/web/static/src/js/views/basic/basic_renderer.js +++ b/addons/web/static/src/js/views/basic/basic_renderer.js @@ -662,7 +662,7 @@ var BasicRenderer = AbstractRenderer.extend({ element.$el.toggleClass('o_field_empty', !!( record.data.id && (modifiers.readonly || mode === 'readonly') && - !element.widget.isSet() + element.widget.isEmpty() )); }, keepBaseMode: !!options.keepBaseMode, diff --git a/addons/web/static/tests/fields/relational_fields_tests.js b/addons/web/static/tests/fields/relational_fields_tests.js index 41f7a86afc4..11d67bd3752 100644 --- a/addons/web/static/tests/fields/relational_fields_tests.js +++ b/addons/web/static/tests/fields/relational_fields_tests.js @@ -815,23 +815,68 @@ QUnit.module('relational_fields', { assert.expect(2); this.data.product.records = []; - var form = await createView({ + const form = await createView({ View: FormView, model: 'partner', data: this.data, - arch:'
', + arch: ``, res_id: 1, config: {device: {isMobile: false}}, }); - assert.hasClass(form.$('.o_statusbar_status'), 'o_field_empty'); + assert.doesNotHaveClass(form.$('.o_statusbar_status'), 'o_field_empty'); assert.strictEqual(form.$('.o_statusbar_status').children().length, 0, 'statusbar widget should be empty'); form.destroy(); }); + QUnit.test('statusbar with required modifier', async function (assert) { + assert.expect(2); + + const form = await createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: ``, + config: {device: {isMobile: false}}, + }); + testUtils.intercept(form, 'call_service', function (ev) { + assert.strictEqual(ev.data.service, 'notification', + "should display an 'invalid fields' notification"); + }, true); + + testUtils.form.clickSave(form); + + assert.containsOnce(form, '.o_form_editable', 'view should still be in edit'); + + form.destroy(); + }); + + QUnit.test('statusbar with no value in readonly', async function (assert) { + assert.expect(2); + + const form = await createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: ` + `, + res_id: 1, + config: {device: {isMobile: false}}, + }); + + assert.doesNotHaveClass(form.$('.o_statusbar_status'), 'o_field_empty'); + assert.containsN(form, '.o_statusbar_status button:visible', 2); + + form.destroy(); + }); + QUnit.test('statusbar with domain but no value (create mode)', async function (assert) { assert.expect(1);