From 77d005c52ba1d958039536be5bc1bc5124536a44 Mon Sep 17 00:00:00 2001 From: oihane Date: Thu, 4 Jun 2015 19:24:48 +0200 Subject: [PATCH 1/5] New module --- web_decimal_numpad_dot/README.rst | 14 + web_decimal_numpad_dot/__init__.py | 4 + web_decimal_numpad_dot/__openerp__.py | 40 ++ .../static/src/js/formats.js | 376 ++++++++++++++++++ .../static/src/js/numpad_dot.js | 23 ++ .../views/web_decimal_numpad_dot.xml | 10 + 6 files changed, 467 insertions(+) create mode 100644 web_decimal_numpad_dot/README.rst create mode 100644 web_decimal_numpad_dot/__init__.py create mode 100644 web_decimal_numpad_dot/__openerp__.py create mode 100644 web_decimal_numpad_dot/static/src/js/formats.js create mode 100644 web_decimal_numpad_dot/static/src/js/numpad_dot.js create mode 100644 web_decimal_numpad_dot/views/web_decimal_numpad_dot.xml diff --git a/web_decimal_numpad_dot/README.rst b/web_decimal_numpad_dot/README.rst new file mode 100644 index 00000000..f0a463a2 --- /dev/null +++ b/web_decimal_numpad_dot/README.rst @@ -0,0 +1,14 @@ +Web - Numpad Dot as decimal separator +===================================== + + + +Credits +======= + +Contributors +------------ + +* Oihane Crucelaegui +* Pedro M. Baeza +* Ana Juaristi diff --git a/web_decimal_numpad_dot/__init__.py b/web_decimal_numpad_dot/__init__.py new file mode 100644 index 00000000..ee9e0cf6 --- /dev/null +++ b/web_decimal_numpad_dot/__init__.py @@ -0,0 +1,4 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# For copyright and license notices, see __openerp__.py file in root directory +############################################################################## diff --git a/web_decimal_numpad_dot/__openerp__.py b/web_decimal_numpad_dot/__openerp__.py new file mode 100644 index 00000000..9e6051de --- /dev/null +++ b/web_decimal_numpad_dot/__openerp__.py @@ -0,0 +1,40 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see http://www.gnu.org/licenses/. +# +############################################################################## + +{ + "name": "Web - Numpad Dot as decimal separator", + "version": "1.0", + "depends": [ + "web", + ], + "author": "OdooMRP team, " + "AvanzOSC, " + "Serv. Tecnol. Avanzados - Pedro M. Baeza", + "website": "http://www.odoomrp.com", + "contributors": [ + "Oihane Crucelaegui ", + "Pedro M. Baeza ", + "Ana Juaristi ", + ], + "category": "Custom Module", + "summary": "", + "data": [ + "views/web_decimal_numpad_dot.xml", + ], + "installable": True, +} diff --git a/web_decimal_numpad_dot/static/src/js/formats.js b/web_decimal_numpad_dot/static/src/js/formats.js new file mode 100644 index 00000000..22131d4d --- /dev/null +++ b/web_decimal_numpad_dot/static/src/js/formats.js @@ -0,0 +1,376 @@ + +(function() { + +var instance = openerp; +openerp.web.formats = {}; + +var _t = instance.web._t; + +/** + * Intersperses ``separator`` in ``str`` at the positions indicated by + * ``indices``. + * + * ``indices`` is an array of relative offsets (from the previous insertion + * position, starting from the end of the string) at which to insert + * ``separator``. + * + * There are two special values: + * + * ``-1`` + * indicates the insertion should end now + * ``0`` + * indicates that the previous section pattern should be repeated (until all + * of ``str`` is consumed) + * + * @param {String} str + * @param {Array} indices + * @param {String} separator + * @returns {String} + */ +instance.web.intersperse = function (str, indices, separator) { + separator = separator || ''; + var result = [], last = str.length; + + for(var i=0; i stop + break; + } else if (section === 0) { + // repeat previous section forever + //noinspection AssignmentToForLoopParameterJS + section = indices[--i]; + } + result.push(str.substring(last-section, last)); + last -= section; + } + + var s = str.substring(0, last); + if (s) { result.push(s); } + return result.reverse().join(separator); +}; +/** + * Insert "thousands" separators in the provided number (which is actually + * a string) + * + * @param {String} num + * @returns {String} + */ +instance.web.insert_thousand_seps = function (num) { + var negative = num[0] === '-'; + num = (negative ? num.slice(1) : num); + return (negative ? '-' : '') + instance.web.intersperse( + num, _t.database.parameters.grouping, _t.database.parameters.thousands_sep); +}; + +/** + * removes literal (non-format) text from a date or time pattern, as datejs can + * not deal with literal text in format strings (whatever the format), whereas + * strftime allows for literal characters + * + * @param {String} value original format + */ +instance.web.strip_raw_chars = function (value) { + var isletter = /[a-zA-Z]/, output = []; + for(var index=0; index < value.length; ++index) { + var character = value[index]; + if(isletter.test(character) && (index === 0 || value[index-1] !== '%')) { + continue; + } + output.push(character); + } + return output.join(''); +}; +var normalize_format = function (format) { + return Date.normalizeFormat(instance.web.strip_raw_chars(format)); +}; + +/** + * Check with a scary heuristic if the value is a bin_size or not. + * If not, compute an approximate size out of the base64 encoded string. + * + * @param {String} value original format + */ +instance.web.binary_to_binsize = function (value) { + if (!value) { + return instance.web.human_size(0); + } + if (value.substr(0, 10).indexOf(' ') == -1) { + // Computing approximate size out of base64 encoded string + // http://en.wikipedia.org/wiki/Base64#MIME + return instance.web.human_size(value.length / 1.37); + } else { + // already bin_size + return value; + } +}; + +/** + * Returns a human readable size + * + * @param {Number} numner of bytes + */ +instance.web.human_size = function(size) { + var units = _t("Bytes,Kb,Mb,Gb,Tb,Pb,Eb,Zb,Yb").split(','); + var i = 0; + while (size >= 1024) { + size /= 1024; + ++i; + } + return size.toFixed(2) + ' ' + units[i]; +}; + +/** + * Formats a single atomic value based on a field descriptor + * + * @param {Object} value read from OpenERP + * @param {Object} descriptor union of orm field and view field + * @param {Object} [descriptor.widget] widget to use to display the value + * @param {Object} descriptor.type fallback if no widget is provided, or if the provided widget is unknown + * @param {Object} [descriptor.digits] used for the formatting of floats + * @param {String} [value_if_empty=''] returned if the ``value`` argument is considered empty + */ +instance.web.format_value = function (value, descriptor, value_if_empty) { + // If NaN value, display as with a `false` (empty cell) + if (typeof value === 'number' && isNaN(value)) { + value = false; + } + //noinspection FallthroughInSwitchStatementJS + switch (value) { + case '': + if (descriptor.type === 'char' || descriptor.type === 'text') { + return ''; + } + console.warn('Field', descriptor, 'had an empty string as value, treating as false...'); + return value_if_empty === undefined ? '' : value_if_empty; + case false: + case undefined: + case Infinity: + case -Infinity: + return value_if_empty === undefined ? '' : value_if_empty; + } + var l10n = _t.database.parameters; + switch (descriptor.widget || descriptor.type || (descriptor.field && descriptor.field.type)) { + case 'id': + return value.toString(); + case 'integer': + return instance.web.insert_thousand_seps( + _.str.sprintf('%d', value)); + case 'float': + var digits = descriptor.digits ? descriptor.digits : [69,2]; + digits = typeof digits === "string" ? py.eval(digits) : digits; + var precision = digits[1]; + var formatted = _.str.sprintf('%.' + precision + 'f', value).split('.'); + formatted[0] = instance.web.insert_thousand_seps(formatted[0]); + return formatted.join(l10n.decimal_point); + case 'float_time': + var pattern = '%02d:%02d'; + if (value < 0) { + value = Math.abs(value); + pattern = '-' + pattern; + } + var hour = Math.floor(value); + var min = Math.round((value % 1) * 60); + if (min == 60){ + min = 0; + hour = hour + 1; + } + return _.str.sprintf(pattern, hour, min); + case 'many2one': + // name_get value format + return value[1] ? value[1].split("\n")[0] : value[1]; + case 'one2many': + case 'many2many': + if (typeof value === 'string') { + return value; + } + return _.str.sprintf(_t("(%d records)"), value.length); + case 'datetime': + if (typeof(value) == "string") + value = instance.web.auto_str_to_date(value); + + return value.toString(normalize_format(l10n.date_format) + + ' ' + normalize_format(l10n.time_format)); + case 'date': + if (typeof(value) == "string") + value = instance.web.auto_str_to_date(value); + return value.toString(normalize_format(l10n.date_format)); + case 'time': + if (typeof(value) == "string") + value = instance.web.auto_str_to_date(value); + return value.toString(normalize_format(l10n.time_format)); + case 'selection': case 'statusbar': + // Each choice is [value, label] + if(_.isArray(value)) { + return value[1]; + } + var result = _(descriptor.selection).detect(function (choice) { + return choice[0] === value; + }); + if (result) { return result[1]; } + return; + default: + return value; + } +}; + +instance.web.parse_value = function (value, descriptor, value_if_empty) { + var date_pattern = normalize_format(_t.database.parameters.date_format), + time_pattern = normalize_format(_t.database.parameters.time_format); + switch (value) { + case false: + case "": + return value_if_empty === undefined ? false : value_if_empty; + } + var tmp; + switch (descriptor.widget || descriptor.type || (descriptor.field && descriptor.field.type)) { + case 'integer': + do { + tmp = value; + value = value.replace(instance.web._t.database.parameters.thousands_sep, ""); + } while(tmp !== value); + tmp = Number(value); + // do not accept not numbers or float values + if (isNaN(tmp) || tmp % 1) + throw new Error(_.str.sprintf(_t("'%s' is not a correct integer"), value)); + return tmp; + case 'float': + tmp = Number(value); + if (!isNaN(tmp)) + return tmp; + + var tmp2 = value; + do { + tmp = tmp2; + tmp2 = tmp.replace(instance.web._t.database.parameters.thousands_sep, ""); + } while(tmp !== tmp2); + var reformatted_value = tmp.replace(instance.web._t.database.parameters.decimal_point, "."); + var parsed = Number(reformatted_value); + if (isNaN(parsed)) + throw new Error(_.str.sprintf(_t("'%s' is not a correct float"), value)); + return parsed; + case 'float_time': + var factor = 1; + if (value[0] === '-') { + value = value.slice(1); + factor = -1; + } + var float_time_pair = value.split(":"); + if (float_time_pair.length != 2) + return factor * instance.web.parse_value(value, {type: "float"}); + var hours = instance.web.parse_value(float_time_pair[0], {type: "integer"}); + var minutes = instance.web.parse_value(float_time_pair[1], {type: "integer"}); + return factor * (hours + (minutes / 60)); + case 'progressbar': + return instance.web.parse_value(value, {type: "float"}); + case 'datetime': + var datetime = Date.parseExact( + value, (date_pattern + ' ' + time_pattern)); + if (datetime !== null) + return instance.web.datetime_to_str(datetime); + datetime = Date.parseExact(value, (date_pattern)); + if (datetime !== null) + return instance.web.datetime_to_str(datetime); + var leading_zero_value = value.toString().replace(/\d+/g, function(m){ + return m.length === 1 ? "0" + m : m ; + }); + datetime = Date.parseExact(leading_zero_value, (date_pattern + ' ' + time_pattern)); + if (datetime !== null) + return instance.web.datetime_to_str(datetime); + datetime = Date.parseExact(leading_zero_value, (date_pattern)); + if (datetime !== null) + return instance.web.datetime_to_str(datetime); + datetime = Date.parse(value); + if (datetime !== null) + return instance.web.datetime_to_str(datetime); + throw new Error(_.str.sprintf(_t("'%s' is not a correct datetime"), value)); + case 'date': + var date = Date.parseExact(value, date_pattern); + if (date !== null) + return instance.web.date_to_str(date); + date = Date.parseExact(value.toString().replace(/\d+/g, function(m){ + return m.length === 1 ? "0" + m : m ; + }), date_pattern); + if (date !== null) + return instance.web.date_to_str(date); + date = Date.parse(value); + if (date !== null) + return instance.web.date_to_str(date); + throw new Error(_.str.sprintf(_t("'%s' is not a correct date"), value)); + case 'time': + var time = Date.parseExact(value, time_pattern); + if (time !== null) + return instance.web.time_to_str(time); + time = Date.parse(value); + if (time !== null) + return instance.web.time_to_str(time); + throw new Error(_.str.sprintf(_t("'%s' is not a correct time"), value)); + } + return value; +}; + +instance.web.auto_str_to_date = function(value, type) { + try { + return instance.web.str_to_datetime(value); + } catch(e) {} + try { + return instance.web.str_to_date(value); + } catch(e) {} + try { + return instance.web.str_to_time(value); + } catch(e) {} + throw new Error(_.str.sprintf(_t("'%s' is not a correct date, datetime nor time"), value)); +}; + +instance.web.auto_date_to_str = function(value, type) { + switch(type) { + case 'datetime': + return instance.web.datetime_to_str(value); + case 'date': + return instance.web.date_to_str(value); + case 'time': + return instance.web.time_to_str(value); + default: + throw new Error(_.str.sprintf(_t("'%s' is not convertible to date, datetime nor time"), type)); + } +}; + +/** + * performs a half up rounding with arbitrary precision, correcting for float loss of precision + * See the corresponding float_round() in server/tools/float_utils.py for more info + * @param {Number} the value to be rounded + * @param {Number} a precision parameter. eg: 0.01 rounds to two digits. + */ +instance.web.round_precision = function(value, precision){ + if (!value) { + return 0; + } else if (!precision || precision < 0) { + precision = 1; + } + var normalized_value = value / precision; + var epsilon_magnitude = Math.log(Math.abs(normalized_value))/Math.log(2); + var epsilon = Math.pow(2, epsilon_magnitude - 53); + normalized_value += normalized_value >= 0 ? epsilon : -epsilon; + var rounded_value = Math.round(normalized_value); + return rounded_value * precision; +}; + +/** + * performs a half up rounding with a fixed amount of decimals, correcting for float loss of precision + * See the corresponding float_round() in server/tools/float_utils.py for more info + * @param {Number} the value to be rounded + * @param {Number} the number of decimals. eg: round_decimals(3.141592,2) -> 3.14 + */ +instance.web.round_decimals = function(value, decimals){ + return instance.web.round_precision(value, Math.pow(10,-decimals)); +}; + +instance.web.float_is_zero = function(value, decimals){ + epsilon = Math.pow(10, -decimals); + return Math.abs(instance.web.round_precision(value, epsilon)) < epsilon; +}; + +})(); diff --git a/web_decimal_numpad_dot/static/src/js/numpad_dot.js b/web_decimal_numpad_dot/static/src/js/numpad_dot.js new file mode 100644 index 00000000..ec9c34cf --- /dev/null +++ b/web_decimal_numpad_dot/static/src/js/numpad_dot.js @@ -0,0 +1,23 @@ +(function() { + +var instance = openerp; + +instance.web.form.FieldFloat = instance.web.form.FieldChar.extend({ + is_field_number: true, + widget_class: 'oe_form_field_float', + events: { + "keyup": "floatKeyup", + }, + floatKeyup: function(e){ + var code = e.which ? e.which : e.keyCode; + + if (code === 110){ + var input = this.$("input").val(); + input = input.substr(0, input.length -1); + input += instance.web._t.database.parameters.decimal_point; + this.set("value", input); + } + }, +}); + +})(); diff --git a/web_decimal_numpad_dot/views/web_decimal_numpad_dot.xml b/web_decimal_numpad_dot/views/web_decimal_numpad_dot.xml new file mode 100644 index 00000000..3345c5dc --- /dev/null +++ b/web_decimal_numpad_dot/views/web_decimal_numpad_dot.xml @@ -0,0 +1,10 @@ + + + + + + From 1419fdb98cce994ad74a264a6b9281675d8c8847 Mon Sep 17 00:00:00 2001 From: oihane Date: Fri, 13 Nov 2015 09:18:09 +0100 Subject: [PATCH 2/5] web_decimal_numpad_dot: now changes . for , in floating numbers --- .../static/src/js/numpad_dot.js | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/web_decimal_numpad_dot/static/src/js/numpad_dot.js b/web_decimal_numpad_dot/static/src/js/numpad_dot.js index ec9c34cf..621bf89c 100644 --- a/web_decimal_numpad_dot/static/src/js/numpad_dot.js +++ b/web_decimal_numpad_dot/static/src/js/numpad_dot.js @@ -1,23 +1,20 @@ (function() { -var instance = openerp; - -instance.web.form.FieldFloat = instance.web.form.FieldChar.extend({ - is_field_number: true, - widget_class: 'oe_form_field_float', - events: { - "keyup": "floatKeyup", - }, - floatKeyup: function(e){ - var code = e.which ? e.which : e.keyCode; - - if (code === 110){ - var input = this.$("input").val(); - input = input.substr(0, input.length -1); - input += instance.web._t.database.parameters.decimal_point; - this.set("value", input); - } - }, -}); + var instance = openerp; + instance.web.form.FieldFloat = instance.web.form.FieldChar.extend({ + is_field_number: true, + widget_class: 'oe_form_field_float', + events: { + "keypress": "floatKeypress", + }, + floatKeypress: function(e){ + if(e.keyCode == '46' || e.charCode == '46'){ + //Cancel the keypress + e.preventDefault(); + // Add the comma to the value of the input field + this.$("input").val(this.$("input").val() + ','); + } + }, + }); })(); From 3a9584851157d796d773ba437e6a5ab172fbd888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20Casti=C3=B1eira=20Saavedra?= Date: Tue, 15 Dec 2015 11:53:05 +0100 Subject: [PATCH 3/5] web_decimal_numpad_dot: fixed float widget not working properly --- web_decimal_numpad_dot/static/src/js/numpad_dot.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/web_decimal_numpad_dot/static/src/js/numpad_dot.js b/web_decimal_numpad_dot/static/src/js/numpad_dot.js index 621bf89c..55f9917c 100644 --- a/web_decimal_numpad_dot/static/src/js/numpad_dot.js +++ b/web_decimal_numpad_dot/static/src/js/numpad_dot.js @@ -2,11 +2,13 @@ var instance = openerp; - instance.web.form.FieldFloat = instance.web.form.FieldChar.extend({ - is_field_number: true, - widget_class: 'oe_form_field_float', - events: { - "keypress": "floatKeypress", + instance.web.form.FieldFloat = instance.web.form.FieldFloat.extend({ + render_value: function() { + var self = this; + this._super(); + if (!this.get('readonly')){ + this.$el.find('input').on('keypress', this.floatKeypress.bind(this)); + } }, floatKeypress: function(e){ if(e.keyCode == '46' || e.charCode == '46'){ @@ -14,7 +16,7 @@ e.preventDefault(); // Add the comma to the value of the input field this.$("input").val(this.$("input").val() + ','); - } + } }, }); })(); From 180d33ffbe83465737d0939ea567b4d6f780318f Mon Sep 17 00:00:00 2001 From: Roel Adriaans Date: Wed, 16 Dec 2015 10:45:30 +0100 Subject: [PATCH 4/5] web_decimal_numpad_dot: use the decimal_point defined in user language --- web_decimal_numpad_dot/static/src/js/numpad_dot.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/web_decimal_numpad_dot/static/src/js/numpad_dot.js b/web_decimal_numpad_dot/static/src/js/numpad_dot.js index 55f9917c..560ce048 100644 --- a/web_decimal_numpad_dot/static/src/js/numpad_dot.js +++ b/web_decimal_numpad_dot/static/src/js/numpad_dot.js @@ -11,12 +11,18 @@ } }, floatKeypress: function(e){ - if(e.keyCode == '46' || e.charCode == '46'){ - //Cancel the keypress + if (e.keyCode == '46' || e.charCode == '46') { + // Cancel the keypress e.preventDefault(); // Add the comma to the value of the input field - this.$("input").val(this.$("input").val() + ','); + this.$("input").val(this.$("input").val() + instance.web._t.database.parameters.decimal_point); } + else if (e.keyCode == '44' || e.charCode == '44') { + // Cancel the keypress + e.preventDefault(); + // Add the comma to the value of the input field + this.$("input").val(this.$("input").val() + instance.web._t.database.parameters.thousands_sep); + } }, }); })(); From 8196fc6be8361d6af82cf7e8bd2cbc6536a280e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20Casti=C3=B1eira=20Saavedra?= Date: Wed, 10 Apr 2019 13:48:14 +0200 Subject: [PATCH 5/5] [FIX+IMP] web_decimal_numpad_dot: Fixes in Comunitea branch + OCA adaptation --- web_decimal_numpad_dot/README.rst | 1 + web_decimal_numpad_dot/__openerp__.py | 18 +- .../static/src/js/formats.js | 376 ------------------ .../static/src/js/numpad_dot.js | 43 +- 4 files changed, 28 insertions(+), 410 deletions(-) delete mode 100644 web_decimal_numpad_dot/static/src/js/formats.js diff --git a/web_decimal_numpad_dot/README.rst b/web_decimal_numpad_dot/README.rst index f0a463a2..c41cb450 100644 --- a/web_decimal_numpad_dot/README.rst +++ b/web_decimal_numpad_dot/README.rst @@ -12,3 +12,4 @@ Contributors * Oihane Crucelaegui * Pedro M. Baeza * Ana Juaristi +* Omar Castiñeira Saavedra diff --git a/web_decimal_numpad_dot/__openerp__.py b/web_decimal_numpad_dot/__openerp__.py index 9e6051de..90b7e367 100644 --- a/web_decimal_numpad_dot/__openerp__.py +++ b/web_decimal_numpad_dot/__openerp__.py @@ -18,21 +18,17 @@ { "name": "Web - Numpad Dot as decimal separator", - "version": "1.0", + "version": "8.0.1.0.0", "depends": [ "web", ], - "author": "OdooMRP team, " - "AvanzOSC, " - "Serv. Tecnol. Avanzados - Pedro M. Baeza", - "website": "http://www.odoomrp.com", - "contributors": [ - "Oihane Crucelaegui ", - "Pedro M. Baeza ", - "Ana Juaristi ", - ], + "author": "AvanzOSC," + "Tecnativa," + "Comunitea Servicios Tecnológicos," + "Odoo Community Association (OCA)", + "website": "http://github.com/OCA/web", "category": "Custom Module", - "summary": "", + "license": "AGPL-3", "data": [ "views/web_decimal_numpad_dot.xml", ], diff --git a/web_decimal_numpad_dot/static/src/js/formats.js b/web_decimal_numpad_dot/static/src/js/formats.js deleted file mode 100644 index 22131d4d..00000000 --- a/web_decimal_numpad_dot/static/src/js/formats.js +++ /dev/null @@ -1,376 +0,0 @@ - -(function() { - -var instance = openerp; -openerp.web.formats = {}; - -var _t = instance.web._t; - -/** - * Intersperses ``separator`` in ``str`` at the positions indicated by - * ``indices``. - * - * ``indices`` is an array of relative offsets (from the previous insertion - * position, starting from the end of the string) at which to insert - * ``separator``. - * - * There are two special values: - * - * ``-1`` - * indicates the insertion should end now - * ``0`` - * indicates that the previous section pattern should be repeated (until all - * of ``str`` is consumed) - * - * @param {String} str - * @param {Array} indices - * @param {String} separator - * @returns {String} - */ -instance.web.intersperse = function (str, indices, separator) { - separator = separator || ''; - var result = [], last = str.length; - - for(var i=0; i stop - break; - } else if (section === 0) { - // repeat previous section forever - //noinspection AssignmentToForLoopParameterJS - section = indices[--i]; - } - result.push(str.substring(last-section, last)); - last -= section; - } - - var s = str.substring(0, last); - if (s) { result.push(s); } - return result.reverse().join(separator); -}; -/** - * Insert "thousands" separators in the provided number (which is actually - * a string) - * - * @param {String} num - * @returns {String} - */ -instance.web.insert_thousand_seps = function (num) { - var negative = num[0] === '-'; - num = (negative ? num.slice(1) : num); - return (negative ? '-' : '') + instance.web.intersperse( - num, _t.database.parameters.grouping, _t.database.parameters.thousands_sep); -}; - -/** - * removes literal (non-format) text from a date or time pattern, as datejs can - * not deal with literal text in format strings (whatever the format), whereas - * strftime allows for literal characters - * - * @param {String} value original format - */ -instance.web.strip_raw_chars = function (value) { - var isletter = /[a-zA-Z]/, output = []; - for(var index=0; index < value.length; ++index) { - var character = value[index]; - if(isletter.test(character) && (index === 0 || value[index-1] !== '%')) { - continue; - } - output.push(character); - } - return output.join(''); -}; -var normalize_format = function (format) { - return Date.normalizeFormat(instance.web.strip_raw_chars(format)); -}; - -/** - * Check with a scary heuristic if the value is a bin_size or not. - * If not, compute an approximate size out of the base64 encoded string. - * - * @param {String} value original format - */ -instance.web.binary_to_binsize = function (value) { - if (!value) { - return instance.web.human_size(0); - } - if (value.substr(0, 10).indexOf(' ') == -1) { - // Computing approximate size out of base64 encoded string - // http://en.wikipedia.org/wiki/Base64#MIME - return instance.web.human_size(value.length / 1.37); - } else { - // already bin_size - return value; - } -}; - -/** - * Returns a human readable size - * - * @param {Number} numner of bytes - */ -instance.web.human_size = function(size) { - var units = _t("Bytes,Kb,Mb,Gb,Tb,Pb,Eb,Zb,Yb").split(','); - var i = 0; - while (size >= 1024) { - size /= 1024; - ++i; - } - return size.toFixed(2) + ' ' + units[i]; -}; - -/** - * Formats a single atomic value based on a field descriptor - * - * @param {Object} value read from OpenERP - * @param {Object} descriptor union of orm field and view field - * @param {Object} [descriptor.widget] widget to use to display the value - * @param {Object} descriptor.type fallback if no widget is provided, or if the provided widget is unknown - * @param {Object} [descriptor.digits] used for the formatting of floats - * @param {String} [value_if_empty=''] returned if the ``value`` argument is considered empty - */ -instance.web.format_value = function (value, descriptor, value_if_empty) { - // If NaN value, display as with a `false` (empty cell) - if (typeof value === 'number' && isNaN(value)) { - value = false; - } - //noinspection FallthroughInSwitchStatementJS - switch (value) { - case '': - if (descriptor.type === 'char' || descriptor.type === 'text') { - return ''; - } - console.warn('Field', descriptor, 'had an empty string as value, treating as false...'); - return value_if_empty === undefined ? '' : value_if_empty; - case false: - case undefined: - case Infinity: - case -Infinity: - return value_if_empty === undefined ? '' : value_if_empty; - } - var l10n = _t.database.parameters; - switch (descriptor.widget || descriptor.type || (descriptor.field && descriptor.field.type)) { - case 'id': - return value.toString(); - case 'integer': - return instance.web.insert_thousand_seps( - _.str.sprintf('%d', value)); - case 'float': - var digits = descriptor.digits ? descriptor.digits : [69,2]; - digits = typeof digits === "string" ? py.eval(digits) : digits; - var precision = digits[1]; - var formatted = _.str.sprintf('%.' + precision + 'f', value).split('.'); - formatted[0] = instance.web.insert_thousand_seps(formatted[0]); - return formatted.join(l10n.decimal_point); - case 'float_time': - var pattern = '%02d:%02d'; - if (value < 0) { - value = Math.abs(value); - pattern = '-' + pattern; - } - var hour = Math.floor(value); - var min = Math.round((value % 1) * 60); - if (min == 60){ - min = 0; - hour = hour + 1; - } - return _.str.sprintf(pattern, hour, min); - case 'many2one': - // name_get value format - return value[1] ? value[1].split("\n")[0] : value[1]; - case 'one2many': - case 'many2many': - if (typeof value === 'string') { - return value; - } - return _.str.sprintf(_t("(%d records)"), value.length); - case 'datetime': - if (typeof(value) == "string") - value = instance.web.auto_str_to_date(value); - - return value.toString(normalize_format(l10n.date_format) - + ' ' + normalize_format(l10n.time_format)); - case 'date': - if (typeof(value) == "string") - value = instance.web.auto_str_to_date(value); - return value.toString(normalize_format(l10n.date_format)); - case 'time': - if (typeof(value) == "string") - value = instance.web.auto_str_to_date(value); - return value.toString(normalize_format(l10n.time_format)); - case 'selection': case 'statusbar': - // Each choice is [value, label] - if(_.isArray(value)) { - return value[1]; - } - var result = _(descriptor.selection).detect(function (choice) { - return choice[0] === value; - }); - if (result) { return result[1]; } - return; - default: - return value; - } -}; - -instance.web.parse_value = function (value, descriptor, value_if_empty) { - var date_pattern = normalize_format(_t.database.parameters.date_format), - time_pattern = normalize_format(_t.database.parameters.time_format); - switch (value) { - case false: - case "": - return value_if_empty === undefined ? false : value_if_empty; - } - var tmp; - switch (descriptor.widget || descriptor.type || (descriptor.field && descriptor.field.type)) { - case 'integer': - do { - tmp = value; - value = value.replace(instance.web._t.database.parameters.thousands_sep, ""); - } while(tmp !== value); - tmp = Number(value); - // do not accept not numbers or float values - if (isNaN(tmp) || tmp % 1) - throw new Error(_.str.sprintf(_t("'%s' is not a correct integer"), value)); - return tmp; - case 'float': - tmp = Number(value); - if (!isNaN(tmp)) - return tmp; - - var tmp2 = value; - do { - tmp = tmp2; - tmp2 = tmp.replace(instance.web._t.database.parameters.thousands_sep, ""); - } while(tmp !== tmp2); - var reformatted_value = tmp.replace(instance.web._t.database.parameters.decimal_point, "."); - var parsed = Number(reformatted_value); - if (isNaN(parsed)) - throw new Error(_.str.sprintf(_t("'%s' is not a correct float"), value)); - return parsed; - case 'float_time': - var factor = 1; - if (value[0] === '-') { - value = value.slice(1); - factor = -1; - } - var float_time_pair = value.split(":"); - if (float_time_pair.length != 2) - return factor * instance.web.parse_value(value, {type: "float"}); - var hours = instance.web.parse_value(float_time_pair[0], {type: "integer"}); - var minutes = instance.web.parse_value(float_time_pair[1], {type: "integer"}); - return factor * (hours + (minutes / 60)); - case 'progressbar': - return instance.web.parse_value(value, {type: "float"}); - case 'datetime': - var datetime = Date.parseExact( - value, (date_pattern + ' ' + time_pattern)); - if (datetime !== null) - return instance.web.datetime_to_str(datetime); - datetime = Date.parseExact(value, (date_pattern)); - if (datetime !== null) - return instance.web.datetime_to_str(datetime); - var leading_zero_value = value.toString().replace(/\d+/g, function(m){ - return m.length === 1 ? "0" + m : m ; - }); - datetime = Date.parseExact(leading_zero_value, (date_pattern + ' ' + time_pattern)); - if (datetime !== null) - return instance.web.datetime_to_str(datetime); - datetime = Date.parseExact(leading_zero_value, (date_pattern)); - if (datetime !== null) - return instance.web.datetime_to_str(datetime); - datetime = Date.parse(value); - if (datetime !== null) - return instance.web.datetime_to_str(datetime); - throw new Error(_.str.sprintf(_t("'%s' is not a correct datetime"), value)); - case 'date': - var date = Date.parseExact(value, date_pattern); - if (date !== null) - return instance.web.date_to_str(date); - date = Date.parseExact(value.toString().replace(/\d+/g, function(m){ - return m.length === 1 ? "0" + m : m ; - }), date_pattern); - if (date !== null) - return instance.web.date_to_str(date); - date = Date.parse(value); - if (date !== null) - return instance.web.date_to_str(date); - throw new Error(_.str.sprintf(_t("'%s' is not a correct date"), value)); - case 'time': - var time = Date.parseExact(value, time_pattern); - if (time !== null) - return instance.web.time_to_str(time); - time = Date.parse(value); - if (time !== null) - return instance.web.time_to_str(time); - throw new Error(_.str.sprintf(_t("'%s' is not a correct time"), value)); - } - return value; -}; - -instance.web.auto_str_to_date = function(value, type) { - try { - return instance.web.str_to_datetime(value); - } catch(e) {} - try { - return instance.web.str_to_date(value); - } catch(e) {} - try { - return instance.web.str_to_time(value); - } catch(e) {} - throw new Error(_.str.sprintf(_t("'%s' is not a correct date, datetime nor time"), value)); -}; - -instance.web.auto_date_to_str = function(value, type) { - switch(type) { - case 'datetime': - return instance.web.datetime_to_str(value); - case 'date': - return instance.web.date_to_str(value); - case 'time': - return instance.web.time_to_str(value); - default: - throw new Error(_.str.sprintf(_t("'%s' is not convertible to date, datetime nor time"), type)); - } -}; - -/** - * performs a half up rounding with arbitrary precision, correcting for float loss of precision - * See the corresponding float_round() in server/tools/float_utils.py for more info - * @param {Number} the value to be rounded - * @param {Number} a precision parameter. eg: 0.01 rounds to two digits. - */ -instance.web.round_precision = function(value, precision){ - if (!value) { - return 0; - } else if (!precision || precision < 0) { - precision = 1; - } - var normalized_value = value / precision; - var epsilon_magnitude = Math.log(Math.abs(normalized_value))/Math.log(2); - var epsilon = Math.pow(2, epsilon_magnitude - 53); - normalized_value += normalized_value >= 0 ? epsilon : -epsilon; - var rounded_value = Math.round(normalized_value); - return rounded_value * precision; -}; - -/** - * performs a half up rounding with a fixed amount of decimals, correcting for float loss of precision - * See the corresponding float_round() in server/tools/float_utils.py for more info - * @param {Number} the value to be rounded - * @param {Number} the number of decimals. eg: round_decimals(3.141592,2) -> 3.14 - */ -instance.web.round_decimals = function(value, decimals){ - return instance.web.round_precision(value, Math.pow(10,-decimals)); -}; - -instance.web.float_is_zero = function(value, decimals){ - epsilon = Math.pow(10, -decimals); - return Math.abs(instance.web.round_precision(value, epsilon)) < epsilon; -}; - -})(); diff --git a/web_decimal_numpad_dot/static/src/js/numpad_dot.js b/web_decimal_numpad_dot/static/src/js/numpad_dot.js index 560ce048..1e5a7e60 100644 --- a/web_decimal_numpad_dot/static/src/js/numpad_dot.js +++ b/web_decimal_numpad_dot/static/src/js/numpad_dot.js @@ -1,28 +1,25 @@ (function() { - var instance = openerp; +var instance = openerp; - instance.web.form.FieldFloat = instance.web.form.FieldFloat.extend({ - render_value: function() { - var self = this; - this._super(); - if (!this.get('readonly')){ - this.$el.find('input').on('keypress', this.floatKeypress.bind(this)); +instance.web.form.FieldFloat = instance.web.form.FieldFloat.extend({ + render_value: function() { + var self = this; + this._super(); + if (!this.get('readonly')){ + this.$el.find('input').on('keypress', this.floatKeypress.bind(this)); + } + }, + floatKeypress: function(e){ + if((e.keyCode == '46' || e.charCode == '46') && instance.web._t.database.parameters.decimal_point == ','){ + //Cancel the keypress + e.preventDefault(); + // Add the comma to the value of the input field + if(this.el.firstElementChild.value.slice(-1)!=','){ + this.$("input").val(this.$("input").val() + ','); } - }, - floatKeypress: function(e){ - if (e.keyCode == '46' || e.charCode == '46') { - // Cancel the keypress - e.preventDefault(); - // Add the comma to the value of the input field - this.$("input").val(this.$("input").val() + instance.web._t.database.parameters.decimal_point); - } - else if (e.keyCode == '44' || e.charCode == '44') { - // Cancel the keypress - e.preventDefault(); - // Add the comma to the value of the input field - this.$("input").val(this.$("input").val() + instance.web._t.database.parameters.thousands_sep); - } - }, - }); + } + }, +}); + })();