diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js index a4979848adb..2872be972a5 100644 --- a/addons/web/static/src/js/fields/basic_fields.js +++ b/addons/web/static/src/js/fields/basic_fields.js @@ -347,6 +347,20 @@ var FieldChar = InputField.extend(TranslatableFieldMixin, { this.$el = this.$el.add(this._renderTranslateButton()); return def; }, + /** + * Trim the value input by the user. + * + * @override + * @private + * @param {any} value + * @param {Object} [options] + */ + _setValue: function (value, options) { + if (this.field.trim) { + value = value.trim(); + } + return this._super(value, options); + }, }); diff --git a/addons/web/static/tests/fields/basic_fields_tests.js b/addons/web/static/tests/fields/basic_fields_tests.js index 35431904cec..0e1bb096e50 100644 --- a/addons/web/static/tests/fields/basic_fields_tests.js +++ b/addons/web/static/tests/fields/basic_fields_tests.js @@ -24,7 +24,7 @@ QUnit.module('basic_fields', { date: {string: "A date", type: "date", searchable: true}, datetime: {string: "A datetime", type: "datetime", searchable: true}, display_name: {string: "Displayed name", type: "char", searchable: true}, - foo: {string: "Foo", type: "char", default: "My little Foo Value", searchable: true}, + foo: {string: "Foo", type: "char", default: "My little Foo Value", searchable: true, trim: true}, bar: {string: "Bar", type: "boolean", default: true, searchable: true}, txt: {string: "txt", type: "text", default: "My little txt Value\nHo-ho-hoooo Merry Christmas"}, int_field: {string: "int_field", type: "integer", sortable: true, searchable: true}, @@ -876,6 +876,43 @@ QUnit.module('basic_fields', { form.destroy(); }); + QUnit.test('char field trim (or not) characters', function (assert) { + assert.expect(2); + + this.data.partner.fields.foo2 = {string: "Foo2", type: "char", trim: false}; + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '
' + + '' + + '' + + '' + + '' + + '' + + '' + + '
', + res_id: 1, + viewOptions: { + mode: 'edit', + }, + }); + + form.$('input[name="foo"]').val(' abc ').trigger('input'); + form.$('input[name="foo2"]').val(' def ').trigger('input'); + + form.$buttons.find('.o_form_button_save').click(); + + // edit mode + form.$buttons.find('.o_form_button_edit').click(); + + assert.strictEqual(form.$('input[name="foo"]').val(), 'abc', 'Foo value should have been trimmed'); + assert.strictEqual(form.$('input[name="foo2"]').val(), ' def ', 'Foo2 value should not have been trimmed'); + + form.destroy(); + }); + QUnit.test('input field: change value before pending onchange returns', function (assert) { assert.expect(3); diff --git a/odoo/addons/base/ir/ir_sequence.py b/odoo/addons/base/ir/ir_sequence.py index 70d70b536ef..84c8be3af60 100644 --- a/odoo/addons/base/ir/ir_sequence.py +++ b/odoo/addons/base/ir/ir_sequence.py @@ -122,8 +122,8 @@ class IrSequence(models.Model): "and 'No gap'. The later is slower than the former but forbids any" "gap in the sequence (while they are possible in the former).") active = fields.Boolean(default=True) - prefix = fields.Char(help="Prefix value of the record for the sequence") - suffix = fields.Char(help="Suffix value of the record for the sequence") + prefix = fields.Char(help="Prefix value of the record for the sequence", trim=False) + suffix = fields.Char(help="Suffix value of the record for the sequence", trim=False) number_next = fields.Integer(string='Next Number', required=True, default=1, help="Next number of this sequence") number_next_actual = fields.Integer(compute='_get_number_next_actual', inverse='_set_number_next_actual', string='Next Number', diff --git a/odoo/addons/base/res/res_lang.py b/odoo/addons/base/res/res_lang.py index 38737df2cb0..38b4209cc6f 100644 --- a/odoo/addons/base/res/res_lang.py +++ b/odoo/addons/base/res/res_lang.py @@ -38,8 +38,8 @@ class Lang(models.Model): "-1 will end the separation. e.g. [3,2,-1] will represent 106500 to be 1,06,500; " "[1,2,-1] will represent it to be 106,50,0;[3] will represent it as 106,500. " "Provided ',' as the thousand separator in each case.") - decimal_point = fields.Char(string='Decimal Separator', required=True, default='.') - thousands_sep = fields.Char(string='Thousands Separator', default=',') + decimal_point = fields.Char(string='Decimal Separator', required=True, default='.', trim=False) + thousands_sep = fields.Char(string='Thousands Separator', default=',', trim=False) _sql_constraints = [ ('name_uniq', 'unique(name)', 'The name of the language must be unique !'), diff --git a/odoo/fields.py b/odoo/fields.py index 4c41c938637..9818e99e1d3 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -1362,6 +1362,9 @@ class Char(_String): :param int size: the maximum size of values stored for that field + :param bool trim: states whether the value is trimmed or not. Note that + the trim operation is applied only on the web client + :param translate: enable the translation of the field's values; use ``translate=True`` to translate field values as a whole; ``translate`` may also be a callable such that ``translate(callback, value)`` @@ -1372,6 +1375,7 @@ class Char(_String): column_cast_from = ('text',) _slots = { 'size': None, # maximum size of values (deprecated) + 'trim': True, # whether value is trimmed (only by web client) } @property @@ -1388,7 +1392,9 @@ class Char(_String): super(Char, self).update_db_column(model, column) _related_size = property(attrgetter('size')) + _related_trim = property(attrgetter('trim')) _description_size = property(attrgetter('size')) + _description_trim = property(attrgetter('trim')) def _setup_regular_base(self, model): super(Char, self)._setup_regular_base(model)