From 343d0560d5079729cafef9fd7fe53eb47902f827 Mon Sep 17 00:00:00 2001 From: Alexey Pelykh <alexey.pelykh@gmail.com> Date: Thu, 6 Dec 2018 14:25:47 +0200 Subject: [PATCH] [FIX] web_widget_x2many_2d_matrix: _renderBodyCell + _renderAggregateColCells --- web_widget_x2many_2d_matrix/README.rst | 18 ++- web_widget_x2many_2d_matrix/__manifest__.py | 3 +- .../readme/DESCRIPTION.rst | 2 +- .../readme/HISTORY.rst | 11 ++ .../static/description/index.html | 57 ++++++--- .../static/src/js/2d_matrix_renderer.js | 108 +++++++++++------- .../static/src/js/widget_x2many_2d_matrix.js | 12 +- 7 files changed, 148 insertions(+), 63 deletions(-) create mode 100644 web_widget_x2many_2d_matrix/readme/HISTORY.rst diff --git a/web_widget_x2many_2d_matrix/README.rst b/web_widget_x2many_2d_matrix/README.rst index 1372c625ae4a..c0693fcf41c4 100644 --- a/web_widget_x2many_2d_matrix/README.rst +++ b/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 ~~~~~~~~~~~~ diff --git a/web_widget_x2many_2d_matrix/__manifest__.py b/web_widget_x2many_2d_matrix/__manifest__.py index bfee53ec3550..3299e66b71ac 100644 --- a/web_widget_x2many_2d_matrix/__manifest__.py +++ b/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', diff --git a/web_widget_x2many_2d_matrix/readme/DESCRIPTION.rst b/web_widget_x2many_2d_matrix/readme/DESCRIPTION.rst index a84da8005ae6..d3f10cae8eef 100644 --- a/web_widget_x2many_2d_matrix/readme/DESCRIPTION.rst +++ b/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 diff --git a/web_widget_x2many_2d_matrix/readme/HISTORY.rst b/web_widget_x2many_2d_matrix/readme/HISTORY.rst new file mode 100644 index 000000000000..8bad8c46cd42 --- /dev/null +++ b/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>`_) diff --git a/web_widget_x2many_2d_matrix/static/description/index.html b/web_widget_x2many_2d_matrix/static/description/index.html index bd5775f28619..1be53a2a7d6c 100644 --- a/web_widget_x2many_2d_matrix/static/description/index.html +++ b/web_widget_x2many_2d_matrix/static/description/index.html @@ -397,29 +397,34 @@ <h1 class="title">2D matrix for x2many fields</h1> <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"> <field name="my_field" widget="x2many_2d_matrix" /> @@ -457,7 +462,7 @@ <h1><a class="toc-backref" href="#id1">Usage</a></h1> 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 @@ <h2><a class="toc-backref" href="#id2">Example</a></h2> </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 @@ <h1><a class="toc-backref" href="#id3">Known issues / Roadmap</a></h1> <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 @@ <h1><a class="toc-backref" href="#id4">Bug Tracker</a></h1> <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 <<a class="reference external" href="mailto:hbrunn@therp.nl">hbrunn@therp.nl</a>></li> <li>Pedro M. Baeza <<a class="reference external" href="mailto:pedro.baeza@tecnativa.com">pedro.baeza@tecnativa.com</a>></li> @@ -555,7 +578,7 @@ <h2><a class="toc-backref" href="#id7">Contributors</a></h2> </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 diff --git a/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js b/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js index ac627e44c7c0..30808ae1be02 100644 --- a/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js +++ b/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); }, /** diff --git a/web_widget_x2many_2d_matrix/static/src/js/widget_x2many_2d_matrix.js b/web_widget_x2many_2d_matrix/static/src/js/widget_x2many_2d_matrix.js index addf7cd4087e..bdaead56a553 100644 --- a/web_widget_x2many_2d_matrix/static/src/js/widget_x2many_2d_matrix.js +++ b/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]); });