Browse Source

[FIX] web_widget_x2many_2d_matrix: _renderBodyCell + _renderAggregateColCells

pull/1124/head
Alexey Pelykh 5 years ago
parent
commit
343d0560d5
  1. 18
      web_widget_x2many_2d_matrix/README.rst
  2. 3
      web_widget_x2many_2d_matrix/__manifest__.py
  3. 2
      web_widget_x2many_2d_matrix/readme/DESCRIPTION.rst
  4. 11
      web_widget_x2many_2d_matrix/readme/HISTORY.rst
  5. 57
      web_widget_x2many_2d_matrix/static/description/index.html
  6. 108
      web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js
  7. 12
      web_widget_x2many_2d_matrix/static/src/js/widget_x2many_2d_matrix.js

18
web_widget_x2many_2d_matrix/README.rst

@ -42,7 +42,7 @@ An example use case would be: Select some projects and some employees so that
a manager can easily fill in the planned_hours for one task per employee. The
result could look like this:
.. image:: https://raw.githubusercontent.com/web_widget_x2many_2d_matrix/static/description/screenshot.png
.. image:: https://raw.githubusercontent.com/OCA/web/12.0/web_widget_x2many_2d_matrix/static/description/screenshot.png
:alt: Screenshot
The beauty of this is that you have an arbitrary amount of columns with this
@ -168,6 +168,21 @@ Known issues / Roadmap
* Support extra invisible fields inside each cell.
Changelog
=========
12.0.1.0.1 (2018-12-07)
~~~~~~~~~~~~~~~~~~~~~~~
* [FIX] Cells are unable to render property.
(`#1126 <https://github.com/OCA/web/issues/1126>`_)
12.0.1.0.0 (2018-11-20)
~~~~~~~~~~~~~~~~~~~~~~~
* [12.0][MIG] web_widget_x2many_2d_matrix
(`#1101 <https://github.com/OCA/web/issues/1101>`_)
Bug Tracker
===========
@ -187,6 +202,7 @@ Authors
* Therp BV
* Tecnativa
* Camptocamp
* Brainbean Apps
Contributors
~~~~~~~~~~~~

3
web_widget_x2many_2d_matrix/__manifest__.py

@ -4,11 +4,12 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': '2D matrix for x2many fields',
'version': '12.0.1.0.0',
'version': '12.0.1.0.1',
'author': (
'Therp BV, '
'Tecnativa, '
'Camptocamp, '
'Brainbean Apps, '
'Odoo Community Association (OCA)'
),
'website': 'https://github.com/OCA/web',

2
web_widget_x2many_2d_matrix/readme/DESCRIPTION.rst

@ -15,7 +15,7 @@ An example use case would be: Select some projects and some employees so that
a manager can easily fill in the planned_hours for one task per employee. The
result could look like this:
.. image:: /web_widget_x2many_2d_matrix/static/description/screenshot.png
.. image:: https://raw.githubusercontent.com/OCA/web/12.0/web_widget_x2many_2d_matrix/static/description/screenshot.png
:alt: Screenshot
The beauty of this is that you have an arbitrary amount of columns with this

11
web_widget_x2many_2d_matrix/readme/HISTORY.rst

@ -0,0 +1,11 @@
12.0.1.0.1 (2018-12-07)
~~~~~~~~~~~~~~~~~~~~~~~
* [FIX] Cells are unable to render property.
(`#1126 <https://github.com/OCA/web/issues/1126>`_)
12.0.1.0.0 (2018-11-20)
~~~~~~~~~~~~~~~~~~~~~~~
* [12.0][MIG] web_widget_x2many_2d_matrix
(`#1101 <https://github.com/OCA/web/issues/1101>`_)

57
web_widget_x2many_2d_matrix/static/description/index.html

