diff --git a/web_widget_float_formula/__init__.py b/web_widget_float_formula/__init__.py new file mode 100644 index 00000000..97833ca3 --- /dev/null +++ b/web_widget_float_formula/__init__.py @@ -0,0 +1,4 @@ +# -*- encoding: utf-8 -*- +################################################################################ +# See __openerp__.py file for Copyright and Licence Informations. +################################################################################ diff --git a/web_widget_float_formula/__openerp__.py b/web_widget_float_formula/__openerp__.py new file mode 100644 index 00000000..2cd5e8ab --- /dev/null +++ b/web_widget_float_formula/__openerp__.py @@ -0,0 +1,63 @@ +# -*- encoding: utf-8 -*- +################################################################################ +# See Copyright and Licence Informations undermentioned. +################################################################################ +{ + 'name': 'Web Widget - Formulas in Float fields', + 'version': '1.0', + 'category': 'web', + 'description': """ +Allow to write simple mathematic formulas in Integer / Float fields +=================================================================== + +Functionnalities: +------------------ + * Possibility to tip a text like "=45 + 4/3 - 5 * (2 +1)"; + * if the formula is correct, The result will be computed and displayed; + * if the formula is not correct, the initial text is displayed; + +Documentations: +------------------ + * Video: http://www.youtube.com/watch?v=jQGdD34WYrA&hd=1 + +Technical informations: +------------------------ + * Overloads "instance.web.form.FieldFloat"; (so works for fields.integer & fields.float); + * To compute, the module simply use the eval() javascript function; + * Rounding computation is not done by this module (The module has the same behaviour if the user tips "=1/3" or if he tips "0.33[...]"); + * avoid code injonction by regexpr test: "=alert('security')" is not valid; + +Limits: +-------- + * Only supports the four operators: "+" "-" "*" "/" and parenthesis; + +Copyright and Licence: +----------------------- + * 2013, Groupement Régional Alimentaire de Proximité (http://www.grap.coop/) + * Licence: AGPL-3 (http://www.gnu.org/licenses/) + +Contacts : +---------- + * Sylvain LE GAL (https://twitter.com/legalsylvain); + * for any help or question about this module. + """, + 'author': 'GRAP', + 'website': 'http://www.grap.coop', + 'license': 'AGPL-3', + 'depends': [ + 'web', + ], + 'data': [], + 'demo': [], + 'js': [ + 'static/src/js/models.js', + ], + 'css': [], + 'qweb': [], + 'images': [], + 'post_load': '', + 'application': False, + 'installable': True, + 'auto_install': False, + 'images': [], +} diff --git a/web_widget_float_formula/static/src/img/icon.png b/web_widget_float_formula/static/src/img/icon.png new file mode 100644 index 00000000..7f744399 Binary files /dev/null and b/web_widget_float_formula/static/src/img/icon.png differ diff --git a/web_widget_float_formula/static/src/js/models.js b/web_widget_float_formula/static/src/js/models.js new file mode 100644 index 00000000..6a132251 --- /dev/null +++ b/web_widget_float_formula/static/src/js/models.js @@ -0,0 +1,132 @@ +/******************************************************************************* +See __openerp__.py file for Copyright and Licence Informations. +*******************************************************************************/ + +openerp.web_widget_float_formula = function (instance) { + + instance.web.FormView = instance.web.FormView.extend({ + /*********************************************************************** + Overload section + ***********************************************************************/ + + /** + * Overload : '_process_save' function + 1: to force computation of formula if the user realize a keydown directly after the formula input in a tree view ; + 2: to clean up the '_formula_text' value in all case to avoid bugs in tree view ; + */ + _process_save: function(save_obj) { + for (var f in this.fields) { + if (!this.fields.hasOwnProperty(f)) { continue; } + f = this.fields[f]; + if (f.hasOwnProperty('_formula_text')){ + currentval = f.$('input').attr('value') + if (typeof currentval != 'undefined'){ + formula = f._get_valid_expression(currentval); + if (formula){ + f._compute_result(); + } + } + f._clean_formula_text(); + } + } + return this._super(save_obj); + }, + + }); + + instance.web.form.FieldFloat = instance.web.form.FieldFloat.extend({ + /*********************************************************************** + Overload section + ***********************************************************************/ + + /** + * Overload : 'start' function to catch 'blur' and 'focus' events. + */ + start: function() { + this.on("blurred", this, this._compute_result); + this.on("focused", this, this._display_formula); + return this._super(); + }, + + /** + * Overload : 'initialize_content' function to clean '_formula_text' value. + */ + initialize_content: function() { + this._clean_formula_text(); + return this._super(); + }, + + /*********************************************************************** + Custom section + ***********************************************************************/ + + /** + * keep in memory the formula to allow user to edit it again. + The formula has to be keeped in memory until a 'save' action. + */ + _formula_text: '', + + /** + * Clean '_formula_text' value. + */ + _clean_formula_text: function() { + this._formula_text = ''; + }, + + /** + * Return a valid formula from a val, if possible. + Otherwise, return false. + */ + _get_valid_expression: function(val) { + // Trim the value + currenttxt = val.toString().replace(/^\s+|\s+$/g, ''); + // Test if the value is a formula + if (currenttxt[0] == '=') { + // allowed chars : [0-9] .,+-/*() and spaces + myreg = RegExp('[0-9]|\\s|\\.|,|\\(|\\)|\\+|\\-|\\*|\\/','g') + // Test to avoid code injonction in eval function. + if (currenttxt.substring(1).replace(myreg, '') == ''){ + try { + // Try to compute + formula = currenttxt.substring(1).replace(/,/g,'.'); + var floatval = eval(formula); + }catch (e) {} + if (typeof (floatval) != 'undefined'){ + return formula; + } + } + } + return false; + }, + + /** + * test if the content of the field is a valid formula, + * compute the result, and replace the current value by the final result. + */ + _compute_result: function() { + var formula + // Erase old formula + this._formula_text = ''; + + formula = this._get_valid_expression(this.$el.find('input').attr('value')); + if (formula){ + // Store new formula + this._formula_text = "=" + formula; + // put the result in the field + this.set_value(eval(formula)); + // Force rendering anyway to avoid format loss if no change + this.render_value(); + } + }, + + /** + * Display the stored formula in the field, to allow modification. + */ + _display_formula: function() { + if (this._formula_text != ''){ + this.$el.find('input').val(this._formula_text); + } + }, + + }); +};