2011-04-28 13:50:45 +00:00
|
|
|
|
2013-08-06 12:50:22 +00:00
|
|
|
(function() {
|
|
|
|
|
|
|
|
var instance = openerp;
|
|
|
|
openerp.web.formats = {};
|
|
|
|
|
2012-04-17 11:59:16 +00:00
|
|
|
var _t = instance.web._t;
|
2011-11-14 15:34:36 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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}
|
|
|
|
*/
|
2012-04-17 11:59:16 +00:00
|
|
|
instance.web.intersperse = function (str, indices, separator) {
|
2011-11-14 15:34:36 +00:00
|
|
|
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);
|
|
|
|
};
|
2011-11-14 15:53:32 +00:00
|
|
|
/**
|
|
|
|
* Insert "thousands" separators in the provided number (which is actually
|
|
|
|
* a string)
|
|
|
|
*
|
|
|
|
* @param {String} num
|
|
|
|
* @returns {String}
|
|
|
|
*/
|
2012-04-17 11:59:16 +00:00
|
|
|
instance.web.insert_thousand_seps = function (num) {
|
2011-11-14 15:53:32 +00:00
|
|
|
var negative = num[0] === '-';
|
|
|
|
num = (negative ? num.slice(1) : num);
|
2012-04-17 11:59:16 +00:00
|
|
|
return (negative ? '-' : '') + instance.web.intersperse(
|
2011-11-14 15:53:32 +00:00
|
|
|
num, _t.database.parameters.grouping, _t.database.parameters.thousands_sep);
|
|
|
|
};
|
2012-02-15 15:32:37 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*/
|
2012-04-17 11:59:16 +00:00
|
|
|
instance.web.strip_raw_chars = function (value) {
|
2012-02-15 15:32:37 +00:00
|
|
|
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) {
|
2012-04-17 11:59:16 +00:00
|
|
|
return Date.normalizeFormat(instance.web.strip_raw_chars(format));
|
2012-02-15 15:32:37 +00:00
|
|
|
};
|
2012-11-12 17:11:28 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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];
|
|
|
|
};
|
|
|
|
|
2011-08-09 15:30:21 +00:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*/
|
2012-04-17 11:59:16 +00:00
|
|
|
instance.web.format_value = function (value, descriptor, value_if_empty) {
|
2011-08-09 15:30:21 +00:00
|
|
|
// If NaN value, display as with a `false` (empty cell)
|
|
|
|
if (typeof value === 'number' && isNaN(value)) {
|
|
|
|
value = false;
|
|
|
|
}
|
2011-11-16 10:04:16 +00:00
|
|
|
//noinspection FallthroughInSwitchStatementJS
|
2011-08-09 15:30:21 +00:00
|
|
|
switch (value) {
|
2011-11-16 10:04:16 +00:00
|
|
|
case '':
|
2014-01-17 11:31:41 +00:00
|
|
|
if (descriptor.type === 'char' || descriptor.type === 'text') {
|
2011-11-16 10:04:16 +00:00
|
|
|
return '';
|
|
|
|
}
|
|
|
|
console.warn('Field', descriptor, 'had an empty string as value, treating as false...');
|
2013-07-25 10:07:49 +00:00
|
|
|
return value_if_empty === undefined ? '' : value_if_empty;
|
2011-08-09 15:30:21 +00:00
|
|
|
case false:
|
2014-01-13 17:23:47 +00:00
|
|
|
case undefined:
|
2011-08-09 15:30:21 +00:00
|
|
|
case Infinity:
|
|
|
|
case -Infinity:
|
|
|
|
return value_if_empty === undefined ? '' : value_if_empty;
|
|
|
|
}
|
2011-11-14 15:45:10 +00:00
|
|
|
var l10n = _t.database.parameters;
|
2012-05-11 11:32:22 +00:00
|
|
|
switch (descriptor.widget || descriptor.type || (descriptor.field && descriptor.field.type)) {
|
2012-01-25 11:16:28 +00:00
|
|
|
case 'id':
|
|
|
|
return value.toString();
|
2011-08-09 15:30:21 +00:00
|
|
|
case 'integer':
|
2012-04-17 11:59:16 +00:00
|
|
|
return instance.web.insert_thousand_seps(
|
2011-11-15 12:30:59 +00:00
|
|
|
_.str.sprintf('%d', value));
|
2011-08-09 15:30:21 +00:00
|
|
|
case 'float':
|
2012-06-21 12:41:23 +00:00
|
|
|
var digits = descriptor.digits ? descriptor.digits : [69,2];
|
|
|
|
digits = typeof digits === "string" ? py.eval(digits) : digits;
|
|
|
|
var precision = digits[1];
|
2011-11-15 12:30:59 +00:00
|
|
|
var formatted = _.str.sprintf('%.' + precision + 'f', value).split('.');
|
2012-04-17 11:59:16 +00:00
|
|
|
formatted[0] = instance.web.insert_thousand_seps(formatted[0]);
|
2011-11-14 15:53:32 +00:00
|
|
|
return formatted.join(l10n.decimal_point);
|
2011-08-09 15:30:21 +00:00
|
|
|
case 'float_time':
|
2012-02-08 13:56:55 +00:00
|
|
|
var pattern = '%02d:%02d';
|
|
|
|
if (value < 0) {
|
|
|
|
value = Math.abs(value);
|
|
|
|
pattern = '-' + pattern;
|
|
|
|
}
|
2013-01-22 06:04:20 +00:00
|
|
|
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);
|
2011-08-09 15:30:21 +00:00
|
|
|
case 'many2one':
|
|
|
|
// name_get value format
|
2012-10-15 13:56:07 +00:00
|
|
|
return value[1] ? value[1].split("\n")[0] : value[1];
|
2012-05-04 17:23:03 +00:00
|
|
|
case 'one2many':
|
2012-06-07 10:13:29 +00:00
|
|
|
case 'many2many':
|
2012-09-28 11:35:24 +00:00
|
|
|
if (typeof value === 'string') {
|
|
|
|
return value;
|
|
|
|
}
|
2012-06-07 10:13:29 +00:00
|
|
|
return _.str.sprintf(_t("(%d records)"), value.length);
|
2011-08-19 15:47:26 +00:00
|
|
|
case 'datetime':
|
|
|
|
if (typeof(value) == "string")
|
2012-04-17 11:59:16 +00:00
|
|
|
value = instance.web.auto_str_to_date(value);
|
2011-11-14 14:00:07 +00:00
|
|
|
|
2012-02-15 15:32:37 +00:00
|
|
|
return value.toString(normalize_format(l10n.date_format)
|
|
|
|
+ ' ' + normalize_format(l10n.time_format));
|
2011-08-19 15:47:26 +00:00
|
|
|
case 'date':
|
|
|
|
if (typeof(value) == "string")
|
2015-02-04 13:31:32 +00:00
|
|
|
value = instance.web.auto_str_to_date(value);
|
2012-02-15 15:32:37 +00:00
|
|
|
return value.toString(normalize_format(l10n.date_format));
|
2011-08-22 12:35:16 +00:00
|
|
|
case 'time':
|
2011-08-19 15:47:26 +00:00
|
|
|
if (typeof(value) == "string")
|
2012-04-17 11:59:16 +00:00
|
|
|
value = instance.web.auto_str_to_date(value);
|
2012-02-15 15:32:37 +00:00
|
|
|
return value.toString(normalize_format(l10n.time_format));
|
2012-03-07 10:19:35 +00:00
|
|
|
case 'selection': case 'statusbar':
|
2011-10-12 12:09:38 +00:00
|
|
|
// Each choice is [value, label]
|
2011-12-30 16:46:55 +00:00
|
|
|
if(_.isArray(value)) {
|
2014-02-18 16:21:25 +00:00
|
|
|
return value[1];
|
2011-12-30 16:46:55 +00:00
|
|
|
}
|
2011-10-12 12:09:38 +00:00
|
|
|
var result = _(descriptor.selection).detect(function (choice) {
|
|
|
|
return choice[0] === value;
|
|
|
|
});
|
|
|
|
if (result) { return result[1]; }
|
|
|
|
return;
|
2011-08-09 15:30:21 +00:00
|
|
|
default:
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-04-17 11:59:16 +00:00
|
|
|
instance.web.parse_value = function (value, descriptor, value_if_empty) {
|
2012-02-15 15:32:37 +00:00
|
|
|
var date_pattern = normalize_format(_t.database.parameters.date_format),
|
|
|
|
time_pattern = normalize_format(_t.database.parameters.time_format);
|
2011-08-22 12:35:16 +00:00
|
|
|
switch (value) {
|
|
|
|
case false:
|
|
|
|
case "":
|
|
|
|
return value_if_empty === undefined ? false : value_if_empty;
|
|
|
|
}
|
2013-07-25 10:07:49 +00:00
|
|
|
var tmp;
|
2012-05-11 11:32:22 +00:00
|
|
|
switch (descriptor.widget || descriptor.type || (descriptor.field && descriptor.field.type)) {
|
2011-08-22 12:35:16 +00:00
|
|
|
case 'integer':
|
2011-09-19 13:46:15 +00:00
|
|
|
do {
|
|
|
|
tmp = value;
|
2012-04-17 11:59:16 +00:00
|
|
|
value = value.replace(instance.web._t.database.parameters.thousands_sep, "");
|
2011-09-19 13:46:15 +00:00
|
|
|
} while(tmp !== value);
|
|
|
|
tmp = Number(value);
|
2014-06-12 10:24:48 +00:00
|
|
|
// do not accept not numbers or float values
|
|
|
|
if (isNaN(tmp) || tmp % 1)
|
2012-11-29 00:22:00 +00:00
|
|
|
throw new Error(_.str.sprintf(_t("'%s' is not a correct integer"), value));
|
2011-08-22 12:35:16 +00:00
|
|
|
return tmp;
|
|
|
|
case 'float':
|
2011-11-29 10:13:34 +00:00
|
|
|
var tmp2 = value;
|
2011-08-22 12:35:16 +00:00
|
|
|
do {
|
|
|
|
tmp = tmp2;
|
2012-04-17 11:59:16 +00:00
|
|
|
tmp2 = tmp.replace(instance.web._t.database.parameters.thousands_sep, "");
|
2011-08-22 12:35:16 +00:00
|
|
|
} while(tmp !== tmp2);
|
2012-04-17 11:59:16 +00:00
|
|
|
var reformatted_value = tmp.replace(instance.web._t.database.parameters.decimal_point, ".");
|
2011-11-29 10:13:34 +00:00
|
|
|
var parsed = Number(reformatted_value);
|
|
|
|
if (isNaN(parsed))
|
2012-11-29 00:22:00 +00:00
|
|
|
throw new Error(_.str.sprintf(_t("'%s' is not a correct float"), value));
|
2011-11-29 10:13:34 +00:00
|
|
|
return parsed;
|
2011-08-22 12:35:16 +00:00
|
|
|
case 'float_time':
|
2012-02-08 14:04:45 +00:00
|
|
|
var factor = 1;
|
|
|
|
if (value[0] === '-') {
|
|
|
|
value = value.slice(1);
|
|
|
|
factor = -1;
|
|
|
|
}
|
2011-11-10 13:29:40 +00:00
|
|
|
var float_time_pair = value.split(":");
|
|
|
|
if (float_time_pair.length != 2)
|
2012-04-17 11:59:16 +00:00
|
|
|
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"});
|
2012-02-08 14:04:45 +00:00
|
|
|
return factor * (hours + (minutes / 60));
|
2011-08-22 12:35:16 +00:00
|
|
|
case 'progressbar':
|
2012-04-17 11:59:16 +00:00
|
|
|
return instance.web.parse_value(value, {type: "float"});
|
2011-08-22 12:35:16 +00:00
|
|
|
case 'datetime':
|
2011-11-14 14:00:07 +00:00
|
|
|
var datetime = Date.parseExact(
|
|
|
|
value, (date_pattern + ' ' + time_pattern));
|
2014-06-18 09:12:27 +00:00
|
|
|
if (datetime !== null)
|
|
|
|
return instance.web.datetime_to_str(datetime);
|
2014-12-24 10:30:58 +00:00
|
|
|
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){
|
2014-06-18 09:12:27 +00:00
|
|
|
return m.length === 1 ? "0" + m : m ;
|
2014-12-24 10:30:58 +00:00
|
|
|
});
|
|
|
|
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));
|
2011-11-10 13:29:40 +00:00
|
|
|
if (datetime !== null)
|
2012-04-17 11:59:16 +00:00
|
|
|
return instance.web.datetime_to_str(datetime);
|
2011-11-10 13:29:40 +00:00
|
|
|
datetime = Date.parse(value);
|
|
|
|
if (datetime !== null)
|
2012-04-17 11:59:16 +00:00
|
|
|
return instance.web.datetime_to_str(datetime);
|
2012-11-29 00:22:00 +00:00
|
|
|
throw new Error(_.str.sprintf(_t("'%s' is not a correct datetime"), value));
|
2011-08-22 12:35:16 +00:00
|
|
|
case 'date':
|
2011-11-14 14:00:07 +00:00
|
|
|
var date = Date.parseExact(value, date_pattern);
|
2014-06-18 09:12:27 +00:00
|
|
|
if (date !== null)
|
|
|
|
return instance.web.date_to_str(date);
|
2014-06-24 11:53:02 +00:00
|
|
|
date = Date.parseExact(value.toString().replace(/\d+/g, function(m){
|
2014-06-18 09:12:27 +00:00
|
|
|
return m.length === 1 ? "0" + m : m ;
|
|
|
|
}), date_pattern);
|
2011-11-10 13:29:40 +00:00
|
|
|
if (date !== null)
|
2012-04-17 11:59:16 +00:00
|
|
|
return instance.web.date_to_str(date);
|
2011-11-10 13:29:40 +00:00
|
|
|
date = Date.parse(value);
|
|
|
|
if (date !== null)
|
2012-04-17 11:59:16 +00:00
|
|
|
return instance.web.date_to_str(date);
|
2012-11-29 00:22:00 +00:00
|
|
|
throw new Error(_.str.sprintf(_t("'%s' is not a correct date"), value));
|
2011-08-22 12:35:16 +00:00
|
|
|
case 'time':
|
2011-11-14 14:00:07 +00:00
|
|
|
var time = Date.parseExact(value, time_pattern);
|
2011-11-10 13:29:40 +00:00
|
|
|
if (time !== null)
|
2012-04-17 11:59:16 +00:00
|
|
|
return instance.web.time_to_str(time);
|
2011-11-10 13:29:40 +00:00
|
|
|
time = Date.parse(value);
|
|
|
|
if (time !== null)
|
2012-04-17 11:59:16 +00:00
|
|
|
return instance.web.time_to_str(time);
|
2012-11-29 00:22:00 +00:00
|
|
|
throw new Error(_.str.sprintf(_t("'%s' is not a correct time"), value));
|
2011-08-22 12:35:16 +00:00
|
|
|
}
|
|
|
|
return value;
|
|
|
|
};
|
|
|
|
|
2012-04-17 11:59:16 +00:00
|
|
|
instance.web.auto_str_to_date = function(value, type) {
|
2011-09-01 15:22:24 +00:00
|
|
|
try {
|
2012-04-17 11:59:16 +00:00
|
|
|
return instance.web.str_to_datetime(value);
|
2011-09-01 15:22:24 +00:00
|
|
|
} catch(e) {}
|
|
|
|
try {
|
2012-04-17 11:59:16 +00:00
|
|
|
return instance.web.str_to_date(value);
|
2011-09-01 15:22:24 +00:00
|
|
|
} catch(e) {}
|
|
|
|
try {
|
2012-04-17 11:59:16 +00:00
|
|
|
return instance.web.str_to_time(value);
|
2011-09-01 15:22:24 +00:00
|
|
|
} catch(e) {}
|
2012-11-29 00:22:00 +00:00
|
|
|
throw new Error(_.str.sprintf(_t("'%s' is not a correct date, datetime nor time"), value));
|
2011-09-01 15:22:24 +00:00
|
|
|
};
|
|
|
|
|
2012-04-17 11:59:16 +00:00
|
|
|
instance.web.auto_date_to_str = function(value, type) {
|
2011-09-01 14:21:56 +00:00
|
|
|
switch(type) {
|
|
|
|
case 'datetime':
|
2012-04-17 11:59:16 +00:00
|
|
|
return instance.web.datetime_to_str(value);
|
2011-09-01 14:21:56 +00:00
|
|
|
case 'date':
|
2012-04-17 11:59:16 +00:00
|
|
|
return instance.web.date_to_str(value);
|
2011-09-01 14:21:56 +00:00
|
|
|
case 'time':
|
2012-04-17 11:59:16 +00:00
|
|
|
return instance.web.time_to_str(value);
|
2011-09-01 14:21:56 +00:00
|
|
|
default:
|
2012-11-29 00:22:00 +00:00
|
|
|
throw new Error(_.str.sprintf(_t("'%s' is not convertible to date, datetime nor time"), type));
|
2011-09-01 14:21:56 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-07-25 10:07:49 +00:00
|
|
|
/**
|
|
|
|
* 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
|
2014-11-11 15:18:27 +00:00
|
|
|
* @param {Number} a precision parameter. eg: 0.01 rounds to two digits.
|
2013-07-25 10:07:49 +00:00
|
|
|
*/
|
|
|
|
instance.web.round_precision = function(value, precision){
|
2014-11-11 15:18:27 +00:00
|
|
|
if (!value) {
|
2013-07-25 10:07:49 +00:00
|
|
|
return 0;
|
2014-11-11 15:18:27 +00:00
|
|
|
} else if (!precision || precision < 0) {
|
|
|
|
precision = 1;
|
2013-07-25 10:07:49 +00:00
|
|
|
}
|
|
|
|
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;
|
2015-11-03 16:11:45 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Javascript performs strictly the round half up method, which is asymmetric. However, in
|
|
|
|
* Python, the method is symmetric. For example:
|
|
|
|
* - In JS, Math.round(-0.5) is equal to -0.
|
|
|
|
* - In Python, round(-0.5) is equal to -1.
|
|
|
|
* We want to keep the Python behavior for consistency.
|
|
|
|
*/
|
|
|
|
var sign = normalized_value < 0 ? -1.0 : 1.0;
|
|
|
|
var rounded_value = sign * Math.round(Math.abs(normalized_value));
|
2013-07-25 10:07:49 +00:00
|
|
|
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));
|
|
|
|
};
|
|
|
|
|
[FIX] web: float compare, float is zero
When setting a float field,
the web client rounds the value entered by the user
using the instance.web.round_decimals method.
Nevertheless, this is possible that this method returns unrounded float,
due to the float precision
For example, round_decimals(53.8, 2) returns 53.800000000000004
In order to compare this new float value to the old float value
and check the eventual change),
we need to check if the delta between the two is almost 0.
This is the goal of the float_is_zero method introduced during this rev.
which is comparable to the float_is_zero method
already available in the openerp server, in openerp.tools.
Float values compared using the simple === operator
instead of this float_is_zero method
will be regarded as different in some cases,
according to the float value and the precision
And the value of the field will be regarded as changed,
which can lead to unwanted triggers of onchanges.
opw-626635
2015-01-28 13:57:12 +00:00
|
|
|
instance.web.float_is_zero = function(value, decimals){
|
|
|
|
epsilon = Math.pow(10, -decimals);
|
|
|
|
return Math.abs(instance.web.round_precision(value, epsilon)) < epsilon;
|
|
|
|
};
|
|
|
|
|
2013-08-06 12:50:22 +00:00
|
|
|
})();
|