mirror of https://github.com/OCA/web.git
[MIG] web_decimal_numpad_dot: Migration to 10.0
parent
477c7c0c6a
commit
0c0e7fc4dc
|
@ -1,7 +1,31 @@
|
||||||
Web - Numpad Dot as decimal separator
|
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
|
||||||
=====================================
|
:target: http://www.gnu.org/licenses/agpl
|
||||||
|
:alt: License: AGPL-3
|
||||||
|
|
||||||
|
===============================
|
||||||
|
Numpad Dot as decimal separator
|
||||||
|
===============================
|
||||||
|
|
||||||
|
Allows using numpad dot to enter period decimal separator even in localizations
|
||||||
|
where comma is used instead of period.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
=====
|
||||||
|
|
||||||
|
Whenever on a float or monetary input field pressing numpad dot produces the
|
||||||
|
proper decimal separator for the active localization.
|
||||||
|
|
||||||
|
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
|
||||||
|
:alt: Try me on Runbot
|
||||||
|
:target: https://runbot.odoo-community.org/runbot/web/162
|
||||||
|
|
||||||
|
Bug Tracker
|
||||||
|
===========
|
||||||
|
|
||||||
|
Bugs are tracked on `GitHub Issues
|
||||||
|
<https://github.com/OCA/web/issues>`_. In case of trouble, please
|
||||||
|
check there if your issue has already been reported. If you spotted it first,
|
||||||
|
help us smash it by providing detailed and welcomed feedback.
|
||||||
|
|
||||||
Credits
|
Credits
|
||||||
=======
|
=======
|
||||||
|
@ -10,5 +34,24 @@ Contributors
|
||||||
------------
|
------------
|
||||||
|
|
||||||
* Oihane Crucelaegui <oihanecrucelaegi@avanzosc.es>
|
* Oihane Crucelaegui <oihanecrucelaegi@avanzosc.es>
|
||||||
* Pedro M. Baeza <pedro.baeza@serviciosbaeza.com>
|
* Pedro M. Baeza <pedro.baeza@tecnativa.com>
|
||||||
* Ana Juaristi <anajuaristi@avanzosc.es>
|
* Ana Juaristi <anajuaristi@avanzosc.es>
|
||||||
|
* Omar Castiñeira Saavedra <omar@comunitea.com>
|
||||||
|
* Oliver Dony <@odony>
|
||||||
|
* Wim Audenaert <Wim.Audenaert@ucamco.com>
|
||||||
|
* David Vidal <david.vidal@tecnativa.com>
|
||||||
|
|
||||||
|
Maintainer
|
||||||
|
----------
|
||||||
|
|
||||||
|
.. image:: https://odoo-community.org/logo.png
|
||||||
|
:alt: Odoo Community Association
|
||||||
|
:target: https://odoo-community.org
|
||||||
|
|
||||||
|
This module is maintained by the OCA.
|
||||||
|
|
||||||
|
OCA, or the Odoo Community Association, is a nonprofit organization whose
|
||||||
|
mission is to support the collaborative development of Odoo features and
|
||||||
|
promote its widespread use.
|
||||||
|
|
||||||
|
To contribute to this module, please visit https://odoo-community.org.
|
||||||
|
|
|
@ -1,4 +1 @@
|
||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
##############################################################################
|
|
||||||
# For copyright and license notices, see __openerp__.py file in root directory
|
|
||||||
##############################################################################
|
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2015 AvanzOSC - Oihane Crucelaegui
|
||||||
|
# Copyright 2015 Tecnativa - Pedro M. Baeza
|
||||||
|
# Copyright 2015 Comunitea - Omar Castiñeira Saavedra
|
||||||
|
# Copyright 2016 Oliver Dony
|
||||||
|
# Copyright 2017 Tecnativa - David Vidal
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "Web - Numpad Dot as decimal separator",
|
||||||
|
"version": "10.0.1.0.0",
|
||||||
|
"license": "AGPL-3",
|
||||||
|
"summary": "Allows using numpad dot to enter period decimal separator",
|
||||||
|
"depends": [
|
||||||
|
"web",
|
||||||
|
],
|
||||||
|
"author": "AvanzOSC, "
|
||||||
|
"Comunitea, "
|
||||||
|
"Tecnativa, "
|
||||||
|
"Odoo Community Association (OCA)",
|
||||||
|
"website": "https://odoo-community.org/",
|
||||||
|
"category": "Web",
|
||||||
|
"data": [
|
||||||
|
"views/web_decimal_numpad_dot.xml",
|
||||||
|
],
|
||||||
|
"installable": True,
|
||||||
|
}
|
|
@ -1,40 +0,0 @@
|
||||||
# -*- 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 <oihanecrucelaegi@avanzosc.es>",
|
|
||||||
"Pedro M. Baeza <pedro.baeza@serviciosbaeza.com>",
|
|
||||||
"Ana Juaristi <anajuaristi@avanzosc.es>",
|
|
||||||
],
|
|
||||||
"category": "Custom Module",
|
|
||||||
"summary": "",
|
|
||||||
"data": [
|
|
||||||
"views/web_decimal_numpad_dot.xml",
|
|
||||||
],
|
|
||||||
"installable": True,
|
|
||||||
}
|
|
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
|
@ -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<Number>} 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<indices.length; ++i) {
|
|
||||||
var section = indices[i];
|
|
||||||
if (section === -1 || last <= 0) {
|
|
||||||
// Done with string, or -1 (stops formatting string)
|
|
||||||
break;
|
|
||||||
} else if(section === 0 && i === 0) {
|
|
||||||
// repeats previous section, which there is none => 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;
|
|
||||||
};
|
|
||||||
|
|
||||||
})();
|
|
|
@ -1,28 +1,34 @@
|
||||||
(function() {
|
/* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
|
||||||
|
|
||||||
var instance = openerp;
|
odoo.define("web_decimal_numpad_dot.FieldFloat", function (require) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
instance.web.form.FieldFloat = instance.web.form.FieldFloat.extend({
|
var form_widgets = require("web.form_widgets");
|
||||||
render_value: function() {
|
var translation = require("web.translation");
|
||||||
var self = this;
|
|
||||||
this._super();
|
form_widgets.FieldFloat.include({
|
||||||
if (!this.get('readonly')){
|
init: function () {
|
||||||
this.$el.find('input').on('keypress', this.floatKeypress.bind(this));
|
this.events.keypress = function (event) {
|
||||||
}
|
if (event.which === 46 || event.which === 44) {
|
||||||
},
|
event.preventDefault();
|
||||||
floatKeypress: function(e){
|
var input = this.$input || this.$("input");
|
||||||
if (e.keyCode == '46' || e.charCode == '46') {
|
var l10n = translation._t.database.parameters;
|
||||||
// Cancel the keypress
|
if (!_.str.contains(input.val(), l10n.decimal_point)) {
|
||||||
e.preventDefault();
|
try {
|
||||||
// Add the comma to the value of the input field
|
var caret_pos = input[0].selectionStart;
|
||||||
this.$("input").val(this.$("input").val() + instance.web._t.database.parameters.decimal_point);
|
var selection_end = input[0].selectionEnd;
|
||||||
}
|
var cur_val = input.val();
|
||||||
else if (e.keyCode == '44' || e.charCode == '44') {
|
var newval = cur_val.substring(0, caret_pos) + l10n.decimal_point + cur_val.substring(selection_end);
|
||||||
// Cancel the keypress
|
input.val(newval);
|
||||||
e.preventDefault();
|
input[0].selectionStart = input[0].selectionEnd = caret_pos + 1;
|
||||||
// Add the comma to the value of the input field
|
} catch (error) {
|
||||||
this.$("input").val(this.$("input").val() + instance.web._t.database.parameters.thousands_sep);
|
//fallback to appending if no caret position can be determined
|
||||||
}
|
input.val(input.val() + l10n.decimal_point);
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return this._super.apply(this, arguments);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
})();
|
});
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<openerp>
|
<odoo>
|
||||||
<data>
|
|
||||||
<template id="assets_backend" name="numpad_dot assets" inherit_id="web.assets_backend">
|
<template id="assets_backend"
|
||||||
<xpath expr="." position="inside">
|
name="numpad_dot assets" inherit_id="web.assets_backend">
|
||||||
<script type="text/javascript" src="/web_decimal_numpad_dot/static/src/js/numpad_dot.js"></script>
|
<xpath expr="." position="inside">
|
||||||
</xpath>
|
<script type="text/javascript" src="/web_decimal_numpad_dot/static/src/js/numpad_dot.js"></script>
|
||||||
</template>
|
</xpath>
|
||||||
</data>
|
</template>
|
||||||
</openerp>
|
|
||||||
|
</odoo>
|
||||||
|
|
Loading…
Reference in New Issue