summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js/services/data_manager.js
diff options
context:
space:
mode:
authorChristophe Matthieu <chm@odoo.com>2017-03-21 15:30:58 +0100
committerAaron Bohy <aab@odoo.com>2017-04-11 19:44:38 +0200
commiteaa66d11568b415b8d6b4c7a17a058b5ec1df4a6 (patch)
tree822fe86e984e69f989c3574936fe1792ae96fe9b /addons/web/static/src/js/services/data_manager.js
parente1eea38f2f940fbe252273a5a9d4d03474f81d0a (diff)
[REF] web: change internal representation of fields and view meta datas
* Data manager load_view returns a viewInfo object * ViewInfo contains: the arch, fields and fieldsInfo objects, and some extra informations * The fields come from the server and are frozen, without any view attributes (depend of the model). * The fieldsInfo contains every view attributes and informations.
Diffstat (limited to 'addons/web/static/src/js/services/data_manager.js')
-rw-r--r--addons/web/static/src/js/services/data_manager.js154
1 files changed, 153 insertions, 1 deletions
diff --git a/addons/web/static/src/js/services/data_manager.js b/addons/web/static/src/js/services/data_manager.js
index e86f1b9bb39..3fdb0986624 100644
--- a/addons/web/static/src/js/services/data_manager.js
+++ b/addons/web/static/src/js/services/data_manager.js
@@ -1,7 +1,10 @@
odoo.define('web.DataManager', function (require) {
"use strict";
+var config = require('web.config');
var core = require('web.core');
+var fieldRegistry = require('web.field_registry');
+var pyeval = require('web.pyeval');
var session = require('web.session');
var utils = require('web.utils');
@@ -112,7 +115,13 @@ return core.Class.extend({
}
return this._cache.views[key].then(function (views) {
- return $.extend(true, {}, views);
+ return _.mapObject(views, function (view, viewType) {
+ return _.extend(view, self._processFieldsView({
+ type: viewType,
+ arch: view.arch,
+ fields: view.fields,
+ }));
+ });
});
},
@@ -224,6 +233,149 @@ return core.Class.extend({
_invalidate: function (cache, key) {
delete cache[key];
},
+
+ ///////////////////////////////////////////////////////////////
+
+ /**
+ * Process a field node, in particular, put a flag on the field to give
+ * special directives to the BasicModel.
+ *
+ * @param {string} viewType
+ * @param {Object} field - the field properties
+ * @param {Object} attrs - the field attributes (from the xml)
+ * @returns {Object} attrs
+ */
+ _processField: function (viewType, field, attrs) {
+ var self = this;
+ attrs.Widget = this._getFieldWidgetClass(viewType, field, attrs);
+
+ if (!_.isObject(attrs.options)) { // parent arch could have already been processed (TODO this should not happen)
+ attrs.options = attrs.options ? pyeval.py_eval(attrs.options) : {};
+ }
+
+ if (attrs.on_change && !field.onChange) {
+ field.onChange = "1";
+ }
+
+ if (field.views) {
+ // process the inner fields_view as well to find the fields they use.
+ // register those fields' description directly on the view.
+ // for those inner views, the list of all fields isn't necessary, so
+ // basically the field_names will be the keys of the fields obj.
+ // don't use _ to iterate on fields in case there is a 'length' field,
+ // as _ doesn't behave correctly when there is a length key in the object
+ attrs.views = {};
+ _.each(field.views, function (innerFieldsView, viewType) {
+ innerFieldsView.type = viewType;
+ attrs.views[viewType] = self._processFieldsView(_.extend({}, innerFieldsView));
+ });
+ delete field.views;
+ }
+
+ if (field.type === 'one2many' || field.type === 'many2many') {
+ if (attrs.Widget.prototype.useSubview) {
+ if (!attrs.views) {
+ attrs.views = {};
+ }
+ var mode = attrs.mode;
+ if (!mode) {
+ if (attrs.views.tree && attrs.views.kanban) {
+ mode = 'tree';
+ } else if (!attrs.views.tree && attrs.views.kanban) {
+ mode = 'kanban';
+ } else {
+ mode = 'tree,kanban';
+ }
+ } else {
+ mode = 'tree,kanban';
+ }
+ if (mode.indexOf(',') !== -1) {
+ mode = config.device.size_class !== config.device.SIZES.XS ? 'tree' : 'kanban';
+ }
+ if (mode === 'tree') {
+ mode = 'list';
+ if (!attrs.views.list && attrs.views.tree) {
+ attrs.views.list = attrs.views.tree;
+ }
+ }
+ attrs.mode = mode;
+ }
+ if (attrs.Widget.prototype.fetchSubFields) {
+ attrs.relatedFields = {
+ display_name: {type: 'char'},
+ //id: {type: 'integer'},
+ };
+ attrs.fieldsInfo = {display_name: {}, id: {}};
+ if (attrs.color || 'color') {
+ attrs.relatedFields[attrs.color || 'color'] = {type: 'int'};
+ attrs.fieldsInfo.color = {};
+ }
+ }
+ }
+ return attrs;
+ },
+ /**
+ * Visit all nodes in the arch field and process each fields
+ *
+ * @param {string} viewType
+ * @param {Object} arch
+ * @param {Object} fields
+ * @returns {Object} fieldsInfo
+ */
+ _processFields: function (viewType, arch, fields) {
+ var self = this;
+ var fieldsInfo = Object.create(null);
+ utils.traverse(arch, function (node) {
+ if (typeof node === 'string') {
+ return false;
+ }
+ if (node.tag === 'field') {
+ fieldsInfo[node.attrs.name] = self._processField(viewType,
+ fields[node.attrs.name], node.attrs ? _.clone(node.attrs) : {});
+ return false;
+ }
+ return node.tag !== 'arch';
+ });
+ return fieldsInfo;
+ },
+ /**
+ * Visit all nodes in the arch field and process each fields and inner views
+ *
+ * @param {Object} viewInfo
+ * @param {Object} viewInfo.arch
+ * @param {Object} viewInfo.fields
+ * @returns {Object} viewInfo
+ */
+ _processFieldsView: function (viewInfo) {
+ viewInfo.fieldsInfo = this._processFields(viewInfo.type, viewInfo.arch, viewInfo.fields);
+ // by default display fetch display_name and id
+ if (!viewInfo.fields.display_name) {
+ viewInfo.fields.display_name = {type: 'char'};
+ viewInfo.fieldsInfo.display_name = {};
+ }
+ utils.deepFreeze(viewInfo.fields);
+ return viewInfo;
+ },
+ /**
+ * Returns the AbstractField specialization that should be used for the
+ * given field informations. If there is no mentioned specific widget to
+ * use, determine one according the field type.
+ *
+ * @param {string} viewType
+ * @param {Object} field
+ * @param {Object} attrs
+ * @returns {function|null} AbstractField specialization Class
+ */
+ _getFieldWidgetClass: function (viewType, field, attrs) {
+ var Widget;
+ if (attrs.widget) {
+ Widget = fieldRegistry.getAny([viewType + "." + attrs.widget, attrs.widget]);
+ if (!Widget) {
+ console.warn("Missing widget: ", attrs.widget, " for field", attrs.name, "of type", field.type);
+ }
+ }
+ return Widget || fieldRegistry.getAny([viewType + "." + field.type, field.type, "abstract"]);
+ },
});
});