4
var instance = openerp;
5
openerp.web.formats = {};
7
var _t = instance.web._t;
10
* Intersperses ``separator`` in ``str`` at the positions indicated by
13
* ``indices`` is an array of relative offsets (from the previous insertion
14
* position, starting from the end of the string) at which to insert
17
* There are two special values:
20
* indicates the insertion should end now
22
* indicates that the previous section pattern should be repeated (until all
23
* of ``str`` is consumed)
26
* @param {Array<Number>} indices
27
* @param {String} separator
30
instance.web.intersperse = function (str, indices, separator) {
31
separator = separator || '';
32
var result = [], last = str.length;
34
for(var i=0; i<indices.length; ++i) {
35
var section = indices[i];
36
if (section === -1 || last <= 0) {
37
// Done with string, or -1 (stops formatting string)
39
} else if(section === 0 && i === 0) {
40
// repeats previous section, which there is none => stop
42
} else if (section === 0) {
43
// repeat previous section forever
44
//noinspection AssignmentToForLoopParameterJS
45
section = indices[--i];
47
result.push(str.substring(last-section, last));
51
var s = str.substring(0, last);
52
if (s) { result.push(s); }
53
return result.reverse().join(separator);
56
* Insert "thousands" separators in the provided number (which is actually
62
instance.web.insert_thousand_seps = function (num) {
63
var negative = num[0] === '-';
64
num = (negative ? num.slice(1) : num);
65
return (negative ? '-' : '') + instance.web.intersperse(
66
num, _t.database.parameters.grouping, _t.database.parameters.thousands_sep);
70
* removes literal (non-format) text from a date or time pattern, as datejs can
71
* not deal with literal text in format strings (whatever the format), whereas
72
* strftime allows for literal characters
74
* @param {String} value original format
76
instance.web.strip_raw_chars = function (value) {
77
var isletter = /[a-zA-Z]/, output = [];
78
for(var index=0; index < value.length; ++index) {
79
var character = value[index];
80
if(isletter.test(character) && (index === 0 || value[index-1] !== '%')) {
83
output.push(character);
85
return output.join('');
87
var normalize_format = function (format) {
88
return Date.normalizeFormat(instance.web.strip_raw_chars(format));
92
* Check with a scary heuristic if the value is a bin_size or not.
93
* If not, compute an approximate size out of the base64 encoded string.
95
* @param {String} value original format
97
instance.web.binary_to_binsize = function (value) {
99
return instance.web.human_size(0);
101
if (value.substr(0, 10).indexOf(' ') == -1) {
102
// Computing approximate size out of base64 encoded string
103
// http://en.wikipedia.org/wiki/Base64#MIME
104
return instance.web.human_size(value.length / 1.37);
112
* Returns a human readable size
114
* @param {Number} numner of bytes
116
instance.web.human_size = function(size) {
117
var units = _t("Bytes,Kb,Mb,Gb,Tb,Pb,Eb,Zb,Yb").split(',');
119
while (size >= 1024) {
123
return size.toFixed(2) + ' ' + units[i];
127
* Formats a single atomic value based on a field descriptor
129
* @param {Object} value read from OpenERP
130
* @param {Object} descriptor union of orm field and view field
131
* @param {Object} [descriptor.widget] widget to use to display the value
132
* @param {Object} descriptor.type fallback if no widget is provided, or if the provided widget is unknown
133
* @param {Object} [descriptor.digits] used for the formatting of floats
134
* @param {String} [value_if_empty=''] returned if the ``value`` argument is considered empty
136
instance.web.format_value = function (value, descriptor, value_if_empty) {
137
// If NaN value, display as with a `false` (empty cell)
138
if (typeof value === 'number' && isNaN(value)) {
141
//noinspection FallthroughInSwitchStatementJS
144
if (descriptor.type === 'char' || descriptor.type === 'text') {
147
console.warn('Field', descriptor, 'had an empty string as value, treating as false...');
148
return value_if_empty === undefined ? '' : value_if_empty;
153
return value_if_empty === undefined ? '' : value_if_empty;
155
var l10n = _t.database.parameters;
156
switch (descriptor.widget || descriptor.type || (descriptor.field && descriptor.field.type)) {
158
return value.toString();
160
return instance.web.insert_thousand_seps(
161
_.str.sprintf('%d', value));
163
var digits = descriptor.digits ? descriptor.digits : [69,2];
164
digits = typeof digits === "string" ? py.eval(digits) : digits;
165
var precision = digits[1];
166
var formatted = _.str.sprintf('%.' + precision + 'f', value).split('.');
167
formatted[0] = instance.web.insert_thousand_seps(formatted[0]);
168
return formatted.join(l10n.decimal_point);
170
var pattern = '%02d:%02d';
172
value = Math.abs(value);
173
pattern = '-' + pattern;
175
var hour = Math.floor(value);
176
var min = Math.round((value % 1) * 60);
181
return _.str.sprintf(pattern, hour, min);
183
// name_get value format
184
return value[1] ? value[1].split("\n")[0] : value[1];
187
if (typeof value === 'string') {
190
return _.str.sprintf(_t("(%d records)"), value.length);
192
if (typeof(value) == "string")
193
value = instance.web.auto_str_to_date(value);
195
return value.toString(normalize_format(l10n.date_format)
196
+ ' ' + normalize_format(l10n.time_format));
198
if (typeof(value) == "string")
199
value = instance.web.str_to_date(value.substring(0,10));
200
return value.toString(normalize_format(l10n.date_format));
202
if (typeof(value) == "string")
203
value = instance.web.auto_str_to_date(value);
204
return value.toString(normalize_format(l10n.time_format));
205
case 'selection': case 'statusbar':
206
// Each choice is [value, label]
207
if(_.isArray(value)) {
210
var result = _(descriptor.selection).detect(function (choice) {
211
return choice[0] === value;
213
if (result) { return result[1]; }
220
instance.web.parse_value = function (value, descriptor, value_if_empty) {
221
var date_pattern = normalize_format(_t.database.parameters.date_format),
222
time_pattern = normalize_format(_t.database.parameters.time_format);
226
return value_if_empty === undefined ? false : value_if_empty;
229
switch (descriptor.widget || descriptor.type || (descriptor.field && descriptor.field.type)) {
233
value = value.replace(instance.web._t.database.parameters.thousands_sep, "");
234
} while(tmp !== value);
236
// do not accept not numbers or float values
237
if (isNaN(tmp) || tmp % 1)
238
throw new Error(_.str.sprintf(_t("'%s' is not a correct integer"), value));
248
tmp2 = tmp.replace(instance.web._t.database.parameters.thousands_sep, "");
249
} while(tmp !== tmp2);
250
var reformatted_value = tmp.replace(instance.web._t.database.parameters.decimal_point, ".");
251
var parsed = Number(reformatted_value);
253
throw new Error(_.str.sprintf(_t("'%s' is not a correct float"), value));
257
if (value[0] === '-') {
258
value = value.slice(1);
261
var float_time_pair = value.split(":");
262
if (float_time_pair.length != 2)
263
return factor * instance.web.parse_value(value, {type: "float"});
264
var hours = instance.web.parse_value(float_time_pair[0], {type: "integer"});
265
var minutes = instance.web.parse_value(float_time_pair[1], {type: "integer"});
266
return factor * (hours + (minutes / 60));
268
return instance.web.parse_value(value, {type: "float"});
270
var datetime = Date.parseExact(
271
value, (date_pattern + ' ' + time_pattern));
272
if (datetime !== null)
273
return instance.web.datetime_to_str(datetime);
274
datetime = Date.parseExact(value.toString().replace(/\d+/g, function(m){
275
return m.length === 1 ? "0" + m : m ;
276
}), (date_pattern + ' ' + time_pattern));
277
if (datetime !== null)
278
return instance.web.datetime_to_str(datetime);
279
datetime = Date.parse(value);
280
if (datetime !== null)
281
return instance.web.datetime_to_str(datetime);
282
throw new Error(_.str.sprintf(_t("'%s' is not a correct datetime"), value));
284
var date = Date.parseExact(value, date_pattern);
286
return instance.web.date_to_str(date);
287
date = Date.parseExact(value.toString().replace(/\d+/g, function(m){
288
return m.length === 1 ? "0" + m : m ;
291
return instance.web.date_to_str(date);
292
date = Date.parse(value);
294
return instance.web.date_to_str(date);
295
throw new Error(_.str.sprintf(_t("'%s' is not a correct date"), value));
297
var time = Date.parseExact(value, time_pattern);
299
return instance.web.time_to_str(time);
300
time = Date.parse(value);
302
return instance.web.time_to_str(time);
303
throw new Error(_.str.sprintf(_t("'%s' is not a correct time"), value));
308
instance.web.auto_str_to_date = function(value, type) {
310
return instance.web.str_to_datetime(value);
313
return instance.web.str_to_date(value);
316
return instance.web.str_to_time(value);
318
throw new Error(_.str.sprintf(_t("'%s' is not a correct date, datetime nor time"), value));
321
instance.web.auto_date_to_str = function(value, type) {
324
return instance.web.datetime_to_str(value);
326
return instance.web.date_to_str(value);
328
return instance.web.time_to_str(value);
330
throw new Error(_.str.sprintf(_t("'%s' is not convertible to date, datetime nor time"), type));
335
* performs a half up rounding with arbitrary precision, correcting for float loss of precision
336
* See the corresponding float_round() in server/tools/float_utils.py for more info
337
* @param {Number} the value to be rounded
338
* @param {Number} a non zero precision parameter. eg: 0.01 rounds to two digits.
340
instance.web.round_precision = function(value, precision){
343
}else if(!precision){
344
throw new Error('round_precision(...): Cannot round value: '+value+' with a precision of zero (or undefined)');
346
var normalized_value = value / precision;
347
var epsilon_magnitude = Math.log(Math.abs(normalized_value))/Math.log(2);
348
var epsilon = Math.pow(2, epsilon_magnitude - 53);
349
normalized_value += normalized_value >= 0 ? epsilon : -epsilon;
350
var rounded_value = Math.round(normalized_value);
351
return rounded_value * precision;
355
* performs a half up rounding with a fixed amount of decimals, correcting for float loss of precision
356
* See the corresponding float_round() in server/tools/float_utils.py for more info
357
* @param {Number} the value to be rounded
358
* @param {Number} the number of decimals. eg: round_decimals(3.141592,2) -> 3.14
360
instance.web.round_decimals = function(value, decimals){
361
return instance.web.round_precision(value, Math.pow(10,-decimals));