From 1944564f1cb0c3ec8a0c9d30860dac5cda09e48c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 27 Nov 2017 22:18:09 +0100 Subject: [PATCH] Use input number and toLocaleString for numeric fields To get a proper virtual keyboard on mobile, it is needed to use a input of type 'number' when editing a numeric field. But as it is not possible to ensure to display non signifiant digits, a text input is used with the toLocaleString method. Also the lang attribute is repeated on the number input because not all browsers manage to use the global as default. issue5233 review43621002 --- CHANGELOG | 1 + index.html | 2 +- src/model.js | 7 +++--- src/sao.js | 3 +++ src/view/form.js | 62 +++++++++++++++++++++++++++++++++++++++++++++--- src/view/tree.js | 2 +- 6 files changed, 69 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 5eb049df06..e2c29a4b0e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Use input number and toLocaleString for numeric fields * Show related record names for all windows * Allow to edit Many2One from tree view * Use translated values when exporting Reference and Selection fields diff --git a/index.html b/index.html index 3d0d06387d..7ec4e06a71 100644 --- a/index.html +++ b/index.html @@ -1,7 +1,7 @@ - + diff --git a/src/model.js b/src/model.js index 67fa995854..09b80fa44a 100644 --- a/src/model.js +++ b/src/model.js @@ -1710,12 +1710,13 @@ } var value = this.get(record); if (value !== null) { + var options = {}; var digits = this.digits(record, factor); if (digits) { - return (value * factor).toFixed(digits[1]); - } else { - return '' + (value * factor); + options.minimumFractionDigits = digits[1]; + options.maximumFractionDigits = digits[1]; } + return (value * factor).toLocaleString(Sao.i18n.getlang(), options); } else { return ''; } diff --git a/src/sao.js b/src/sao.js index 8fe327439d..fa77a64acf 100644 --- a/src/sao.js +++ b/src/sao.js @@ -207,6 +207,7 @@ var Sao = {}; navigator.userLanguage || 'en').replace('-', '_'); } + jQuery('html').attr('lang', lang); Sao.i18n.setLocale(lang); moment.locale(lang.slice(0, 2)); return jQuery.getJSON('locale/' + lang + '.json', function(data) { @@ -230,6 +231,7 @@ var Sao = {}; return Sao.i18n.getLocale(); }; Sao.i18n.setlang(); + Sao.i18n.locale = {}; Sao.get_preferences = function() { var session = Sao.Session.current_session; @@ -256,6 +258,7 @@ var Sao = {}; } prm.resolve(preferences); }); + Sao.i18n.locale = preferences.locale; return prm; }); }); diff --git a/src/view/form.js b/src/view/form.js index 0c4cfb56bc..8c27262c4b 100644 --- a/src/view/form.js +++ b/src/view/form.js @@ -1489,10 +1489,28 @@ function eval_pyson(value){ init: function(field_name, model, attributes) { Sao.View.Form.Integer._super.init.call(this, field_name, model, attributes); - this.input.attr('type', 'text'); this.input.attr('width', 8); + this.input_text = this.input.clone().appendTo(this.group); + this.input_text.attr('type', 'text'); + this.input.attr('type', 'number'); + this.input.attr('step', 1); + this.input.attr('lang', Sao.i18n.getlang()); this.group.css('width', ''); this.factor = Number(attributes.factor || 1); + + this.input.hide().on('focusout', function() { + this.input.hide(); + this.input_text.show(); + }.bind(this)); + this.input_text.on('focusin', function() { + if (!this.input.prop('readonly')) { + this.input_text.hide(); + this.input.show(); + window.setTimeout(function() { + this.input.focus(); + }.bind(this)); + } + }.bind(this)); }, set_value: function(record, field) { field.set_client(record, this.input.val(), undefined, this.factor); @@ -1500,14 +1518,52 @@ function eval_pyson(value){ get_client_value: function(record, field) { var value = ''; if (field) { - value = field.get_client(record, this.factor); + value = field.get(record); + if (value !== null) { + value *= this.factor; + } } return value; + }, + display: function(record, field) { + Sao.View.Form.Integer._super.display.call(this, record, field); + var value = ''; + if (field) { + value = field.get_client(record, this.factor); + } + this.input_text.val(value); + this.input_text.attr('maxlength', this.input.attr('maxlength')); + this.input_text.attr('size', this.input.attr('size')); + }, + set_readonly: function(readonly) { + Sao.View.Form.Integer._super.set_readonly.call(this, readonly); + this.input_text.prop('readonly', readonly); + }, + focus: function() { + if (!this.input.prop('readonly')) { + this.input_text.hide(); + this.input.show().focus(); + } else { + this.input_text.focus(); + } } }); Sao.View.Form.Float = Sao.class_(Sao.View.Form.Integer, { - class_: 'form-float' + class_: 'form-float', + display: function(record, field) { + var digits = 'any'; + if (record) { + digits = field.digits(record, this.factor); + if (digits) { + digits = digits[1]; + } else { + digits = 'any'; + } + } + this.input.attr('step', Math.pow(10, -digits)); + Sao.View.Form.Float._super.display.call(this, record, field); + } }); Sao.View.Form.Selection = Sao.class_(Sao.View.Form.Widget, { diff --git a/src/view/tree.js b/src/view/tree.js index 1584207b61..a4c1de2942 100644 --- a/src/view/tree.js +++ b/src/view/tree.js @@ -1240,7 +1240,7 @@ }.bind(this), 0); }.bind(this)); } else if (event_.which == Sao.common.ESC_KEYCODE) { - this.get_static_el().show(); + this.get_static_el().show().find('[tabindex=0]').focus(); current_td = this.get_active_td(); current_td.on('click keypress', {column: this.edited_column, td: current_td},