23d8a2c24e0b18242bc7f7f6b9075d03fa1ad695
[odoo/odoo.git] / addons / web / static / src / js / formats.js
1
2 openerp.web.formats = function(openerp) {
3 var _t = openerp.web._t;
4
5 /**
6  * Intersperses ``separator`` in ``str`` at the positions indicated by
7  * ``indices``.
8  *
9  * ``indices`` is an array of relative offsets (from the previous insertion
10  * position, starting from the end of the string) at which to insert
11  * ``separator``.
12  *
13  * There are two special values:
14  *
15  * ``-1``
16  *   indicates the insertion should end now
17  * ``0``
18  *   indicates that the previous section pattern should be repeated (until all
19  *   of ``str`` is consumed)
20  *
21  * @param {String} str
22  * @param {Array<Number>} indices
23  * @param {String} separator
24  * @returns {String}
25  */
26 openerp.web.intersperse = function (str, indices, separator) {
27     separator = separator || '';
28     var result = [], last = str.length;
29
30     for(var i=0; i<indices.length; ++i) {
31         var section = indices[i];
32         if (section === -1 || last <= 0) {
33             // Done with string, or -1 (stops formatting string)
34             break;
35         } else if(section === 0 && i === 0) {
36             // repeats previous section, which there is none => stop
37             break;
38         } else if (section === 0) {
39             // repeat previous section forever
40             //noinspection AssignmentToForLoopParameterJS
41             section = indices[--i];
42         }
43         result.push(str.substring(last-section, last));
44         last -= section;
45     }
46
47     var s = str.substring(0, last);
48     if (s) { result.push(s); }
49     return result.reverse().join(separator);
50 };
51 /**
52  * Insert "thousands" separators in the provided number (which is actually
53  * a string)
54  *
55  * @param {String} num
56  * @returns {String}
57  */
58 openerp.web.insert_thousand_seps = function (num) {
59     var negative = num[0] === '-';
60     num = (negative ? num.slice(1) : num);
61     return (negative ? '-' : '') + openerp.web.intersperse(
62         num, _t.database.parameters.grouping, _t.database.parameters.thousands_sep);
63 };
64 /**
65  * Formats a single atomic value based on a field descriptor
66  *
67  * @param {Object} value read from OpenERP
68  * @param {Object} descriptor union of orm field and view field
69  * @param {Object} [descriptor.widget] widget to use to display the value
70  * @param {Object} descriptor.type fallback if no widget is provided, or if the provided widget is unknown
71  * @param {Object} [descriptor.digits] used for the formatting of floats
72  * @param {String} [value_if_empty=''] returned if the ``value`` argument is considered empty
73  */
74 openerp.web.format_value = function (value, descriptor, value_if_empty) {
75     // If NaN value, display as with a `false` (empty cell)
76     if (typeof value === 'number' && isNaN(value)) {
77         value = false;
78     }
79     switch (value) {
80         case false:
81         case Infinity:
82         case -Infinity:
83             return value_if_empty === undefined ?  '' : value_if_empty;
84     }
85     var l10n = _t.database.parameters;
86     switch (descriptor.widget || descriptor.type) {
87         case 'integer':
88             return openerp.web.insert_thousand_seps(
89                 _.str.sprintf('%d', value));
90         case 'float':
91             var precision = descriptor.digits ? descriptor.digits[1] : 2;
92             var formatted = _.str.sprintf('%.' + precision + 'f', value).split('.');
93             formatted[0] = openerp.web.insert_thousand_seps(formatted[0]);
94             return formatted.join(l10n.decimal_point);
95         case 'float_time':
96             return _.str.sprintf("%02d:%02d",
97                     Math.floor(value),
98                     Math.round((value % 1) * 60));
99         case 'progressbar':
100             return _.str.sprintf(
101                 '<progress value="%.2f" max="100.0">%.2f%%</progress>',
102                     value, value);
103         case 'many2one':
104             // name_get value format
105             return value[1];
106         case 'datetime':
107             if (typeof(value) == "string")
108                 value = openerp.web.auto_str_to_date(value);
109
110             return value.format(l10n.date_format
111                         + ' ' + l10n.time_format);
112         case 'date':
113             if (typeof(value) == "string")
114                 value = openerp.web.auto_str_to_date(value);
115             return value.format(l10n.date_format);
116         case 'time':
117             if (typeof(value) == "string")
118                 value = openerp.web.auto_str_to_date(value);
119             return value.format(l10n.time_format);
120         case 'selection':
121             // Each choice is [value, label]
122             var result = _(descriptor.selection).detect(function (choice) {
123                 return choice[0] === value;
124             });
125             if (result) { return result[1]; }
126             return;
127         default:
128             return value;
129     }
130 };
131
132 openerp.web.parse_value = function (value, descriptor, value_if_empty) {
133     var date_pattern = Date.normalizeFormat(_t.database.parameters.date_format),
134         time_pattern = Date.normalizeFormat(_t.database.parameters.time_format);
135     switch (value) {
136         case false:
137         case "":
138             return value_if_empty === undefined ?  false : value_if_empty;
139     }
140     switch (descriptor.widget || descriptor.type) {
141         case 'integer':
142             var tmp;
143             do {
144                 tmp = value;
145                 value = value.replace(openerp.web._t.database.parameters.thousands_sep, "");
146             } while(tmp !== value);
147             tmp = Number(value);
148             if (isNaN(tmp))
149                 throw new Error(value + " is not a correct integer");
150             return tmp;
151         case 'float':
152             var tmp = Number(value);
153             if (!isNaN(tmp))
154                 return tmp;
155             tmp = value.replace(openerp.web._t.database.parameters.decimal_point, ".");
156             var tmp2 = tmp;
157             do {
158                 tmp = tmp2;
159                 tmp2 = tmp.replace(openerp.web._t.database.parameters.thousands_sep, "");
160             } while(tmp !== tmp2);
161             tmp = Number(tmp);
162             if (isNaN(tmp))
163                 throw new Error(value + " is not a correct float");
164             return tmp;
165         case 'float_time':
166             var float_time_pair = value.split(":");
167             if (float_time_pair.length != 2)
168                 return openerp.web.parse_value(value, {type: "float"});
169             var hours = openerp.web.parse_value(float_time_pair[0], {type: "integer"});
170             var minutes = openerp.web.parse_value(float_time_pair[1], {type: "integer"});
171             return hours + (minutes / 60);
172         case 'progressbar':
173             return openerp.web.parse_value(value, {type: "float"});
174         case 'datetime':
175             var datetime = Date.parseExact(
176                     value, (date_pattern + ' ' + time_pattern));
177             if (datetime !== null)
178                 return openerp.web.datetime_to_str(datetime);
179             datetime = Date.parse(value);
180             if (datetime !== null)
181                 return openerp.web.datetime_to_str(datetime);
182             throw new Error(value + " is not a valid datetime");
183         case 'date':
184             var date = Date.parseExact(value, date_pattern);
185             if (date !== null)
186                 return openerp.web.date_to_str(date);
187             date = Date.parse(value);
188             if (date !== null)
189                 return openerp.web.date_to_str(date);
190             throw new Error(value + " is not a valid date");
191         case 'time':
192             var time = Date.parseExact(value, time_pattern);
193             if (time !== null)
194                 return openerp.web.time_to_str(time);
195             time = Date.parse(value);
196             if (time !== null)
197                 return openerp.web.time_to_str(time);
198             throw new Error(value + " is not a valid time");
199     }
200     return value;
201 };
202
203 openerp.web.auto_str_to_date = function(value, type) {
204     try {
205         return openerp.web.str_to_datetime(value);
206     } catch(e) {}
207     try {
208         return openerp.web.str_to_date(value);
209     } catch(e) {}
210     try {
211         return openerp.web.str_to_time(value);
212     } catch(e) {}
213     throw new Error("'" + value + "' is not a valid date, datetime nor time");
214 };
215
216 openerp.web.auto_date_to_str = function(value, type) {
217     switch(type) {
218         case 'datetime':
219             return openerp.web.datetime_to_str(value);
220         case 'date':
221             return openerp.web.date_to_str(value);
222         case 'time':
223             return openerp.web.time_to_str(value);
224         default:
225             throw new Error(type + " is not convertible to date, datetime nor time");
226     }
227 };
228
229 /**
230  * Formats a provided cell based on its field type
231  *
232  * @param {Object} row_data record whose values should be displayed in the cell
233  * @param {Object} column column descriptor
234  * @param {"button"|"field"} column.tag base control type
235  * @param {String} column.type widget type for a field control
236  * @param {String} [column.string] button label
237  * @param {String} [column.icon] button icon
238  * @param {String} [value_if_empty=''] what to display if the field's value is ``false``
239  * @param {Boolean} [process_modifiers=true] should the modifiers be computed ?
240  */
241 openerp.web.format_cell = function (row_data, column, value_if_empty, process_modifiers) {
242     var attrs = {};
243     if (process_modifiers !== false) {
244         attrs = column.modifiers_for(row_data);
245     }
246     if (attrs.invisible) { return ''; }
247     if (column.tag === 'button') {
248         return [
249             '<button type="button" title="', column.string || '', '">',
250                 '<img src="/web/static/src/img/icons/', column.icon, '.png"',
251                     ' alt="', column.string || '', '"/>',
252             '</button>'
253         ].join('')
254     }
255
256     if (!row_data[column.id]) {
257         return value_if_empty === undefined ? '' : value_if_empty;
258     }
259     return openerp.web.format_value(
260             row_data[column.id].value, column, value_if_empty);
261 }
262     
263 };