summaryrefslogtreecommitdiff
path: root/addons/web/static/src
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
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')
-rw-r--r--addons/web/static/src/js/chrome/view_manager.js2
-rw-r--r--addons/web/static/src/js/core/utils.js27
-rw-r--r--addons/web/static/src/js/fields/abstract_field.js5
-rw-r--r--addons/web/static/src/js/fields/field_utils.js13
-rw-r--r--addons/web/static/src/js/fields/relational_fields.js9
-rw-r--r--addons/web/static/src/js/services/data_manager.js154
-rw-r--r--addons/web/static/src/js/views/abstract_view.js16
-rw-r--r--addons/web/static/src/js/views/basic/basic_model.js142
-rw-r--r--addons/web/static/src/js/views/basic/basic_view.js131
-rw-r--r--addons/web/static/src/js/views/calendar/calendar_model.js1
-rw-r--r--addons/web/static/src/js/views/calendar/calendar_view.js5
-rw-r--r--addons/web/static/src/js/views/form/form_controller.js7
-rw-r--r--addons/web/static/src/js/views/form/form_renderer.js3
-rw-r--r--addons/web/static/src/js/views/form/form_view.js37
-rw-r--r--addons/web/static/src/js/views/graph/graph_view.js14
-rw-r--r--addons/web/static/src/js/views/kanban/kanban_model.js2
-rw-r--r--addons/web/static/src/js/views/kanban/kanban_record.js14
-rw-r--r--addons/web/static/src/js/views/kanban/kanban_view.js3
-rw-r--r--addons/web/static/src/js/views/list/list_editable_renderer.js4
-rw-r--r--addons/web/static/src/js/views/list/list_renderer.js4
-rw-r--r--addons/web/static/src/js/views/list/list_view.js6
-rw-r--r--addons/web/static/src/js/views/pivot/pivot_view.js7
-rw-r--r--addons/web/static/src/js/views/view_dialogs.js14
-rw-r--r--addons/web/static/src/js/widgets/domain_selector.js2
24 files changed, 349 insertions, 273 deletions
diff --git a/addons/web/static/src/js/chrome/view_manager.js b/addons/web/static/src/js/chrome/view_manager.js
index af1d037bc2f..45be7a9484a 100644
--- a/addons/web/static/src/js/chrome/view_manager.js
+++ b/addons/web/static/src/js/chrome/view_manager.js
@@ -348,7 +348,7 @@ var ViewManager = Widget.extend(ControlPanelMixin, {
params.mode = params.initial_mode || 'edit';
}
- view = new View(arch, view.fields_view.fields, params);
+ view = new View(view.fields_view, params);
return view.getController(this).then(function(controller) {
controller.on('history_back', this, function() {
if (self.action_manager) self.action_manager.trigger('history_back');
diff --git a/addons/web/static/src/js/core/utils.js b/addons/web/static/src/js/core/utils.js
index 578eb3478f1..585be4d37b8 100644
--- a/addons/web/static/src/js/core/utils.js
+++ b/addons/web/static/src/js/core/utils.js
@@ -429,6 +429,33 @@ var utils = {
});
return str;
},
+ /**
+ * Visit a tree of objects, where each children are in an attribute 'children'.
+ * For each children, we call the callback function given in arguments.
+ *
+ * @param {Object} tree an object describing a tree structure
+ * @param {function} f a callback
+ */
+ traverse: function (tree, f) {
+ if (f(tree)) {
+ _.each(tree.children, function (c) { utils.traverse(c, f); });
+ }
+ },
+ /**
+ * Visit a tree of objects and freeze all
+ *
+ * @param {Object} obj
+ */
+ deepFreeze: function (obj) {
+ var propNames = Object.getOwnPropertyNames(obj);
+ propNames.forEach(function(name) {
+ var prop = obj[name];
+ if (typeof prop == 'object' && prop !== null)
+ utils.deepFreeze(prop);
+ });
+ return Object.freeze(obj);
+ },
+
};
return utils;
diff --git a/addons/web/static/src/js/fields/abstract_field.js b/addons/web/static/src/js/fields/abstract_field.js
index 2cfe961037c..25c530d8fd4 100644
--- a/addons/web/static/src/js/fields/abstract_field.js
+++ b/addons/web/static/src/js/fields/abstract_field.js
@@ -88,8 +88,9 @@ var AbstractField = Widget.extend({
// such as the type, the comodel (relation), ...
this.field = record.fields[name];
- // the 'attrs' property contains the attributes of the xml 'field' tag
- this.attrs = record.fieldAttrs[name] || {};
+ // the 'attrs' property contains the attributes of the xml 'field' tag,
+ // the inner views...
+ this.attrs = record.fieldsInfo && record.fieldsInfo[name] || {};
// modifiers
this.modifiers = JSON.parse(this.attrs.modifiers || "{}");
diff --git a/addons/web/static/src/js/fields/field_utils.js b/addons/web/static/src/js/fields/field_utils.js
index bee1681a067..9c5afb71dd9 100644
--- a/addons/web/static/src/js/fields/field_utils.js
+++ b/addons/web/static/src/js/fields/field_utils.js
@@ -20,6 +20,8 @@ var session = require('web.session');
var time = require('web.time');
var utils = require('web.utils');
+var _t = core._t;
+
//------------------------------------------------------------------------------
// Formatting
//------------------------------------------------------------------------------
@@ -191,10 +193,13 @@ function formatMany2one(value) {
* @returns {string}
*/
function formatMany2Many(value) {
- var names = _.map(value.data, function (p) {
- return p.data.display_name;
- });
- return names.join(', ');
+ if (value.data.length === 0) {
+ return value.data.length + _t('0 records');
+ } else if (value.data.length === 1) {
+ return value.data.length + _t('1 record');
+ } else {
+ return value.data.length + _t(' records');
+ }
}
function formatMonetary(value, field, options) {
diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js
index 408b4c5a3ea..923e8400b1e 100644
--- a/addons/web/static/src/js/fields/relational_fields.js
+++ b/addons/web/static/src/js/fields/relational_fields.js
@@ -520,7 +520,7 @@ var FieldX2Many = AbstractField.extend({
this._super.apply(this, arguments);
this.operations = [];
this.isReadonly = this.mode === 'readonly';
- this.view = this.field.views.tree || this.field.views.kanban;
+ this.view = this.attrs.views.list || this.attrs.views.kanban;
this.activeActions = {};
var arch = this.view && this.view.arch;
if (arch) {
@@ -704,7 +704,7 @@ var FieldX2Many = AbstractField.extend({
_.extend(event.data, {
context: this.record.getContext({fieldName: this.name}),
domain: this.record.getDomain({fieldName: this.name}),
- form_view: this.field.views && this.field.views.form,
+ form_view: this.attrs.views && this.attrs.views.form,
readonly: this.mode === 'readonly',
string: this.string,
});
@@ -799,6 +799,7 @@ var FieldOne2Many = FieldX2Many.extend({
domain: this.record.getDomain({fieldName: this.name}),
context: this.record.getContext({fieldName: this.name}),
field: this.field,
+ attrs: this.attrs,
on_save: function (record) {
this._setValue({
operation: 'ADD',
@@ -867,7 +868,7 @@ var FieldMany2Many = FieldX2Many.extend({
context: this.record.getContext({fieldName: this.name}),
title: _t("Add: ") + this.string,
no_create: this.nodeOptions.no_create || !this.activeActions.create,
- fields_view: this.field.views.form,
+ fields_view: this.attrs.views.form,
on_selected: function (res_ids) {
var new_ids = _.difference(res_ids, self.value.res_ids);
if (new_ids.length) {
@@ -911,6 +912,8 @@ var FieldMany2ManyTags = AbstractField.extend({
'keydown .o_form_field_many2one input': '_onKeyDown',
}),
+ fetchSubFields: true,
+
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
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"]);
+ },
});
});
diff --git a/addons/web/static/src/js/views/abstract_view.js b/addons/web/static/src/js/views/abstract_view.js
index 98c6aaac22e..e1066e56e92 100644
--- a/addons/web/static/src/js/views/abstract_view.js
+++ b/addons/web/static/src/js/views/abstract_view.js
@@ -60,8 +60,10 @@ var AbstractView = Class.extend({
*
* @constructs AbstractView
*
- * @param {any} arch
- * @param {any} fields
+ * @param {Object} viewInfo
+ * @param {Object} viewInfo.arch
+ * @param {Object} viewInfo.fields
+ * @param {Object} viewInfo.fieldsInfo
* @param {Object} params
* @param {string} params.modelName The actual model name
* @param {Object} params.context
@@ -72,17 +74,17 @@ var AbstractView = Class.extend({
* @param {number[]} [params.ids]
* @param {string} [params.action.help]
*/
- init: function (arch, fields, params) {
+ init: function (viewInfo, params) {
this.rendererParams = {
- arch: arch
+ arch: viewInfo.arch,
};
this.controllerParams = {
modelName: params.modelName,
activeActions: {
- edit: arch.attrs.edit ? JSON.parse(arch.attrs.edit) : true,
- create: arch.attrs.create ? JSON.parse(arch.attrs.create) : true,
- delete: arch.attrs.delete ? JSON.parse(arch.attrs.delete) : true,
+ edit: viewInfo.arch.attrs.edit ? JSON.parse(viewInfo.arch.attrs.edit) : true,
+ create: viewInfo.arch.attrs.create ? JSON.parse(viewInfo.arch.attrs.create) : true,
+ delete: viewInfo.arch.attrs.delete ? JSON.parse(viewInfo.arch.attrs.delete) : true,
},
noContentHelp: params.action && params.action.help,
};
diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js
index d5f3c86cc8e..023571d19a4 100644
--- a/addons/web/static/src/js/views/basic/basic_model.js
+++ b/addons/web/static/src/js/views/basic/basic_model.js
@@ -25,7 +25,7 @@ odoo.define('web.BasicModel', function (require) {
* domain: {*[]},
* fieldNames: {string[]},
* fields: {Object},
- * fieldAttrs: {Object},
+ * fieldsInfo: {Object},
* getContext: {function},
* getDomain: {function},
* groupedBy: {string[]},
@@ -160,7 +160,7 @@ var BasicModel = AbstractModel.extend({
var position = (options && options.position) || 'top';
var params = {
context: context,
- fieldAttrs: list.fieldAttrs,
+ fieldsInfo: list.fieldsInfo,
fieldNames: list.fieldNames,
fields: list.fields,
parentID: list.id,
@@ -238,7 +238,7 @@ var BasicModel = AbstractModel.extend({
var index = record.res_ids.indexOf(record.res_id);
record.res_ids.splice(index + 1, 0, res_id);
return self.load({
- fieldAttrs: record.fieldAttrs,
+ fieldsInfo: record.fieldsInfo,
fieldNames: record.fieldNames,
fields: record.fields,
modelName: record.model,
@@ -395,7 +395,7 @@ var BasicModel = AbstractModel.extend({
* @todo document all params
*
* @param {any} params
- * @param {Object} [params.fieldAttrs={}] contains the attrs of each field
+ * @param {Object} [params.fieldsInfo={}] contains the fieldInfo of each field
* @param {Array} [params.fieldNames] the name of fields to load, the list
* of all fields by default
* @param {Object} params.fields contains the description of each field
@@ -428,7 +428,7 @@ var BasicModel = AbstractModel.extend({
* @param {any} params
* @param {string} modelName model name
* @param {Object} params.context the context for the new record
- * @param {Object} [params.fieldAttrs={}] contains the attrs of each field
+ * @param {Object} [params.fieldsInfo={}] contains the fieldInfo of each field
* @param {Array} params.fieldNames the name of fields to load, the list
* of all fields by default
* @param {Object} params.fields contains the description of each field
@@ -463,7 +463,7 @@ var BasicModel = AbstractModel.extend({
data: data,
fields: params.fields,
fieldNames: params.fieldNames,
- fieldAttrs: params.fieldAttrs,
+ fieldsInfo: params.fieldsInfo,
context: params.context,
parentID: params.parentID,
relationField: params.relationField,
@@ -483,15 +483,17 @@ var BasicModel = AbstractModel.extend({
});
record._changes[name] = rec.id;
} else if (field.type === 'one2many' || field.type === 'many2many') {
- var attrs = record.fieldAttrs[name];
+ var fieldInfo = record.fieldsInfo[name];
+ var view = fieldInfo.views && fieldInfo.views[fieldInfo.mode];
+
var x2manyList = self._makeDataPoint({
context: record.context,
- fieldAttrs: field.fieldAttrs,
- fields: field.relatedFields,
- limit: field.limit,
+ fieldsInfo: fieldInfo.fieldsInfo || view && view.fieldsInfo,
+ fields: fieldInfo.relatedFields || view && view.fields,
+ limit: fieldInfo.limit,
modelName: field.relation,
parentID: record.id,
- rawContext: attrs && attrs.context,
+ rawContext: fieldInfo && fieldInfo.context,
relationField: field.relation_field,
res_ids: [],
static: true,
@@ -508,8 +510,8 @@ var BasicModel = AbstractModel.extend({
r = self._makeDataPoint({
modelName: x2manyList.model,
context: x2manyList.context,
- fields: field.relatedFields,
- fieldAttrs: field.fieldAttrs,
+ fieldsInfo: fieldInfo.fieldsInfo || view && view.fieldsInfo,
+ fields: fieldInfo.relatedFields || view && view.fields,
});
x2manyList._changes.push(r.id);
r._changes = value[2];
@@ -540,8 +542,8 @@ var BasicModel = AbstractModel.extend({
r = self._makeDataPoint({
modelName: x2manyList.model,
context: x2manyList.context,
- fields: field.relatedFields,
- fieldAttrs: field.fieldAttrs,
+ fieldsInfo: fieldInfo.fieldsInfo || view && view.fieldsInfo,
+ fields: fieldInfo.relatedFields || view && view.fields,
res_id: value,
});
if (!x2manyList._changes) {
@@ -599,10 +601,10 @@ var BasicModel = AbstractModel.extend({
*
* @param {string} model name of the model
* @param {Object[]} fields a description of field properties
- * @param {Object} [attrs] various field attrs that we want to set
+ * @param {Object} [fieldInfo] various field fieldInfo that we want to set
* @returns {string} the local id for the created resource
*/
- makeRecord: function (model, fields, attrs) {
+ makeRecord: function (model, fields, fieldInfo) {
var self = this;
var record_fields = {};
_.each(fields, function (field) {
@@ -611,7 +613,7 @@ var BasicModel = AbstractModel.extend({
var record = this._makeDataPoint({
modelName: model,
fields: record_fields,
- fieldAttrs: attrs,
+ fieldsInfo: fieldInfo,
});
_.each(fields, function (field) {
if ('value' in field) {
@@ -704,7 +706,7 @@ var BasicModel = AbstractModel.extend({
if ('currentId' in options && !options.currentId) {
var params = {
context: element.context,
- fieldAttrs: element.fieldAttrs,
+ fieldsInfo: element.fieldsInfo,
fieldNames: element.fieldNames,
fields: element.fields,
};
@@ -836,7 +838,7 @@ var BasicModel = AbstractModel.extend({
/**
* Set fieldNames.
* Set fields on a record element (current fields as defaults)
- * Set fieldattrs.
+ * Set fieldsInfo.
* It is mostly useful for the cases where a record element is shared
* between various views, such as a one2many with a tree and a form view.
*
@@ -844,22 +846,23 @@ var BasicModel = AbstractModel.extend({
* @param {Object} props
* @param {Object} props.fieldNames
* @param {Object} props.fields
- * @param {Object} props.fieldAttrs
+ * @param {Object} props.fieldsInfo
* @return {Object}
* @return {Object} result.fieldNames the previous field names
* @return {Object} result.fields the previous description fields
- * @return {Object} result.fieldattrs the previous field attrs
+ * @return {Object} result.fieldsInfo the previous field fieldInfo
*/
setFieldProps: function (recordID, props) {
var record = this.localData[recordID];
var result = {
fieldNames: record.fieldNames,
fields: record.fields,
- fieldAttrs: record.fieldAttrs,
+ fieldsInfo: record.fieldsInfo,
};
- record.fieldNames = props.fieldNames;
+ record.mode = props.mode;
+ record.fieldNames = Object.keys(props.fieldsInfo);
record.fields = _.defaults(props.fields, record.fields);
- record.fieldAttrs = props.fieldAttrs;
+ record.fieldsInfo = props.fieldsInfo;
return result;
},
/**
@@ -979,6 +982,7 @@ var BasicModel = AbstractModel.extend({
context: record.context,
data: rel_data,
fields: {},
+ fieldsInfo: {},
modelName: record.fields[fieldName].relation,
});
record._changes[fieldName] = rec.id;
@@ -1063,7 +1067,7 @@ var BasicModel = AbstractModel.extend({
var params = {
context: context,
fields: list.fields,
- fieldAttrs: list.fieldAttrs,
+ fieldsInfo: list.fieldsInfo,
modelName: list.model,
fieldNames: _.keys(command[2]),
};
@@ -1128,6 +1132,8 @@ var BasicModel = AbstractModel.extend({
var self = this;
var list = this.localData[record._changes[fieldName] || record.data[fieldName]];
var field = record.fields[fieldName];
+ var fieldInfo = record.fieldsInfo[fieldName];
+ var view = fieldInfo.views && fieldInfo.views[fieldInfo.mode];
var rec;
var defs = [];
list._changes = list._changes || list.data;
@@ -1158,8 +1164,8 @@ var BasicModel = AbstractModel.extend({
rec = self._makeDataPoint({
context: record.context,
modelName: field.relation,
- fields: field.relatedFields,
- fieldAttrs: field.fieldAttrs,
+ fields: fieldInfo.relatedFields || view && view.fields,
+ fieldsInfo: fieldInfo.fieldsInfo || view && view.fieldsInfo,
res_id: d.id,
});
list_records[d.id] = rec;
@@ -1237,9 +1243,10 @@ var BasicModel = AbstractModel.extend({
var specs = {};
_.each(record.fieldNames, function (name) {
var field = record.fields[name];
+ var fieldInfo = record.fieldsInfo[name];
specs[name] = (field.onChange) || "";
- _.each(field.views, function (view) {
- _.each(view.fieldAttrs, function (field, subname) {
+ _.each(fieldInfo.views, function (view) {
+ _.each(view.fieldsInfo, function (field, subname) {
specs[name + '.' + subname] = (view.fields[subname].onChange) || "";
});
});
@@ -1374,8 +1381,8 @@ var BasicModel = AbstractModel.extend({
var self = this;
var fieldNames = [];
return $.when.apply($, _.map(record.fieldNames, function (name) {
- var attrs = record.fieldAttrs[name] || {};
- var Widget = attrs.Widget;
+ var fieldInfo = record.fieldsInfo[name] || {};
+ var Widget = fieldInfo.Widget;
if (Widget && Widget.prototype.specialData) {
return self[Widget.prototype.specialData](record, name).then(function (data) {
if (data === undefined) {
@@ -1501,7 +1508,7 @@ var BasicModel = AbstractModel.extend({
* the undefined value.
*/
_fetchSpecialStatus: function (record, fieldName) {
- var foldField = record.fieldAttrs[fieldName].options.fold_field;
+ var foldField = record.fieldsInfo[fieldName].options.fold_field;
var fieldsToRead = foldField ? [foldField] : [];
return this._fetchSpecialMany2ones(record, fieldName, fieldsToRead).then(function (m2os) {
_.each(m2os, function (m2o) {
@@ -1525,7 +1532,7 @@ var BasicModel = AbstractModel.extend({
_fetchSpecialDomain: function (record, fieldName) {
var context = record.getContext({fieldName: fieldName});
- var domainModel = record.fieldAttrs[fieldName].options.model;
+ var domainModel = record.fieldsInfo[fieldName].options.model;
if (record.data.hasOwnProperty(domainModel)) {
domainModel = record._changes && record._changes[domainModel] || record.data[domainModel];
}
@@ -1600,14 +1607,15 @@ var BasicModel = AbstractModel.extend({
_.each(fieldNames, function (fieldName) {
var field = record.fields[fieldName];
if (field.type === 'one2many' || field.type === 'many2many') {
- var attrs = record.fieldAttrs[fieldName];
- var rawContext = attrs && attrs.context;
+ var fieldInfo = record.fieldsInfo[fieldName];
+ var rawContext = fieldInfo && fieldInfo.context;
+ var view = fieldInfo.views && fieldInfo.views[fieldInfo.mode];
var ids = record.data[fieldName] || [];
var list = self._makeDataPoint({
count: ids.length,
- fieldAttrs: field.fieldAttrs,
- fields: field.relatedFields,
- limit: field.limit,
+ fieldsInfo: fieldInfo.fieldsInfo || view && view.fieldsInfo,
+ fields: fieldInfo.relatedFields || view && view.fields,
+ limit: fieldInfo.limit,
modelName: field.relation,
res_ids: ids,
static: true,
@@ -1617,7 +1625,7 @@ var BasicModel = AbstractModel.extend({
relationField: field.relation_field,
});
record.data[fieldName] = list.id;
- if (!field.__no_fetch) {
+ if (!fieldInfo.__no_fetch) {
var def = self._readUngroupedList(list).then(function () {
return self._fetchX2ManysBatched(list);
});
@@ -1638,6 +1646,8 @@ var BasicModel = AbstractModel.extend({
_fetchX2ManyBatched: function (list, fieldName) {
var self = this;
var field = list.fields[fieldName];
+ var fieldInfo = list.fieldsInfo[fieldName];
+ var view = fieldInfo.views && fieldInfo.views[fieldInfo.mode];
// step 1: collect ids
var ids = [];
@@ -1645,8 +1655,8 @@ var BasicModel = AbstractModel.extend({
var record = self.localData[dataPoint];
ids = _.unique(ids.concat(record.data[fieldName] || []));
var m2mList = self._makeDataPoint({
- fieldAttrs: field.fieldAttrs,
- fields: field.relatedFields,
+ fieldsInfo: fieldInfo.fieldsInfo || view && view.fieldsInfo,
+ fields: fieldInfo.relatedFields || view && view.fields,
modelName: field.relation,
res_ids: record.data[fieldName],
static: true,
@@ -1655,13 +1665,13 @@ var BasicModel = AbstractModel.extend({
record.data[fieldName] = m2mList.id;
});
- if (!ids.length || field.__no_fetch) {
+ if (!ids.length || fieldInfo.__no_fetch) {
return $.when();
}
// step 2: fetch data from server
return this._rpc(field.relation, 'read')
- .args([ids, _.keys(field.relatedFields)])
+ .args([ids, _.keys(fieldInfo.relatedFields)])
.withContext({}) // FIXME
.exec()
.then(function (results) {
@@ -1670,8 +1680,8 @@ var BasicModel = AbstractModel.extend({
return self._makeDataPoint({
modelName: field.relation,
data: result,
- fields: field.relatedFields,
- fieldAttrs: field.fieldAttrs,
+ fieldsInfo: fieldInfo.fieldsInfo || view && view.fieldsInfo,
+ fields: fieldInfo.relatedFields || view && view.fields,
});
});
@@ -1796,9 +1806,9 @@ var BasicModel = AbstractModel.extend({
context.set_eval_context(this._getEvalContext(element));
if (options && options.fieldName) {
- var attrs = element.fieldAttrs[options.fieldName];
- if (attrs && attrs.context) {
- context.add(attrs.context);
+ var fieldInfo = element.fieldsInfo[options.fieldName];
+ if (fieldInfo && fieldInfo.context) {
+ context.add(fieldInfo.context);
} else {
var fieldParams = element.fields[options.fieldName];
if (fieldParams.context) {
@@ -1828,10 +1838,10 @@ var BasicModel = AbstractModel.extend({
*/
_getDomain: function (element, options) {
if (options && options.fieldName) {
- var attrs = element.fieldAttrs[options.fieldName];
- if (attrs && attrs.domain) {
+ var fieldInfo = element.fieldsInfo[options.fieldName];
+ if (fieldInfo && fieldInfo.domain) {
return Domain.prototype.stringToArray(
- attrs.domain,
+ fieldInfo.domain,
this._getEvalContext(element)
);
}
@@ -1899,7 +1909,7 @@ var BasicModel = AbstractModel.extend({
* the resource in the localData object.
*
* @param {Object} params
- * @param {Object} [params.fieldAttrs={}] contains the attrs of each field
+ * @param {Object} [params.fieldsInfo={}] contains the fieldInfo of each field
* @param {Array} [params.fieldNames] the name of fields to load, the list
* of all fields by default
* @param {Object} params.fields contains the description of each field
@@ -1907,7 +1917,6 @@ var BasicModel = AbstractModel.extend({
*/
_makeDataPoint: function (params) {
var type = params.type || ('domain' in params && 'list') || 'record';
-
var res_id, value;
var res_ids = params.res_ids || [];
if (type === 'record') {
@@ -1923,6 +1932,13 @@ var BasicModel = AbstractModel.extend({
id: {type: 'integer'},
}, params.fields);
+ if (!params.fieldsInfo) {
+ params.fieldsInfo = {};
+ for (var fieldName in fields) {
+ params.fieldsInfo[fieldName] = {};
+ }
+ }
+
var dataPoint = {
_cache: type === 'list' ? {} : undefined,
_changes: null,
@@ -1931,9 +1947,9 @@ var BasicModel = AbstractModel.extend({
count: params.count || res_ids.length,
data: params.data || (type === 'record' ? {} : []),
domain: params.domain || [],
- fieldNames: params.fieldNames || Object.keys(fields),
+ fieldNames: params.fieldNames || Object.keys(params.fieldsInfo),
fields: fields,
- fieldAttrs: params.fieldAttrs || {},
+ fieldsInfo: params.fieldsInfo || {},
groupedBy: params.groupedBy || [],
id: _.uniqueId(params.modelName + '_'),
isOpen: params.isOpen,
@@ -1979,6 +1995,10 @@ var BasicModel = AbstractModel.extend({
// the many2one value is of the form [id, display_name]
var r = self._makeDataPoint({
modelName: field.relation,
+ fields: {
+ display_name: {type: 'char'},
+ id: {type: 'integer'},
+ },
data: {
display_name: val[1],
id: val[0],
@@ -2013,8 +2033,8 @@ var BasicModel = AbstractModel.extend({
var defs = [];
_.each(record.fieldNames, function (name) {
var field = record.fields[name];
- var attrs = record.fieldAttrs[name] || {};
- var options = attrs.options || {};
+ var fieldInfo = record.fieldsInfo[name] || {};
+ var options = fieldInfo.options || {};
if (options.always_reload) {
if (record.fields[name].type === 'many2one' && record.data[name]) {
var element = self.localData[record.data[name]];
@@ -2076,7 +2096,7 @@ var BasicModel = AbstractModel.extend({
context: list.context,
fields: list.fields,
fieldNames: list.fieldNames,
- fieldAttrs: list.fieldAttrs,
+ fieldsInfo: list.fieldsInfo,
value: group[rawGroupBy],
aggregateValues: aggregateValues,
groupedBy: list.groupedBy.slice(1),
@@ -2152,7 +2172,7 @@ var BasicModel = AbstractModel.extend({
} else {
dataPoint = self._makeDataPoint({
data: _.findWhere(records, {id: id}),
- fieldAttrs: list.fieldAttrs,
+ fieldsInfo: list.fieldsInfo,
fieldNames: list.fieldNames,
fields: list.fields,
modelName: list.model,
@@ -2211,7 +2231,7 @@ var BasicModel = AbstractModel.extend({
data: record,
fields: list.fields,
fieldNames: list.fieldNames,
- fieldAttrs: list.fieldAttrs,
+ fieldsInfo: list.fieldsInfo,
modelName: list.model,
parentID: list.id,
});
diff --git a/addons/web/static/src/js/views/basic/basic_view.js b/addons/web/static/src/js/views/basic/basic_view.js
index 35c0dd5b6f0..5b8a3a7d0c9 100644
--- a/addons/web/static/src/js/views/basic/basic_view.js
+++ b/addons/web/static/src/js/views/basic/basic_view.js
@@ -13,23 +13,6 @@ odoo.define('web.BasicView', function (require) {
var AbstractView = require('web.AbstractView');
var BasicController = require('web.BasicController');
var BasicModel = require('web.BasicModel');
-var fieldRegistry = require('web.field_registry');
-var pyeval = require('web.pyeval');
-
-/**
- * Visit a tree of objects, where each children are in an attribute 'children'.
- * For each children, we call the callback function given in arguments.
- *
- * @todo move this somewhere in web.utils
- *
- * @param {Object} tree an object describing a tree structure
- * @param {function} f a callback
- */
-function traverse(tree, f) {
- if (f(tree)) {
- _.each(tree.children, function (c) { traverse(c, f); });
- }
-}
var BasicView = AbstractView.extend({
config: _.extend({}, AbstractView.prototype.config, {
@@ -45,51 +28,21 @@ var BasicView = AbstractView.extend({
* augmented with their attrs and some flags if they require a
* particular handling.
*
- * @param {Object} arch
- * @param {Object} fields
+ * @param {Object} viewInfo
* @param {Object} params
*/
- init: function (arch, fields, params) {
+ init: function (viewInfo, params) {
this._super.apply(this, arguments);
- var result = this._processFieldsView(arch, fields);
- var fieldAttrs = result.fieldAttrs;
- var viewFields = result.view_fields;
- var fieldNames = _.keys(viewFields);
- fields = _.defaults(viewFields, fields);
- var self = this;
- // 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
- for (var fieldName in fields) {
- var field = fields[fieldName];
- _.each(field.views, function (innerFieldsView) {
- result = self._processFieldsView(innerFieldsView.arch, innerFieldsView.fields);
- innerFieldsView.fieldAttrs = result.fieldAttrs;
- innerFieldsView.fields = result.view_fields;
- });
- if (field.type === 'one2many' || field.type === 'many2many') {
- field.relatedFields = {
- color: {type: 'int'},
- display_name: {type: 'char'},
- id: {type: 'integer'},
- };
- field.fieldAttrs = {};
- }
- }
-
this.controllerParams.confirmOnDelete = true;
- this.controllerParams.archiveEnabled = 'active' in fields;
+ this.controllerParams.archiveEnabled = 'active' in viewInfo.fields;
this.controllerParams.hasButtons =
'action_buttons' in params ? params.action_buttons : true;
- this.loadParams.fieldAttrs = fieldAttrs;
- this.loadParams.fieldNames = fieldNames;
- this.loadParams.fields = fields;
- this.loadParams.limit = parseInt(arch.attrs.limit, 10) || params.limit;
+ this.loadParams.fieldsInfo = viewInfo.fieldsInfo;
+ this.loadParams.fieldNames = _.keys(viewInfo.fieldsInfo);
+ this.loadParams.fields = viewInfo.fields;
+ this.loadParams.limit = parseInt(viewInfo.arch.attrs.limit, 10) || params.limit;
this.recordID = params.recordID;
},
@@ -116,76 +69,6 @@ var BasicView = AbstractView.extend({
}
return this._super.apply(this, arguments);
},
- /**
- * Visit all nodes in the arch field and process each fields
- *
- * @param {Object} arch
- * @param {Object} fields
- * @returns {Object} An object with 2 keys: view_fields and fieldAttrs
- */
- _processFieldsView: function (arch, fields) {
- var self = this;
- var viewFields = Object.create(null);
- var fieldAttrs = Object.create(null);
- traverse(arch, function (node) {
- if (typeof node === 'string') {
- return false;
- }
- if (node.tag === 'field') {
- var attrs = node.attrs ? _.clone(node.attrs) : {};
- var field = _.clone(fields[node.attrs.name]);
- self._processField(field, attrs);
- viewFields[node.attrs.name] = field;
- fieldAttrs[node.attrs.name] = attrs;
- return false;
- }
- return node.tag !== 'arch';
- });
- return {
- view_fields: viewFields,
- fieldAttrs: fieldAttrs,
- };
- },
- /**
- * Process a field node, in particular, put a flag on the field to give
- * special directives to the BasicModel.
- *
- * @param {Object} field - the field properties
- * @param {Object} attrs - the field attributes (from the xml)
- */
- _processField: function (field, attrs) {
- attrs.Widget = this._getFieldWidgetClass(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 = "1";
- }
- },
-
- /**
- * 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 {Object} field
- * @param {Object} attrs
- * @returns {function|null} AbstractField specialization Class
- */
- _getFieldWidgetClass: function (field, attrs) {
- var viewName = this.rendererParams.arch.tag;
-
- var Widget;
- if (attrs.widget) {
- Widget = fieldRegistry.getAny([viewName + "." + attrs.widget, attrs.widget]);
- if (!Widget) {
- console.warn("Missing widget: ", attrs.widget, " for field", attrs.name, "of type", field.type);
- }
- }
- return Widget || fieldRegistry.getAny([viewName + "." + field.type, field.type, "abstract"]);
- },
});
return BasicView;
diff --git a/addons/web/static/src/js/views/calendar/calendar_model.js b/addons/web/static/src/js/views/calendar/calendar_model.js
index 6617854e9ad..07327616097 100644
--- a/addons/web/static/src/js/views/calendar/calendar_model.js
+++ b/addons/web/static/src/js/views/calendar/calendar_model.js
@@ -151,6 +151,7 @@ return AbstractModel.extend({
this.modelName = params.modelName;
this.fields = params.fields;
this.fieldNames = params.fieldNames;
+ this.fieldsInfo = params.fieldsInfo;
this.mapping = params.mapping;
this.mode = params.mode; // one of month, week or day
this.scales = params.scales; // one of month, week or day
diff --git a/addons/web/static/src/js/views/calendar/calendar_view.js b/addons/web/static/src/js/views/calendar/calendar_view.js
index f72dc8e640e..3bd8099484b 100644
--- a/addons/web/static/src/js/views/calendar/calendar_view.js
+++ b/addons/web/static/src/js/views/calendar/calendar_view.js
@@ -26,8 +26,10 @@ var CalendarView = AbstractView.extend({
Controller: CalendarController,
Renderer: CalendarRenderer,
},
- init: function (arch, fields, params) {
+ init: function (viewInfo, params) {
this._super.apply(this, arguments);
+ var arch = viewInfo.arch;
+ var fields = viewInfo.fields;
var attrs = arch.attrs;
if (!attrs.date_start) {
@@ -121,6 +123,7 @@ var CalendarView = AbstractView.extend({
this.loadParams.fieldNames = _.uniq(fieldNames);
this.loadParams.mapping = mapping;
this.loadParams.fields = fields;
+ this.loadParams.fieldsInfo = viewInfo.fieldsInfo;
this.loadParams.editable = !this.controllerParams.read_only_mode && !fields[mapping.date_start].readonly;
this.loadParams.eventLimit = eventLimit;
this.loadParams.field_color = attrs.color;
diff --git a/addons/web/static/src/js/views/form/form_controller.js b/addons/web/static/src/js/views/form/form_controller.js
index 341d23e0bed..940d27d386c 100644
--- a/addons/web/static/src/js/views/form/form_controller.js
+++ b/addons/web/static/src/js/views/form/form_controller.js
@@ -66,7 +66,7 @@ var FormController = BasicController.extend({
var record = this.model.get(this.handle, {raw: true});
return this.model.makeDefaultRecord(this.modelName, {
context: this.context,
- fieldAttrs: record.fieldAttrs,
+ fieldsInfo: record.fieldsInfo,
fieldNames: record.fieldNames,
fields: record.fields,
res_ids: record.res_ids,
@@ -408,6 +408,7 @@ var FormController = BasicController.extend({
*/
_onAddOne2ManyRecord: function (event) {
var field = event.data.field;
+ var attrs = event.data.attrs;
new dialogs.FormViewDialog(this, {
res_model: field.relation,
shouldSaveLocally: true,
@@ -416,7 +417,7 @@ var FormController = BasicController.extend({
on_save: event.data.on_save,
title: _t('Create: ') + field.string,
initial_view: 'form',
- fields_view: field.views ? field.views.form : undefined,
+ fields_view: attrs.views ? attrs.views.form : undefined,
form_view_options: {'not_interactible_on_create': true},
model: this.model,
parentID: this.handle,
@@ -520,7 +521,7 @@ var FormController = BasicController.extend({
var res_id = record.res_id;
var fieldsViewDef;
if (event.data.form_view) {
- fieldsViewDef = $.when(event.data.form_view);
+ fieldsViewDef = $.when({form: event.data.form_view});
} else {
fieldsViewDef = this.loadViews(model, new Context(event.data.context), [[null, 'form']], {});
}
diff --git a/addons/web/static/src/js/views/form/form_renderer.js b/addons/web/static/src/js/views/form/form_renderer.js
index c5f4ba9044a..e477daf930a 100644
--- a/addons/web/static/src/js/views/form/form_renderer.js
+++ b/addons/web/static/src/js/views/form/form_renderer.js
@@ -268,7 +268,8 @@ return BasicRenderer.extend({
required: is_required,
idForLabel: this._getIDForLabel(name),
};
- var widget = new this.state.fieldAttrs[name].Widget(this, name, this.state, options);
+ var attrs = this.state.fieldsInfo[name];
+ var widget = new attrs.Widget(this, name, this.state, options);
this.widgets.push(widget);
var def = widget.__widgetRenderAndInsert(function () {});
if (def.state() === 'pending') {
diff --git a/addons/web/static/src/js/views/form/form_view.js b/addons/web/static/src/js/views/form/form_view.js
index 6578c7ada15..32f78136e50 100644
--- a/addons/web/static/src/js/views/form/form_view.js
+++ b/addons/web/static/src/js/views/form/form_view.js
@@ -5,7 +5,6 @@ var BasicView = require('web.BasicView');
var FormRenderer = require('web.FormRenderer');
var FormController = require('web.FormController');
var Context = require('web.Context');
-var config = require('web.config');
var core = require('web.core');
var _lt = core._lt;
@@ -23,7 +22,7 @@ var FormView = BasicView.extend({
/**
* @override
*/
- init: function (arch, fields, params) {
+ init: function (viewInfo, params) {
this._super.apply(this, arguments);
var mode = params.mode || (params.currentId ? 'readonly' : 'edit');
@@ -51,45 +50,23 @@ var FormView = BasicView.extend({
var defs = [];
var fields = this.loadParams.fields;
- _.each(self.loadParams.fieldAttrs, function (attrs, fieldName) {
+ _.each(self.loadParams.fieldsInfo, function (attrs, fieldName) {
var field = fields[fieldName];
if (field.type !== 'one2many' && field.type !== 'many2many') {
return;
}
- if (attrs.Widget.prototype.useSubview && !(attrs.invisible && JSON.parse(attrs.invisible))) {
- var mode = attrs.mode;
- if (!mode) {
- if (field.views.tree && field.views.kanban) {
- mode = 'tree';
- } else if (!field.views.tree && field.views.kanban) {
- mode = 'kanban';
- } else {
- mode = 'tree,kanban';
- }
- }
- if (mode.indexOf(',') !== -1) {
- mode = config.device.size_class !== config.device.SIZES.XS ? 'tree' : 'kanban';
- }
- if (field.views[mode]) {
- field.relatedFields = field.views[mode].fields;
- field.fieldAttrs = field.views[mode].fieldAttrs;
- field.limit = mode === "tree" ? 80 : 40;
- return;
- }
+ attrs.limit = attrs.mode === "tree" ? 80 : 40;
+
+ if (attrs.Widget.prototype.useSubview && !(attrs.invisible && JSON.parse(attrs.invisible)) && !attrs.views[attrs.mode]) {
defs.push(parent.loadViews(
field.relation,
new Context(self.loadParams.context),
- [[null, mode === 'tree' ? 'list' : mode]],
+ [[null, attrs.mode === 'tree' ? 'list' : attrs.mode]],
{})
.then(function (views) {
for (var viewName in views) {
- var view = views[viewName];
- var fieldView = self._processFieldsView(view.arch, view.fields);
- field.views[viewName === 'list' ? 'tree' : viewName] = view;
- field.relatedFields = fieldView.view_fields;
- field.fieldAttrs = fieldView.fieldAttrs;
- view.fieldAttrs = fieldView.fieldAttrs;
+ attrs.views[viewName] = views[viewName];
}
}));
}
diff --git a/addons/web/static/src/js/views/graph/graph_view.js b/addons/web/static/src/js/views/graph/graph_view.js
index 3422a0922d3..1d4ee29ef63 100644
--- a/addons/web/static/src/js/views/graph/graph_view.js
+++ b/addons/web/static/src/js/views/graph/graph_view.js
@@ -27,13 +27,13 @@ var GraphView = AbstractView.extend({
/**
* @override
*/
- init: function (arch, fields) {
+ init: function (viewInfo) {
this._super.apply(this, arguments);
var initialMeasure = '__count__';
var initialGroupBys = [];
- fields.__count__ = {string: _t("Count"), type: "integer"};
- arch.children.forEach(function (field) {
+ viewInfo.fields = _.defaults({__count__: {string: _t("Count"), type: "integer"}}, viewInfo.fields);
+ viewInfo.arch.children.forEach(function (field) {
var name = field.attrs.name;
if (field.attrs.interval) {
name += ':' + field.attrs.interval;
@@ -46,7 +46,7 @@ var GraphView = AbstractView.extend({
});
var measures = {__count__: {string: _t("Count"), type: "integer"}};
- _.each(fields, function (field, name) {
+ _.each(viewInfo.fields, function (field, name) {
if (name !== 'id' && field.store === true) {
if (field.type === 'integer' || field.type === 'float' || field.type === 'monetary') {
measures[name] = field;
@@ -55,12 +55,12 @@ var GraphView = AbstractView.extend({
});
this.controllerParams.measures = measures;
- this.rendererParams.stacked = arch.attrs.stacked !== "False";
+ this.rendererParams.stacked = viewInfo.arch.attrs.stacked !== "False";
- this.loadParams.initialMode = arch.attrs.type || 'bar';
+ this.loadParams.initialMode = viewInfo.arch.attrs.type || 'bar';
this.loadParams.initialMeasure = initialMeasure;
this.loadParams.initialGroupBys = initialGroupBys;
- this.loadParams.fields = fields;
+ this.loadParams.fields = viewInfo.fields;
},
});
diff --git a/addons/web/static/src/js/views/kanban/kanban_model.js b/addons/web/static/src/js/views/kanban/kanban_model.js
index c600ab48b1e..454349a88c5 100644
--- a/addons/web/static/src/js/views/kanban/kanban_model.js
+++ b/addons/web/static/src/js/views/kanban/kanban_model.js
@@ -28,7 +28,7 @@ var KanbanModel = BasicModel.extend({
modelName: group.model,
fields: group.fields,
fieldNames: group.fieldNames,
- fieldAttrs: group.fieldAttrs,
+ fieldsInfo: group.fieldsInfo,
});
group.data.unshift(new_record);
group.count++;
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 542b25cdd0a..4217e4d25bb 100644
--- a/addons/web/static/src/js/views/kanban/kanban_record.js
+++ b/addons/web/static/src/js/views/kanban/kanban_record.js
@@ -27,7 +27,7 @@ var KanbanRecord = Widget.extend({
this._super(parent);
this.fields = state.fields;
- this.fieldAttrs = state.fieldAttrs;
+ this.fieldsInfo = state.fieldsInfo;
this.modelName = state.model;
this.options = options;
@@ -83,7 +83,7 @@ var KanbanRecord = Widget.extend({
var widget = self.subWidgets[field_name];
if (!widget) {
// the widget doesn't exist yet, so instanciate it
- var Widget = self.fieldAttrs[field_name].Widget;
+ var Widget = self.fieldsInfo[field_name].Widget;
if (Widget) {
// some field's attrs might be record dependent (they start with
// 't-att-') and should thus be evaluated, which is done by qweb
@@ -93,14 +93,14 @@ var KanbanRecord = Widget.extend({
// that dict being shared between records, we don't modify it
// in place
var attrs = Object.create(null);
- _.each(self.fieldAttrs[field_name], function (value, key) {
+ _.each(self.fieldsInfo[field_name], function (value, key) {
if (_.str.startsWith(key, 't-att-')) {
key = key.slice(6);
value = $field.attr(key);
}
attrs[key] = value;
});
- self.fieldAttrs[field_name] = attrs;
+ self.fieldsInfo[field_name] = attrs;
widget = new Widget(self, field_name, self.state, self.options);
self.subWidgets[field_name] = widget;
@@ -276,14 +276,14 @@ var KanbanRecord = Widget.extend({
*/
_setFieldDisplay: function (widget, fieldName) {
// attribute display
- if (this.fieldAttrs[fieldName].display === 'right') {
+ if (this.fieldsInfo[fieldName].display === 'right') {
widget.$el.addClass('pull-right');
- } else if (this.fieldAttrs[fieldName].display === 'full') {
+ } else if (this.fieldsInfo[fieldName].display === 'full') {
widget.$el.addClass('o_text_block');
}
// attribute bold
- if (this.fieldAttrs[fieldName].bold) {
+ if (this.fieldsInfo[fieldName].bold) {
widget.$el.addClass('o_text_bold');
}
},
diff --git a/addons/web/static/src/js/views/kanban/kanban_view.js b/addons/web/static/src/js/views/kanban/kanban_view.js
index 73949004952..9c8c03dfb27 100644
--- a/addons/web/static/src/js/views/kanban/kanban_view.js
+++ b/addons/web/static/src/js/views/kanban/kanban_view.js
@@ -20,9 +20,10 @@ var KanbanView = BasicView.extend({
Controller: KanbanController,
Renderer: KanbanRenderer,
},
- init: function (arch, fields, params) {
+ init: function (viewInfo, params) {
this._super.apply(this, arguments);
+ var arch = viewInfo.arch;
var activeActions = this.controllerParams.activeActions;
activeActions = _.extend(activeActions, {
group_edit: arch.attrs.group_edit ? JSON.parse(arch.attrs.group_edit) : true,
diff --git a/addons/web/static/src/js/views/list/list_editable_renderer.js b/addons/web/static/src/js/views/list/list_editable_renderer.js
index 9e83a45a5fc..0c6a9a4c9ce 100644
--- a/addons/web/static/src/js/views/list/list_editable_renderer.js
+++ b/addons/web/static/src/js/views/list/list_editable_renderer.js
@@ -175,7 +175,7 @@ ListRenderer.include({
if (field.readonly) {
return true;
}
- var Widget = this.state.fieldAttrs[node.attrs.name].Widget;
+ var Widget = this.state.fieldsInfo[node.attrs.name].Widget;
if (Widget && Widget.prototype.readonly) {
return true;
}
@@ -268,7 +268,7 @@ ListRenderer.include({
return;
}
var $td = this._findTd($row, colIndex);
- var widget = new this.state.fieldAttrs[name].Widget(this, name, record, {
+ var widget = new this.state.fieldsInfo[name].Widget(this, name, record, {
mode: 'edit'
});
if (widget.replace_element) {
diff --git a/addons/web/static/src/js/views/list/list_renderer.js b/addons/web/static/src/js/views/list/list_renderer.js
index 4d651198044..041fb2f6ee4 100644
--- a/addons/web/static/src/js/views/list/list_renderer.js
+++ b/addons/web/static/src/js/views/list/list_renderer.js
@@ -285,7 +285,7 @@ var ListRenderer = BasicRenderer.extend({
}
var name = node.attrs.name;
if (node.attrs.widget) {
- var widget = new this.state.fieldAttrs[name].Widget(this, name, record, {
+ var widget = new this.state.fieldsInfo[name].Widget(this, name, record, {
mode: 'readonly',
});
widget.appendTo($td);
@@ -505,7 +505,7 @@ var ListRenderer = BasicRenderer.extend({
}
var description;
if (node.attrs.widget) {
- description = this.state.fieldAttrs[name].Widget.prototype.description;
+ description = this.state.fieldsInfo[name].Widget.prototype.description;
}
if (description === undefined) {
description = node.attrs.string || field.string;
diff --git a/addons/web/static/src/js/views/list/list_view.js b/addons/web/static/src/js/views/list/list_view.js
index a616e9704df..4ec16ef35f4 100644
--- a/addons/web/static/src/js/views/list/list_view.js
+++ b/addons/web/static/src/js/views/list/list_view.js
@@ -27,15 +27,15 @@ var ListView = BasicView.extend({
/**
* @override
*
- * @param {Object} arch
- * @param {Object} fields
+ * @param {Object} viewInfo
* @param {Object} params
* @param {boolean} params.sidebar
* @param {boolean} [params.hasSelectors=true]
*/
- init: function (arch, fields, params) {
+ init: function (viewInfo, params) {
this._super.apply(this, arguments);
+ var arch = viewInfo.arch;
this.controllerParams.editable = arch.attrs.editable;
this.controllerParams.hasSidebar = params.sidebar;
this.controllerParams.noContentHelp = params.action && params.action.help;
diff --git a/addons/web/static/src/js/views/pivot/pivot_view.js b/addons/web/static/src/js/views/pivot/pivot_view.js
index 777d9bcb5a7..83bd32de830 100644
--- a/addons/web/static/src/js/views/pivot/pivot_view.js
+++ b/addons/web/static/src/js/views/pivot/pivot_view.js
@@ -31,9 +31,13 @@ var PivotView = AbstractView.extend({
* @override
* @param {Object} params
*/
- init: function (arch, fields, params) {
+ init: function (viewInfo, params) {
this._super.apply(this, arguments);
+ var arch = viewInfo.arch;
+ var fields = _.extend({
+ __count: {string: _t("Count"), type: "integer"}
+ }, viewInfo.fields);
var activeMeasures = [];
var colGroupBys = [];
var rowGroupBys = [];
@@ -82,7 +86,6 @@ var PivotView = AbstractView.extend({
if ((!activeMeasures.length) || arch.attrs.display_quantity) {
activeMeasures.push('__count');
}
- fields.__count = {string: _t("Count"), type: "integer"};
this.loadParams.measures = activeMeasures;
this.loadParams.colGroupBys = colGroupBys;
diff --git a/addons/web/static/src/js/views/view_dialogs.js b/addons/web/static/src/js/views/view_dialogs.js
index b9870a78e56..2275830fe33 100644
--- a/addons/web/static/src/js/views/view_dialogs.js
+++ b/addons/web/static/src/js/views/view_dialogs.js
@@ -137,7 +137,7 @@ var FormViewDialog = ViewDialog.extend({
this._super(parent, options);
},
/**
- * If we changed some fieldAttrs, we need to restore them now.
+ * If we changed some fieldsInfo, we need to restore them now.
*/
destroy: function () {
if (this.recordID && this.previousFieldProps) {
@@ -166,15 +166,11 @@ var FormViewDialog = ViewDialog.extend({
fields_view_def = this.loadFieldView(this.dataset, this.options.view_id, 'form');
}
- fields_view_def.then(function (fields_view) {
+ fields_view_def.then(function (viewInfo) {
if (self.recordID) {
- self.previousFieldProps = self.model.setFieldProps(self.recordID, {
- fieldNames: Object.keys(fields_view.fields),
- fields: fields_view.fields,
- fieldAttrs: fields_view.fieldAttrs
- });
+ self.previousFieldProps = self.model.setFieldProps(self.recordID, viewInfo);
}
- var formview = new FormView(fields_view.arch, fields_view.fields, {
+ var formview = new FormView(viewInfo, {
modelName: self.res_model,
context: self.context,
ids: self.res_id ? [self.res_id] : [],
@@ -337,7 +333,7 @@ var SelectCreateDialog = ViewDialog.extend({
return $.when(searchDef).then(function (searchResult) {
// Set the list view
- var listView = new ListView(fields_views.list.arch, fields_views.list.fields, _.extend({
+ var listView = new ListView(fields_views.list, _.extend({
context: searchResult.context,
domain: searchResult.domain,
groupBy: searchResult.groupBy,
diff --git a/addons/web/static/src/js/widgets/domain_selector.js b/addons/web/static/src/js/widgets/domain_selector.js
index 61b43c46ae7..670e620c2b3 100644
--- a/addons/web/static/src/js/widgets/domain_selector.js
+++ b/addons/web/static/src/js/widgets/domain_selector.js
@@ -383,7 +383,7 @@ var DomainLeaf = DomainNode.extend({
this.displayValue = this.value;
try {
var f = this.fieldSelector.selectedField;
- if (!f.relation) { // TODO in this case, the value should be m2o input, etc...
+ if (f && !f.relation) { // TODO in this case, the value should be m2o input, etc...
this.displayValue = field_utils.format[f.type](this.value, f);
}
} catch (err) {/**/}