diff options
| author | Christophe Matthieu <chm@odoo.com> | 2017-03-21 15:30:58 +0100 |
|---|---|---|
| committer | Aaron Bohy <aab@odoo.com> | 2017-04-11 19:44:38 +0200 |
| commit | eaa66d11568b415b8d6b4c7a17a058b5ec1df4a6 (patch) | |
| tree | 822fe86e984e69f989c3574936fe1792ae96fe9b /addons/web/static/src | |
| parent | e1eea38f2f940fbe252273a5a9d4d03474f81d0a (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')
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) {/**/} |
