You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

228 lines
7.9 KiB

/* Copyright 2015 Holger Brunn <hbrunn@therp.nl>
* Copyright 2016 Pedro M. Baeza <pedro.baeza@tecnativa.com>
* Copyright 2018 Simone Orsi <simone.orsi@camptocamp.com>
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
odoo.define('web_widget_x2many_2d_matrix.widget', function (require) {
"use strict";
var field_registry = require('web.field_registry');
var relational_fields = require('web.relational_fields');
var X2Many2dMatrixRenderer = require(
'web_widget_x2many_2d_matrix.X2Many2dMatrixRenderer'
);
var WidgetX2Many2dMatrix = relational_fields.FieldOne2Many.extend({
widget_class: 'o_form_field_x2many_2d_matrix',
/**
* Initialize the widget & parameters.
*
* @param {Object} parent contains the form view.
* @param {String} name the name of the field.
* @param {Object} record information about the database records.
* @param {Object} options view options.
*/
init: function (parent, name, record, options) {
this._super(parent, name, record, options);
this.init_params();
},
/**
* Initialize the widget specific parameters.
* Sets the axis and the values.
*/
init_params: function () {
var node = this.attrs;
this.by_x_axis = {};
this.by_y_axis = {};
this.field_x_axis = node.field_x_axis || this.field_x_axis;
this.field_y_axis = node.field_y_axis || this.field_y_axis;
this.field_label_x_axis =
node.field_label_x_axis || this.field_x_axis;
this.field_label_y_axis =
node.field_label_y_axis || this.field_y_axis;
this.x_axis_clickable = this.parse_boolean(
node.x_axis_clickable || '1'
);
this.y_axis_clickable = this.parse_boolean(
node.y_axis_clickable || '1'
);
this.field_value = node.field_value || this.field_value;
// TODO: is this really needed? Holger?
for (var property in node) {
if (property.startsWith("field_att_")) {
this.fields_att[property.substring(10)] =
node[property];
}
}
this.show_row_totals =
this.parse_boolean(node.show_row_totals || '1');
this.show_column_totals =
this.parse_boolean(node.show_column_totals || '1');
},
/**
* Initializes the Value matrix.
*
* Puts the values in the grid.
* If we have related items we use the display name.
*/
init_matrix: function () {
var records = this.recordData[this.name].data;
// Wipe the content if something still exists
this.by_x_axis = {};
this.by_y_axis = {};
_.each(records, function (record) {
var x = record.data[this.field_x_axis],
y = record.data[this.field_y_axis];
if (x.type === 'record') {
// We have a related record
x = x.data.display_name;
}
if (y.type === 'record') {
// We have a related record
y = y.data.display_name;
}
this.by_x_axis[x] = this.by_x_axis[x] || {};
this.by_y_axis[y] = this.by_y_axis[y] || {};
this.by_x_axis[x][y] = record;
this.by_y_axis[y][x] = record;
}.bind(this));
// Init columns
this.columns = [];
$.each(this.by_x_axis, function (x) {
this.columns.push(this._make_column(x));
}.bind(this));
this.rows = [];
$.each(this.by_y_axis, function (y) {
this.rows.push(this._make_row(y));
}.bind(this));
this.matrix_data = {
'field_value': this.field_value,
'field_x_axis': this.field_x_axis,
'field_y_axis': this.field_y_axis,
'columns': this.columns,
'rows': this.rows,
'show_row_totals': this.show_row_totals,
'show_column_totals': this.show_column_totals,
};
},
/**
* Create scaffold for a column.
*
* @param {String} x The string used as a column title
* @returns {Object}
*/
_make_column: function (x) {
return {
// Simulate node parsed on xml arch
'tag': 'field',
'attrs': {
'name': this.field_x_axis,
'string': x,
},
};
},
/**
* Create scaffold for a row.
*
* @param {String} y The string used as a row title
* @returns {Object}
*/
_make_row: function (y) {
var self = this;
// Use object so that we can attach more data if needed
var row = {
'tag': 'field',
'attrs': {
'name': this.field_y_axis,
'string': y,
},
'data': [],
};
$.each(self.by_x_axis, function (x) {
row.data.push(self.by_y_axis[y][x]);
});
return row;
},
/**
* Parse a String containing a bool and convert it to a JS bool.
*
* @param {String} val: the string to be parsed.
* @returns {Boolean} The parsed boolean.
*/
parse_boolean: function (val) {
if (val.toLowerCase() === 'true' || val === '1') {
return true;
}
return false;
},
/**
* Create the matrix renderer and add its output to our element
*
* @returns {Deferred}
* A deferred object to be completed when it finished rendering.
*/
_render: function () {
if (!this.view) {
return this._super();
}
// Ensure widget is re initiated when rendering
this.init_matrix();
var arch = this.view.arch;
// Update existing renderer
if (!_.isUndefined(this.renderer)) {
return this.renderer.updateState(this.value, {
matrix_data: this.matrix_data,
});
}
// Create a new matrix renderer
this.renderer = new X2Many2dMatrixRenderer(this, this.value, {
arch: arch,
editable: this.mode === 'edit' && arch.attrs.editable,
viewType: "list",
matrix_data: this.matrix_data,
});
this.$el.addClass('o_field_x2many o_field_x2many_2d_matrix');
return this.renderer.appendTo(this.$el);
},
/**
* Activate the widget.
*
* @override
*/
activate: function (options) {
// Won't work fine without https://github.com/odoo/odoo/pull/26490
// TODO Use _.propertyOf in underscore 1.9+
try {
this._backwards = options.event.data.direction === "previous";
} catch (error) {
this._backwards = false;
}
var result = this._super.apply(this, arguments);
delete this._backwards;
return result;
},
/**
* Get first element to focus.
*
* @override
*/
getFocusableElement: function () {
return this.$(".o_input:" + (this._backwards ? "last" : "first"));
},
});
field_registry.add('x2many_2d_matrix', WidgetX2Many2dMatrix);
return {
WidgetX2Many2dMatrix: WidgetX2Many2dMatrix,
};
});