summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--addons/web/static/src/js/fields/basic_fields.js91
-rw-r--r--addons/web/static/tests/fields/basic_fields_tests.js131
-rw-r--r--doc/reference/javascript_reference.rst35
3 files changed, 227 insertions, 30 deletions
diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js
index 00a4532c2e1..243a28bb937 100644
--- a/addons/web/static/src/js/fields/basic_fields.js
+++ b/addons/web/static/src/js/fields/basic_fields.js
@@ -346,6 +346,64 @@ var InputField = DebouncedField.extend({
},
});
+var NumericField = InputField.extend({
+ tagName: 'span',
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ /**
+ * For numeric fields, 0 is a valid value.
+ *
+ * @override
+ */
+ isSet: function () {
+ return this.value === 0 || this._super.apply(this, arguments);
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * Format numerical value (integer or float)
+ *
+ * Note: We have to overwrite this method to skip the format if we are into
+ * edit mode on a input type number.
+ *
+ * @override
+ * @private
+ */
+ _formatValue: function (value) {
+ if (this.mode === 'edit' && this.nodeOptions.type === 'number') {
+ return value;
+ }
+ return this._super.apply(this, arguments);
+ },
+
+ /**
+ * Formats an input element for edit mode. This is in a separate function so
+ * extending widgets can use it on their input without having input as tagName.
+ *
+ * Note: We have to overwrite this method to set the input's type to number if
+ * option setted into the field.
+ *
+ * @override
+ * @private
+ */
+ _prepareInput: function ($input) {
+ var result = this._super.apply(this, arguments);
+ if (this.nodeOptions.type === 'number') {
+ this.$input.attr({type: 'number'});
+ }
+ if (this.nodeOptions.step) {
+ this.$input.attr({step: this.nodeOptions.step});
+ }
+ return result;
+ }
+});
+
var FieldChar = InputField.extend(TranslatableFieldMixin, {
className: 'o_field_char',
tagName: 'span',
@@ -811,25 +869,11 @@ var FieldBoolean = AbstractField.extend({
},
});
-var FieldInteger = InputField.extend({
+var FieldInteger = NumericField.extend({
className: 'o_field_integer o_field_number',
- tagName: 'span',
supportedFieldTypes: ['integer'],
//--------------------------------------------------------------------------
- // Public
- //--------------------------------------------------------------------------
-
- /**
- * For integer fields, 0 is a valid value.
- *
- * @override
- */
- isSet: function () {
- return this.value === 0 || this._super.apply(this, arguments);
- },
-
- //--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
@@ -858,9 +902,8 @@ var FieldInteger = InputField.extend({
},
});
-var FieldFloat = InputField.extend({
+var FieldFloat = NumericField.extend({
className: 'o_field_float o_field_number',
- tagName: 'span',
supportedFieldTypes: ['float'],
/**
@@ -875,19 +918,6 @@ var FieldFloat = InputField.extend({
this.nodeOptions.digits = JSON.parse(this.attrs.digits);
}
},
-
- //--------------------------------------------------------------------------
- // Public
- //--------------------------------------------------------------------------
-
- /**
- * For float fields, 0 is a valid value.
- *
- * @override
- */
- isSet: function () {
- return this.value === 0 || this._super.apply(this, arguments);
- },
});
var FieldFloatTime = FieldFloat.extend({
@@ -2884,6 +2914,7 @@ return {
FieldToggleBoolean: FieldToggleBoolean,
HandleWidget: HandleWidget,
InputField: InputField,
+ NumericField: NumericField,
AttachmentImage: AttachmentImage,
LabelSelection: LabelSelection,
StateSelectionWidget: StateSelectionWidget,
diff --git a/addons/web/static/tests/fields/basic_fields_tests.js b/addons/web/static/tests/fields/basic_fields_tests.js
index 583be0a90a5..830855d8c1d 100644
--- a/addons/web/static/tests/fields/basic_fields_tests.js
+++ b/addons/web/static/tests/fields/basic_fields_tests.js
@@ -707,6 +707,71 @@ QUnit.module('basic_fields', {
form.destroy();
});
+ QUnit.test('float field with type number option', function (assert) {
+ assert.expect(4);
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '<form string="Partners">' +
+ '<field name="qux" options="{\'type\': \'number\'}"/>' +
+ '</form>',
+ res_id: 4,
+ translateParameters: {
+ thousands_sep: ",",
+ grouping: [3, 0],
+ },
+ });
+
+ form.$buttons.find('.o_form_button_edit').click();
+ assert.ok(form.$('.o_field_widget')[0].hasAttribute('type'),
+ 'Float field with option type must have a type attribute.');
+ assert.strictEqual(form.$('.o_field_widget').attr('type'), 'number',
+ 'Float field with option type must have a type attribute equals to "number".');
+ form.$('input').val('123456.7890').trigger('input');
+ form.$buttons.find('.o_form_button_save').click();
+ form.$buttons.find('.o_form_button_edit').click();
+ assert.strictEqual(form.$('.o_field_widget').val(), '123456.789',
+ 'Float value must be not formatted if input type is number.');
+ form.$buttons.find('.o_form_button_save').click();
+ assert.strictEqual(form.$('.o_field_widget').text(), '123,456.8',
+ 'Float value must be formatted in readonly view even if the input type is number.');
+
+ form.destroy();
+ });
+
+ QUnit.test('float field without type number option', function (assert) {
+ assert.expect(2);
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '<form string="Partners">' +
+ '<field name="qux"/>' +
+ '</form>',
+ res_id: 4,
+ translateParameters: {
+ thousands_sep: ",",
+ grouping: [3, 0],
+ },
+ });
+
+ form.$buttons.find('.o_form_button_edit').click();
+ assert.strictEqual(form.$('.o_field_widget').attr('type'), 'text',
+ 'Float field with option type must have a text type (default type).');
+
+ form.$('input').val('123456.7890').trigger('input');
+ form.$buttons.find('.o_form_button_save').click();
+ form.$buttons.find('.o_form_button_edit').click();
+ assert.strictEqual(form.$('.o_field_widget').val(), '123,456.8',
+ 'Float value must be formatted if input type isn\'t number.');
+
+ form.destroy();
+ });
+
+
QUnit.module('FieldEmail');
QUnit.test('email field in form view', function (assert) {
@@ -3359,6 +3424,72 @@ QUnit.module('basic_fields', {
list.destroy();
});
+ QUnit.test('integer field with type number option', function (assert) {
+ assert.expect(4);
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '<form string="Partners">' +
+ '<field name="int_field" options="{\'type\': \'number\'}"/>' +
+ '</form>',
+ res_id: 4,
+ translateParameters: {
+ thousands_sep: ",",
+ grouping: [3, 0],
+ },
+ });
+
+ form.$buttons.find('.o_form_button_edit').click();
+ assert.ok(form.$('.o_field_widget')[0].hasAttribute('type'),
+ 'Integer field with option type must have a type attribute.');
+ assert.strictEqual(form.$('.o_field_widget').attr('type'), 'number',
+ 'Integer field with option type must have a type attribute equals to "number".');
+
+ form.$('input').val('1234567890').trigger('input');
+ form.$buttons.find('.o_form_button_save').click();
+ form.$buttons.find('.o_form_button_edit').click();
+ assert.strictEqual(form.$('.o_field_widget').val(), '1234567890',
+ 'Integer value must be not formatted if input type is number.');
+ form.$buttons.find('.o_form_button_save').click();
+ assert.strictEqual(form.$('.o_field_widget').text(), '1,234,567,890',
+ 'Integer value must be formatted in readonly view even if the input type is number.');
+
+ form.destroy();
+ });
+
+ QUnit.test('integer field without type number option', function (assert) {
+ assert.expect(2);
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '<form string="Partners">' +
+ '<field name="int_field"/>' +
+ '</form>',
+ res_id: 4,
+ translateParameters: {
+ thousands_sep: ",",
+ grouping: [3, 0],
+ },
+ });
+
+ form.$buttons.find('.o_form_button_edit').click();
+ assert.strictEqual(form.$('.o_field_widget').attr('type'), 'text',
+ 'Integer field without option type must have a text type (default type).');
+
+ form.$('input').val('1234567890').trigger('input');
+ form.$buttons.find('.o_form_button_save').click();
+ form.$buttons.find('.o_form_button_edit').click();
+ assert.strictEqual(form.$('.o_field_widget').val(), '1,234,567,890',
+ 'Integer value must be formatted if input type isn\'t number.');
+
+ form.destroy();
+ });
+
+
QUnit.module('FieldFloatTime');
QUnit.test('float_time field in form view', function (assert) {
diff --git a/doc/reference/javascript_reference.rst b/doc/reference/javascript_reference.rst
index 14647955afa..c1f2ae9cb0d 100644
--- a/doc/reference/javascript_reference.rst
+++ b/doc/reference/javascript_reference.rst
@@ -1397,6 +1397,23 @@ order.
- Supported field types: *integer*
+ Options:
+
+ - type: setting the input type (*text* by default, can be set on *number*)
+ On edit mode, the field is rendered as an input with the HTML attribute type
+ setted on *number* (so user can benefit the native support, especially on
+ mobile). In this case, the default formatting is disabled to avoid incompability.
+
+ .. code-block:: xml
+
+ <field name="int_value" options='{"type": "number"}'/>
+
+ - step: set the step to the value up and down when the user click on buttons
+ (only for input of type number, 1 by default)
+
+ .. code-block:: xml
+
+ <field name="int_value" options='{"type": "number", "step": 100}'/>
- float (FieldFloat)
This is the default field type for fields of type *float*.
@@ -1411,6 +1428,24 @@ order.
<field name="factor" digits="[42,5]"/>
+ Options:
+
+ - type: setting the input type (*text* by default, can be set on *number*)
+ On edit mode, the field is rendered as an input with the HTML attribute type
+ setted on *number* (so user can benefit the native support, especially on
+ mobile). In this case, the default formatting is disabled to avoid incompability.
+
+ .. code-block:: xml
+
+ <field name="int_value" options='{"type": "number"}'/>
+
+ - step: set the step to the value up and down when the user click on buttons
+ (only for input of type number, 1 by default)
+
+ .. code-block:: xml
+
+ <field name="int_value" options='{"type": "number", "step": 0.1}'/>
+
- float_time (FieldFloatTime)
The goal of this widget is to display properly a float value that represents
a time interval (in hours). So, for example, 0.5 should be formatted as 0:30,