flectra/addons/web/static/src/js/views/basic/basic_view.js
2018-01-16 02:34:37 -08:00

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;
});