@ -397,29 +397,34 @@ ul.auto-toc {
<p>An example use case would be: Select some projects and some employees so that
a manager can easily fill in the planned_hours for one task per employee. The
result could look like this:</p>
<img alt="Screenshot" src="https://raw.githubusercontent.com/web_widget_x2many_2d_matrix/static/description/screenshot.png" />
<img alt="Screenshot" src="https://raw.githubusercontent.com/OCA/web/12.0/web_widget_x2many_2d_matrix/static/description/screenshot.png" />
<p>The beauty of this is that you have an arbitrary amount of columns with this
widget, trying to get this in standard x2many lists involves some quite ugly
hacks.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#usage" id="id1">Usage</a><ul>
<li><a class="reference internal" href="#example" id="id2">Example</a></li>
<li><a class="reference internal" href="#usage" id="id5">Usage</a><ul>
<li><a class="reference internal" href="#example" id="id6">Example</a></li>
</ul>
</li>
<li><a class="reference internal" href="#known-issues-roadmap" id="id3">Known issues / Roadmap</a></li>
<li><a class="reference internal" href="#bug-tracker" id="id4">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id5">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id6">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id7">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id8">Maintainers</a></li>
<li><a class="reference internal" href="#known-issues-roadmap" id="id7">Known issues / Roadmap</a></li>
<li><a class="reference internal" href="#changelog" id="id8">Changelog</a><ul>
<li><a class="reference internal" href="#id1" id="id9">12.0.1.0.1 (2018-12-07)</a></li>
<li><a class="reference internal" href="#id3" id="id10">12.0.1.0.0 (2018-11-20)</a></li>
</ul>
</li>
<li><a class="reference internal" href="#bug-tracker" id="id11">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id12">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id13">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id14">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id15">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#id1">Usage</a></h1>
<h1><a class="toc-backref" href="#id5">Usage</a></h1>
<p>Use this widget by saying:</p>
<pre class="literal-block">
&lt;field name=&quot;my_field&quot; widget=&quot;x2many_2d_matrix&quot; /&gt;
@ -457,7 +462,7 @@ row totals. True by default</dd>
column totals. True by default</dd>
</dl>
<div class="section" id="example">
<h2><a class="toc-backref" href="#id2">Example</a></h2>
<h2><a class="toc-backref" href="#id6">Example</a></h2>
<p>You need a data structure already filled with values. Let’s assume we want to
use this widget in a wizard that lets the user fill in planned hours for one
task per project per user. In this case, we can use <tt class="docutils literal">project.task</tt> as our
@ -509,7 +514,7 @@ the field in the default function:</p>
</div>
</div>
<div class="section" id="known-issues-roadmap">
<h1><a class="toc-backref" href="#id3">Known issues / Roadmap</a></h1>
<h1><a class="toc-backref" href="#id7">Known issues / Roadmap</a></h1>
<ul class="simple">
<li>Support extra attributes on each field cell via <cite>field_extra_attrs</cite> param.
We could set a cell as not editable, required or readonly for instance.
@ -523,8 +528,25 @@ is merged.</li>
<li>Support extra invisible fields inside each cell.</li>
</ul>
</div>
<div class="section" id="changelog">
<h1><a class="toc-backref" href="#id8">Changelog</a></h1>
<div class="section" id="id1">
<h2><a class="toc-backref" href="#id9">12.0.1.0.1 (2018-12-07)</a></h2>
<ul class="simple">
<li>[FIX] Cells are unable to render property.
(<a class="reference external" href="https://github.com/OCA/web/issues/1126">#1126</a>)</li>
</ul>
</div>
<div class="section" id="id3">
<h2><a class="toc-backref" href="#id10">12.0.1.0.0 (2018-11-20)</a></h2>
<ul class="simple">
<li>[12.0][MIG] web_widget_x2many_2d_matrix
(<a class="reference external" href="https://github.com/OCA/web/issues/1101">#1101</a>)</li>
</ul>
</div>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id4">Bug Tracker</a></h1>
<h1><a class="toc-backref" href="#id11">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/web/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
@ -532,17 +554,18 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#id5">Credits</a></h1>
<h1><a class="toc-backref" href="#id12">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id6">Authors</a></h2>
<h2><a class="toc-backref" href="#id13">Authors</a></h2>
<ul class="simple">
<li>Therp BV</li>
<li>Tecnativa</li>
<li>Camptocamp</li>
<li>Brainbean Apps</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id7">Contributors</a></h2>
<h2><a class="toc-backref" href="#id14">Contributors</a></h2>
<ul class="simple">
<li>Holger Brunn &lt;<a class="reference external" href="mailto:hbrunn&#64;therp.nl">hbrunn&#64;therp.nl</a>&gt;</li>
<li>Pedro M. Baeza &lt;<a class="reference external" href="mailto:pedro.baeza&#64;tecnativa.com">pedro.baeza&#64;tecnativa.com</a>&gt;</li>
@ -555,7 +578,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id8">Maintainers</a></h2>
<h2><a class="toc-backref" href="#id15">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose

108
web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js

@ -1,23 +1,25 @@
/* Copyright 2018 Simone Orsi <simone.orsi@camptocamp.com>
* Copyright 2018 Brainbean Apps
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
odoo.define('web_widget_x2many_2d_matrix.X2Many2dMatrixRenderer', function (require) {
"use strict";
// Heavily inspired by Odoo's `ListRenderer`
var BasicRenderer = require('web.BasicRenderer');
var config = require('web.config');
var core = require('web.core');
var field_utils = require('web.field_utils');
var _t = core._t;
var FIELD_CLASSES = {
// Copied from ListRenderer
float: 'o_list_number',
integer: 'o_list_number',
monetary: 'o_list_number',
text: 'o_list_text',
};
// X2Many2dMatrixRenderer is heavily inspired by Odoo's ListRenderer
// and is reusing portions of code from list_renderer.js
var X2Many2dMatrixRenderer = BasicRenderer.extend({
/**
@ -53,8 +55,11 @@ odoo.define('web_widget_x2many_2d_matrix.X2Many2dMatrixRenderer', function (requ
_renderView: function () {
var self = this;
this.$el
.removeClass('table-responsive')
.empty();
// Display a nice message if there's no data to display
this.$el.empty();
if (!self.rows.length) {
var $alert = $('<div>', {'class': 'alert alert-info'});
$alert.text(_t('Sorry no matrix data to display.'));
@ -170,7 +175,10 @@ odoo.define('web_widget_x2many_2d_matrix.X2Many2dMatrixRenderer', function (requ
* @returns {String} a string with the generated html.
*/
_renderRows: function () {
return _.map(this.rows, this._renderRow.bind(this));
return _.map(this.rows, function (row) {
row.attrs.name = this.matrix_data.field_value;
return this._renderRow(row);
}.bind(this));
},
/**
@ -187,11 +195,11 @@ odoo.define('web_widget_x2many_2d_matrix.X2Many2dMatrixRenderer', function (requ
var $tr = $('<tr/>', {class: 'o_data_row'}),
_data = _.without(row.data, undefined);
$tr = $tr.append(this._renderLabelCell(_data[0]));
var $cells = _.map(this.columns, function (node, index) {
var $cells = _.map(this.columns, function (column, index) {
var record = row.data[index];
// Make the widget use our field value for each cell
node.attrs.name = this.matrix_data.field_value;
return this._renderBodyCell(record, node, index, {mode:''});
column.attrs.name = this.matrix_data.field_value;
return this._renderBodyCell(record, column, index, {mode:''});
}.bind(this));
$tr = $tr.append($cells);
if (row.aggregate) {
@ -227,8 +235,8 @@ odoo.define('web_widget_x2many_2d_matrix.X2Many2dMatrixRenderer', function (requ
* @returns {jQueryElement} The rendered cell.
*/
_renderAggregateRowCell: function (row) {
var $cell = $('<td/>', {class: 'row-total text-right'});
this._apply_aggregate_value($cell, row.aggregate);
var $cell = $('<td/>', {class: 'row-total'});
this.applyAggregateValue($cell, row);
return $cell;
},
@ -246,9 +254,7 @@ odoo.define('web_widget_x2many_2d_matrix.X2Many2dMatrixRenderer', function (requ
*/
_renderBodyCell: function (record, node, colIndex, options) {
var tdClassName = 'o_data_cell';
if (node.tag === 'button') {
tdClassName += ' o_list_button';
} else if (node.tag === 'field') {
if (node.tag === 'field') {
var typeClass = FIELD_CLASSES[
this.state.fields[node.attrs.name].type
];
@ -259,11 +265,14 @@ odoo.define('web_widget_x2many_2d_matrix.X2Many2dMatrixRenderer', function (requ
tdClassName += ' o_' + node.attrs.widget + '_cell';
}
}
// TODO roadmap: here we should collect possible extra params
// the user might want to attach to each single cell.
var $td = $('<td>', {
'class': tdClassName,
});
if (_.isUndefined(record)) {
// Without record, nothing elese to do
return $td;
@ -272,6 +281,7 @@ odoo.define('web_widget_x2many_2d_matrix.X2Many2dMatrixRenderer', function (requ
'data-form-id': record.id,
'data-id': record.data.id,
});
// We register modifiers on the <td> element so that it gets
// the correct modifiers classes (for styling)
var modifiers = this._registerModifiers(
@ -286,13 +296,28 @@ odoo.define('web_widget_x2many_2d_matrix.X2Many2dMatrixRenderer', function (requ
if (modifiers.invisible && !(options && options.renderInvisible)) {
return $td;
}
// Enforce mode of the parent
options.mode = this.getParent().mode;
var widget = this._renderFieldWidget(
node, record, _.pick(options, 'mode')
);
this._handleAttributes(widget.$el, node);
return $td.append(widget.$el);
if (node.tag === 'widget') {
return $td.append(this._renderWidget(record, node));
}
if (node.attrs.widget || (options && (options.renderWidgets || options.mode === 'edit'))) {
var $el = this._renderFieldWidget(node, record, _.pick(options, 'mode'));
this._handleAttributes($el, node);
return $td.append($el);
}
var name = node.attrs.name;
var field = this.state.fields[name];
var value = record.data[name];
var formattedValue = field_utils.format[field.type](value, field, {
data: record.data,
escape: true,
isPassword: 'password' in node.attrs,
});
this._handleAttributes($td, node);
return $td.html(formattedValue);
},
/**
@ -325,8 +350,8 @@ odoo.define('web_widget_x2many_2d_matrix.X2Many2dMatrixRenderer', function (requ
return;
}
var $cell = $('<td>', {class: 'col-total text-right'});
this._apply_aggregate_value($cell, this.total);
var $cell = $('<td>', {class: 'col-total'});
this.applyAggregateValue($cell, this.total);
return $cell;
},
@ -338,10 +363,14 @@ odoo.define('web_widget_x2many_2d_matrix.X2Many2dMatrixRenderer', function (requ
*/
_renderAggregateColCells: function () {
var self = this;
return _.map(this.columns, function (column) {
var $cell = $('<td>', {class: 'col-total text-right'});
var $cell = $('<td>');
if (config.debug) {
$cell.addClass(column.attrs.name);
}
if (column.aggregate) {
self._apply_aggregate_value($cell, column.aggregate);
self.applyAggregateValue($cell, column)
}
return $cell;
});
@ -367,15 +396,16 @@ odoo.define('web_widget_x2many_2d_matrix.X2Many2dMatrixRenderer', function (requ
return;
}
this.total = {
fname: fname,
ftype: type,
help: _t('Sum Total'),
value: 0,
attrs: {
name: fname,
},
aggregate: {
help: _t('Sum Total'),
value: 0,
},
};
_.each(this.columns, function (column, index) {
column.aggregate = {
fname: fname,
ftype: type,
help: _t('Sum'),
value: 0,
};
@ -451,8 +481,6 @@ odoo.define('web_widget_x2many_2d_matrix.X2Many2dMatrixRenderer', function (requ
}
_.each(this.rows, function (row) {
row.aggregate = {
fname: fname,
ftype: type,
help: _t('Sum'),
value: 0,
};
@ -475,17 +503,19 @@ odoo.define('web_widget_x2many_2d_matrix.X2Many2dMatrixRenderer', function (requ
* @param {jQueryElement} $cell
* The Cell where the aggregate should be added.
*
* @param {Object} aggregate
* The object which contains the information about the aggregate value
* @param {Object} axis
* The object which contains the information about the aggregate value axis
*/
_apply_aggregate_value: function ($cell, aggregate) {
var field = this.state.fields[aggregate.fname],
formatter = field_utils.format[field.type];
var formattedValue = formatter(
aggregate.value, field, {escape: true}
);
$cell.addClass('total').attr('title', aggregate.help)
.html(formattedValue);
applyAggregateValue: function ($cell, axis) {
var field = this.state.fields[axis.attrs.name];
var value = axis.aggregate.value;
var help = axis.aggregate.help;
var formatFunc = field_utils.format[axis.attrs.widget];
if (!formatFunc) {
formatFunc = field_utils.format[field.type];
}
var formattedValue = formatFunc(value, field, { escape: true });
$cell.addClass('o_list_number').attr('title', help).html(formattedValue);
},
/**

12
web_widget_x2many_2d_matrix/static/src/js/widget_x2many_2d_matrix.js

@ -56,9 +56,6 @@ odoo.define('web_widget_x2many_2d_matrix.widget', function (require) {
node[property];
}
}
// And this?
this.field_editability =
node.field_editability || this.field_editability;
this.show_row_totals =
this.parse_boolean(node.show_row_totals || '1');
this.show_column_totals =
@ -138,7 +135,14 @@ odoo.define('web_widget_x2many_2d_matrix.widget', function (require) {
_make_row: function (y) {
var self = this;
// Use object so that we can attach more data if needed
var row = {'data': []};
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]);
});

Loading…
Cancel
Save