diff options
| author | Christophe Matthieu <chm@odoo.com> | 2017-02-23 10:14:57 +0100 |
|---|---|---|
| committer | Aaron Bohy <aab@odoo.com> | 2017-04-11 19:44:38 +0200 |
| commit | 173896b62d2c2d3c4acc6be75c3396b29887e4fb (patch) | |
| tree | 09ea86ccb845313e07adbd21c01e7cad1853c85f /addons/web | |
| parent | c9f747dad646b48d3dc9fed799df046180526531 (diff) | |
[REF] web: remove format.js
use 'web.field_utils' instead of 'web.formats'
Diffstat (limited to 'addons/web')
| -rw-r--r-- | addons/web/static/src/js/_deprecated/formats.js | 204 | ||||
| -rw-r--r-- | addons/web/static/src/js/chrome/search_filters.js | 10 | ||||
| -rw-r--r-- | addons/web/static/src/js/chrome/search_inputs.js | 10 | ||||
| -rw-r--r-- | addons/web/static/src/js/fields/basic_fields.js | 5 | ||||
| -rw-r--r-- | addons/web/static/src/js/fields/field_utils.js | 61 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/graph/graph_renderer.js | 8 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/kanban/kanban_record.js | 2 | ||||
| -rw-r--r-- | addons/web/static/src/js/widgets/date_picker.js | 6 | ||||
| -rw-r--r-- | addons/web/static/src/js/widgets/debug_manager.js | 4 | ||||
| -rw-r--r-- | addons/web/static/src/js/widgets/domain_selector.js | 8 | ||||
| -rw-r--r-- | addons/web/views/webclient_templates.xml | 1 |
11 files changed, 79 insertions, 240 deletions
diff --git a/addons/web/static/src/js/_deprecated/formats.js b/addons/web/static/src/js/_deprecated/formats.js deleted file mode 100644 index 479fa1082cd..00000000000 --- a/addons/web/static/src/js/_deprecated/formats.js +++ /dev/null @@ -1,204 +0,0 @@ -odoo.define('web.formats', function (require) { -"use strict"; - -var translation = require('web.translation'); -var time = require('web.time'); -var utils = require('web.utils'); - -var _t = translation._t; - -/** - * 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 - */ -function format_value (value, descriptor, value_if_empty) { - var l10n = _t.database.parameters; - var date_format = time.strftime_to_moment_format(l10n.date_format); - var time_format = time.strftime_to_moment_format(l10n.time_format); - // 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; - } - switch (descriptor.widget || descriptor.type || (descriptor.field && descriptor.field.type)) { - case 'id': - return value.toString(); - case 'integer': - return utils.insert_thousand_seps( - _.str.sprintf('%d', value)); - case 'monetary': - 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] = utils.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 = moment(time.auto_str_to_date(value)); - else { - value = moment(value); - } - return value.format(date_format + ' ' + time_format); - case 'date': - if (typeof(value) == "string") - value = moment(time.auto_str_to_date(value)); - else { - value = moment(value); - } - return value.format(date_format); - case 'time': - if (typeof(value) == "string") - value = moment(time.auto_str_to_date(value)); - else { - value = moment(value); - } - return value.format(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; - } -} - -function parse_value (value, descriptor, value_if_empty) { - var date_pattern = time.strftime_to_moment_format(_t.database.parameters.date_format), - time_pattern = time.strftime_to_moment_format(_t.database.parameters.time_format); - var date_pattern_wo_zero = date_pattern.replace('MM','M').replace('DD','D'), - time_pattern_wo_zero = time_pattern.replace('HH','H').replace('mm','m').replace('ss','s'); - 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(_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 'monetary': - case 'float': - var tmp2 = value; - do { - tmp = tmp2; - tmp2 = tmp.replace(_t.database.parameters.thousands_sep, ""); - } while(tmp !== tmp2); - var reformatted_value = tmp.replace(_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 * parse_value(value, {type: "float"}); - var hours = parse_value(float_time_pair[0], {type: "integer"}); - var minutes = parse_value(float_time_pair[1], {type: "integer"}); - return factor * (hours + (minutes / 60)); - case 'progressbar': - return parse_value(value, {type: "float"}); - case 'datetime': - var datetime = moment(value, [date_pattern + ' ' + time_pattern, date_pattern_wo_zero + ' ' + time_pattern_wo_zero, moment.ISO_8601], true); - if (datetime.isValid() && datetime.year() >= 1900) - return time.datetime_to_str(datetime.toDate()); - datetime = moment(value, [date_pattern + ' ' + time_pattern, date_pattern_wo_zero + ' ' + time_pattern_wo_zero, moment.ISO_8601]); - if (datetime.isValid()) { - if (datetime.year() === 0) { - datetime.year(moment.utc().year()); - } - if (datetime.year() >= 1900) { - return time.datetime_to_str(datetime.toDate()); - } - } - throw new Error(_.str.sprintf(_t("'%s' is not a correct datetime"), value)); - case 'date': - var date = moment(value, [date_pattern, date_pattern_wo_zero, moment.ISO_8601], true); - if (date.isValid() && date.year() >= 1900) - return time.date_to_str(date.toDate()); - date = moment(value, [date_pattern, date_pattern_wo_zero, moment.ISO_8601]); - if (date.isValid()) { - if (date.year() === 0) { - date.year(moment.utc().year()); - } - if (date.year() >= 1900) { - return time.date_to_str(date.toDate()); - } - } - throw new Error(_.str.sprintf(_t("'%s' is not a correct date"), value)); - case 'time': - var _time = moment(value, [time_pattern, time_pattern_wo_zero, moment.ISO_8601], true); - if (_time.isValid()) - return time.time_to_str(_time.toDate()); - throw new Error(_.str.sprintf(_t("'%s' is not a correct time"), value)); - } - return value; -} - -return { - format_value: format_value, - parse_value: parse_value, -}; - -}); diff --git a/addons/web/static/src/js/chrome/search_filters.js b/addons/web/static/src/js/chrome/search_filters.js index e4d58536df2..b1ab1c547b3 100644 --- a/addons/web/static/src/js/chrome/search_filters.js +++ b/addons/web/static/src/js/chrome/search_filters.js @@ -3,7 +3,7 @@ odoo.define('web.search_filters', function (require) { var core = require('web.core'); var datepicker = require('web.datepicker'); -var formats = require('web.formats'); +var field_utils = require('web.field_utils'); var Widget = require('web.Widget'); var _t = core._t; @@ -216,10 +216,10 @@ ExtendedSearchProposition.DateTime = ExtendedSearchProposition.Field.extend({ } }, toString: function () { - var str = formats.format_value(this.get_value(), {type: this.attributes['type']}); + var str = field_utils.format_field(this.get_value(), {type: this.attributes.type}); var date_1_value = this.datewidget_1 && this.get_value(1); if (date_1_value) { - str += _lt(" and ") + formats.format_value(date_1_value, {type: this.attributes['type']}); + str += _lt(" and ") + field_utils.format_field(date_1_value, {type: this.attributes.type}); } return str; }, @@ -271,7 +271,7 @@ ExtendedSearchProposition.Integer = ExtendedSearchProposition.Field.extend({ get_value: function () { try { var val =this.$el.val(); - return formats.parse_value(val === "" ? 0 : val, {'widget': 'integer'}); + return field_utils.parse_integer(val === "" ? 0 : val); } catch (e) { return ""; } @@ -304,7 +304,7 @@ ExtendedSearchProposition.Float = ExtendedSearchProposition.Field.extend({ get_value: function () { try { var val =this.$el.val(); - return formats.parse_value(val === "" ? 0.0 : val, {'widget': 'float'}); + return field_utils.parse_float(val === "" ? 0.0 : val); } catch (e) { return ""; } diff --git a/addons/web/static/src/js/chrome/search_inputs.js b/addons/web/static/src/js/chrome/search_inputs.js index 99535f29797..bf7d16b210c 100644 --- a/addons/web/static/src/js/chrome/search_inputs.js +++ b/addons/web/static/src/js/chrome/search_inputs.js @@ -3,7 +3,7 @@ odoo.define('web.search_inputs', function (require) { var core = require('web.core'); var data = require('web.data'); -var formats = require('web.formats'); +var field_utils = require('web.field_utils'); var Model = require('web.DataModel'); var pyeval = require('web.pyeval'); var time = require('web.time'); @@ -231,7 +231,7 @@ var IntegerField = NumberField.extend(/** @lends instance.web.search.IntegerFiel error_message: _t("not a valid integer"), parse: function (value) { try { - return formats.parse_value(value, {'widget': 'integer'}); + return field_utils.parse_interger(value); } catch (e) { return NaN; } @@ -246,7 +246,7 @@ var FloatField = NumberField.extend(/** @lends instance.web.search.FloatField# * error_message: _t("not a valid number"), parse: function (value) { try { - return formats.parse_value(value, {'widget': 'float'}); + return field_utils.parse_float(value); } catch (e) { return NaN; } @@ -348,7 +348,7 @@ var DateField = Field.extend(/** @lends instance.web.search.DateField# */{ var t, v; try { t = (this.attrs && this.attrs.type === 'datetime') ? 'datetime' : 'date'; - v = formats.parse_value(needle, {'widget': t}); + v = field_utils.parse_field(needle, {type: t}); } catch (e) { return $.when(null); } @@ -356,7 +356,7 @@ var DateField = Field.extend(/** @lends instance.web.search.DateField# */{ var m = moment(v, t === 'datetime' ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD'); if (!m.isValid()) { return $.when(null); } var d = m.toDate(); - var date_string = formats.format_value(d, this.attrs); + var date_string = field_utils.format_field(d, {type: t.attrs.type}); var label = _.str.sprintf(_.str.escapeHTML( _t("Search %(field)s at: %(value)s")), { field: '<em>' + _.escape(this.attrs.string) + '</em>', diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js index d07bcb5dd95..34c2b08e362 100644 --- a/addons/web/static/src/js/fields/basic_fields.js +++ b/addons/web/static/src/js/fields/basic_fields.js @@ -129,8 +129,9 @@ var FieldDate = InputField.extend({ if (this.mode === 'edit') { this.datewidget = this._makeDatePicker(); this.datewidget.on('datetime_changed', this, function () { - if (this.datewidget.get_value() !== this._parseValue(this.value)) { - this._setValue(this.datewidget.get_value()); + var value = this._parseValue(this.datewidget.get_value()); + if (value !== this._parseValue(this.value)) { + this._setValue(value); } }); def = this.datewidget.appendTo('<div>').done(function () { diff --git a/addons/web/static/src/js/fields/field_utils.js b/addons/web/static/src/js/fields/field_utils.js index 3b06af9efc4..fb20839fa2d 100644 --- a/addons/web/static/src/js/fields/field_utils.js +++ b/addons/web/static/src/js/fields/field_utils.js @@ -17,6 +17,10 @@ var session = require('web.session'); var time = require('web.time'); var utils = require('web.utils'); +//////////////////////////////////////////////////////////////////////////////// +// Format +//////////////////////////////////////////////////////////////////////////////// + function format_boolean(value) { var $input = $('<input type="checkbox">') .prop('checked', value) @@ -34,7 +38,7 @@ function format_char(value) { function format_date(value) { var l10n = core._t.database.parameters; var date_format = time.strftime_to_moment_format(l10n.date_format); - return value && moment(time.str_to_date(value)).format(date_format); + return value && moment(time.str_to_date(value), moment.ISO_8601).format(date_format); } function format_datetime(value) { @@ -42,7 +46,7 @@ function format_datetime(value) { var date_format = time.strftime_to_moment_format(l10n.date_format); var time_format = time.strftime_to_moment_format(l10n.time_format); var datetime_format = date_format + ' ' + time_format; - return value && moment(time.str_to_datetime(value)).format(datetime_format); + return value && moment(time.str_to_datetime(value), moment.ISO_8601).format(datetime_format); } // Format a float, according to the local settings @@ -73,7 +77,6 @@ function format_float_time(value) { return _.str.sprintf(pattern, hour, min); } - function format_id(value) { return value ? value.toString() : false; } @@ -140,12 +143,57 @@ function format_selection(value, field) { return val[1]; } +//////////////////////////////////////////////////////////////////////////////// +// Parse +//////////////////////////////////////////////////////////////////////////////// + +function parse_date(value) { + var date_pattern = time.strftime_to_moment_format(core._t.database.parameters.date_format); + var date_pattern_wo_zero = date_pattern.replace('MM','M').replace('DD','D'); + var date = moment(value, [date_pattern, date_pattern_wo_zero, moment.ISO_8601], true); + if (date.isValid() && date.year() >= 1900) { + return time.date_to_str(date.toDate()); + } + date = moment(value, [date_pattern, date_pattern_wo_zero, moment.ISO_8601]); + if (date.isValid()) { + if (date.year() === 0) { + date.year(moment.utc().year()); + } + if (date.year() >= 1900) { + return time.date_to_str(date.toDate()); + } + } + throw new Error(_.str.sprintf(core._t("'%s' is not a correct date"), value)); +} + +function parse_datetime(value) { + var date_pattern = time.strftime_to_moment_format(core._t.database.parameters.date_format), + time_pattern = time.strftime_to_moment_format(core._t.database.parameters.time_format); + var date_pattern_wo_zero = date_pattern.replace('MM','M').replace('DD','D'), + time_pattern_wo_zero = time_pattern.replace('HH','H').replace('mm','m').replace('ss','s'); + var pattern1 = date_pattern + ' ' + time_pattern; + var pattern2 = date_pattern_wo_zero + ' ' + time_pattern_wo_zero; + var datetime = moment(value, [pattern1, pattern2, moment.ISO_8601], true); + if (datetime.isValid() && datetime.year() >= 1900) { + return time.datetime_to_str(datetime.toDate()); + } + datetime = moment(value, [pattern1, pattern2, moment.ISO_8601]); + if (datetime.isValid()) { + if (datetime.year() === 0) { + datetime.year(moment.utc().year()); + } + if (datetime.year() >= 1900) { + return time.datetime_to_str(datetime.toDate()); + } + } + throw new Error(_.str.sprintf(core._t("'%s' is not a correct datetime"), value)); +} + function parse_field(value, field) { var parser = result['parse_' + field.type]; return parser(value, field); } - function parse_float(value) { value = value.replace(new RegExp(core._t.database.parameters.thousands_sep, "g"), ''); value = value.replace(core._t.database.parameters.decimal_point, '.'); @@ -216,8 +264,8 @@ var result = { parse_binary: identity, // todo parse_boolean: identity, // todo parse_char: identity, // todo - parse_date: identity, // todo - parse_datetime: identity, // todo + parse_date: parse_date, // todo + parse_datetime: parse_datetime, // todo parse_float: parse_float, parse_float_time: parse_float_time, parse_html: identity, // todo @@ -232,7 +280,6 @@ var result = { parse_text: identity, // todo parse_field: parse_field, - }; return result; diff --git a/addons/web/static/src/js/views/graph/graph_renderer.js b/addons/web/static/src/js/views/graph/graph_renderer.js index e5fe00cc473..64d6c3fd6a3 100644 --- a/addons/web/static/src/js/views/graph/graph_renderer.js +++ b/addons/web/static/src/js/views/graph/graph_renderer.js @@ -12,7 +12,7 @@ odoo.define('web.GraphRenderer', function (require) { var AbstractRenderer = require('web.AbstractRenderer'); var config = require('web.config'); var core = require('web.core'); -var formats = require('web.formats'); +var field_utils = require('web.field_utils'); var _t = core._t; var qweb = core.qweb; @@ -175,8 +175,7 @@ return AbstractRenderer.extend({ }); chart.yAxis.tickFormat(function (d) { var measure_field = self.state.fields[self.measure]; - return formats.format_value(d, { - type: 'float', + return field_utils.format_float(d, { digits: measure_field && measure_field.digits || [69, 2], }); }); @@ -320,8 +319,7 @@ return AbstractRenderer.extend({ chart.xAxis.tickValues(tickValues) .tickFormat(tickFormat); chart.yAxis.tickFormat(function (d) { - return formats.format_value(d, { - type : 'float', + return field_utils.format_float(d, { digits : self.state.fields[self.state.measure] && self.state.fields[self.state.measure].digits || [69, 2], }); }); diff --git a/addons/web/static/src/js/views/kanban/kanban_record.js b/addons/web/static/src/js/views/kanban/kanban_record.js index 18b72ae3d3e..0f385380f7a 100644 --- a/addons/web/static/src/js/views/kanban/kanban_record.js +++ b/addons/web/static/src/js/views/kanban/kanban_record.js @@ -5,7 +5,6 @@ var core = require('web.core'); var Domain = require('web.Domain'); var field_registry = require('web.field_registry'); var field_utils = require('web.field_utils'); -var formats = require('web.formats'); var framework = require('web.framework'); var session = require('web.session'); var time = require('web.time'); @@ -74,7 +73,6 @@ var KanbanRecord = Widget.extend({ widget: this, read_only_mode: this.read_only_mode, user_context: session.user_context, - formats: formats, }; for (var p in this) { if (_.str.startsWith(p, 'kanban_')) { diff --git a/addons/web/static/src/js/widgets/date_picker.js b/addons/web/static/src/js/widgets/date_picker.js index 4877a17c3ce..3fe9988467a 100644 --- a/addons/web/static/src/js/widgets/date_picker.js +++ b/addons/web/static/src/js/widgets/date_picker.js @@ -2,7 +2,7 @@ odoo.define('web.datepicker', function (require) { "use strict"; var core = require('web.core'); -var formats = require('web.formats'); +var field_utils = require('web.field_utils'); var time = require('web.time'); var Widget = require('web.Widget'); @@ -83,10 +83,10 @@ var DateWidget = Widget.extend({ } }, parse_client: function(v) { - return formats.parse_value(v, {"widget": this.type_of_date}); + return field_utils.parse_field(v, {type: this.type_of_date}); }, format_client: function(v) { - return formats.format_value(v, {"widget": this.type_of_date}); + return field_utils.format_field(v, {type: this.type_of_date}); }, set_datetime_default: function() { //when opening datetimepicker the date and time by default should be the one from diff --git a/addons/web/static/src/js/widgets/debug_manager.js b/addons/web/static/src/js/widgets/debug_manager.js index 44845f7b9e6..2689d789431 100644 --- a/addons/web/static/src/js/widgets/debug_manager.js +++ b/addons/web/static/src/js/widgets/debug_manager.js @@ -5,7 +5,7 @@ var ActionManager = require('web.ActionManager'); var dialogs = require('web.view_dialogs'); var core = require('web.core'); var Dialog = require('web.Dialog'); -var formats = require('web.formats'); +var field_utils = require('web.field_utils'); var framework = require('web.framework'); var Model = require('web.Model'); var session = require('web.session'); @@ -327,7 +327,7 @@ DebugManager.include({ size: 'medium', $content: QWeb.render('WebClient.DebugViewLog', { perm : result[0], - format : formats.format_value + format : field_utils.format_field }) }).open(); }); diff --git a/addons/web/static/src/js/widgets/domain_selector.js b/addons/web/static/src/js/widgets/domain_selector.js index 81d5047a5bc..f7c67aa37cb 100644 --- a/addons/web/static/src/js/widgets/domain_selector.js +++ b/addons/web/static/src/js/widgets/domain_selector.js @@ -4,7 +4,7 @@ odoo.define("web.DomainSelector", function (require) { var core = require("web.core"); var datepicker = require("web.datepicker"); var Domain = require("web.Domain"); -var formats = require ("web.formats"); +var field_utils = require ("web.field_utils"); var ModelFieldSelector = require("web.ModelFieldSelector"); var Widget = require("web.Widget"); @@ -378,7 +378,7 @@ var DomainLeaf = DomainNode.extend({ try { var f = this.fieldSelector.selectedField; if (!f.relation) { // TODO in this case, the value should be m2o input, etc... - this.displayValue = formats.format_value(this.value, this.fieldSelector.selectedField); + this.displayValue = field_utils.format_field(this.value, this.fieldSelector.selectedField); } } catch (err) {/**/} this.displayOperator = this.operator; @@ -466,7 +466,7 @@ var DomainLeaf = DomainNode.extend({ onValueChange: function (value, silent) { var couldNotParse = false; try { - this.value = formats.parse_value(value, this.fieldSelector.selectedField); + this.value = field_utils.parse_field(value, this.fieldSelector.selectedField); } catch (err) { this.value = value; couldNotParse = true; @@ -482,7 +482,7 @@ var DomainLeaf = DomainNode.extend({ } } else if (_.contains(["date", "datetime"], this.fieldSelector.selectedField.type)) { if (couldNotParse || _.isBoolean(this.value)) { - this.value = formats.parse_value(formats.format_value(Date.now(), this.fieldSelector.selectedField), this.fieldSelector.selectedField); + this.value = field_utils.parse_field(field_utils.format_field(Date.now(), this.fieldSelector.selectedField), this.fieldSelector.selectedField); } } else { if (_.isBoolean(this.value)) { // Never display "true" or "false" strings from boolean value diff --git a/addons/web/views/webclient_templates.xml b/addons/web/views/webclient_templates.xml index 21c52b842d3..cc4dbc55193 100644 --- a/addons/web/views/webclient_templates.xml +++ b/addons/web/views/webclient_templates.xml @@ -143,7 +143,6 @@ <script type="text/javascript" src="/web/static/src/js/_deprecated/data_model.js"></script> <script type="text/javascript" src="/web/static/src/js/core/domain.js"></script> - <script type="text/javascript" src="/web/static/src/js/_deprecated/formats.js"></script> <script type="text/javascript" src="/web/static/src/js/core/pyeval.js"></script> <script type="text/javascript" src="/web/static/src/js/chrome/action_manager.js"></script> <script type="text/javascript" src="/web/static/src/js/chrome/control_panel.js"></script> |
