143 lines
5.9 KiB
JavaScript
143 lines
5.9 KiB
JavaScript
flectra.define('web.BasicView', function (require) {
|
|
"use strict";
|
|
|
|
/**
|
|
* The BasicView is an abstract class designed to share code between views that
|
|
* want to use a basicModel. As of now, it is the form view, the list view and
|
|
* the kanban view.
|
|
*
|
|
* The main focus of this class is to process the arch and extract field
|
|
* attributes, as well as some other useful informations.
|
|
*/
|
|
|
|
var AbstractView = require('web.AbstractView');
|
|
var BasicController = require('web.BasicController');
|
|
var BasicModel = require('web.BasicModel');
|
|
|
|
var BasicView = AbstractView.extend({
|
|
config: _.extend({}, AbstractView.prototype.config, {
|
|
Model: BasicModel,
|
|
Controller: BasicController,
|
|
}),
|
|
viewType: undefined,
|
|
/**
|
|
* process the fields_view to find all fields appearing in the views.
|
|
* list those fields' name in this.fields_name, which will be the list
|
|
* of fields read when data is fetched.
|
|
* this.fields is the list of all field's description (the result of
|
|
* the fields_get), where the fields appearing in the fields_view are
|
|
* augmented with their attrs and some flags if they require a
|
|
* particular handling.
|
|
*
|
|
* @param {Object} viewInfo
|
|
* @param {Object} params
|
|
*/
|
|
init: function (viewInfo, params) {
|
|
this._super.apply(this, arguments);
|
|
|
|
this.rendererParams.viewType = this.viewType;
|
|
|
|
this.controllerParams.confirmOnDelete = true;
|
|
this.controllerParams.archiveEnabled = 'active' in viewInfo.fields;
|
|
this.controllerParams.hasButtons =
|
|
'action_buttons' in params ? params.action_buttons : true;
|
|
|
|
this.loadParams.fieldsInfo = viewInfo.fieldsInfo;
|
|
this.loadParams.fields = viewInfo.fields;
|
|
this.loadParams.context = params.context || {};
|
|
this.loadParams.limit = parseInt(viewInfo.arch.attrs.limit, 10) || params.limit;
|
|
this.loadParams.viewType = this.viewType;
|
|
this.loadParams.parentID = params.parentID;
|
|
this.recordID = params.recordID;
|
|
|
|
this.model = params.model;
|
|
},
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Private
|
|
//--------------------------------------------------------------------------
|
|
|
|
/**
|
|
* In some cases, we already have a preloaded record
|
|
*
|
|
* @override
|
|
* @private
|
|
* @returns {Deferred}
|
|
*/
|
|
_loadData: function () {
|
|
if (this.recordID) {
|
|
var self = this;
|
|
var record = this.model.get(this.recordID);
|
|
var viewType = this.viewType;
|
|
var viewFields = Object.keys(record.fieldsInfo[viewType]);
|
|
var fieldNames = _.difference(viewFields, Object.keys(record.data));
|
|
var fieldsInfo = record.fieldsInfo[viewType];
|
|
|
|
// Suppose that in a form view, there is an x2many list view with
|
|
// a field F, and that F is also displayed in the x2many form view.
|
|
// In this case, F is represented in record.data (as it is known by
|
|
// the x2many list view), but the loaded information may not suffice
|
|
// in the form view (e.g. if field is a many2many list in the form
|
|
// view, or if it is displayed by a widget requiring specialData).
|
|
// So when this happens, F is added to the list of fieldNames to fetch.
|
|
_.each(viewFields, function (name) {
|
|
if (!_.contains(fieldNames, name)) {
|
|
var fieldType = record.fields[name].type;
|
|
var fieldInfo = fieldsInfo[name];
|
|
|
|
// SpecialData case: field requires specialData that haven't
|
|
// been fetched yet.
|
|
if (fieldInfo.Widget) {
|
|
var requiresSpecialData = fieldInfo.Widget.prototype.specialData;
|
|
if (requiresSpecialData && !(name in record.specialData)) {
|
|
fieldNames.push(name);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// X2Many case: field is an x2many displayed as a list or
|
|
// kanban view, but the related fields haven't been loaded yet.
|
|
if ((fieldType === 'one2many' || fieldType === 'many2many')) {
|
|
if (!('fieldsInfo' in record.data[name])) {
|
|
fieldNames.push(name);
|
|
} else {
|
|
var fieldViews = fieldInfo.views || fieldInfo.fieldsInfo || {};
|
|
var fieldViewTypes = Object.keys(fieldViews);
|
|
var recordViewTypes = Object.keys(record.data[name].fieldsInfo);
|
|
if (_.difference(fieldViewTypes, recordViewTypes).length) {
|
|
fieldNames.push(name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
var def;
|
|
if (fieldNames.length) {
|
|
// Some fields in the new view weren't in the previous one, so
|
|
// we might have stored changes for them (e.g. coming from
|
|
// onchange RPCs), that we haven't been able to process earlier
|
|
// (because those fields were unknow at that time). So we ask
|
|
// the model to process them.
|
|
def = this.model.applyRawChanges(record.id, viewType).then(function () {
|
|
if (!self.model.isNew(record.id)) {
|
|
return self.model.reload(record.id, {
|
|
fieldNames: fieldNames,
|
|
keepChanges: true,
|
|
viewType: viewType,
|
|
});
|
|
}
|
|
});
|
|
}
|
|
return $.when(def).then(function () {
|
|
return record.id;
|
|
});
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
|
|
return BasicView;
|
|
|
|
});
|