Browse Source
Merge pull request #875 from arkostyuk/11.0-mig-web_tree_dynamic_colored_field
Merge pull request #875 from arkostyuk/11.0-mig-web_tree_dynamic_colored_field
[11.0][MIG] web_tree dynamic_colored_fieldpull/885/head
Pedro M. Baeza
7 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 289 additions and 0 deletions
-
107web_tree_dynamic_colored_field/README.rst
-
2web_tree_dynamic_colored_field/__init__.py
-
19web_tree_dynamic_colored_field/__manifest__.py
-
24web_tree_dynamic_colored_field/demo/res_users.xml
-
BINweb_tree_dynamic_colored_field/static/description/icon.png
-
129web_tree_dynamic_colored_field/static/src/js/web_tree_dynamic_colored_field.js
-
8web_tree_dynamic_colored_field/views/web_tree_dynamic_colored_field.xml
@ -0,0 +1,107 @@ |
|||||
|
.. image:: https://img.shields.io/badge/license-LGPL--3-blue.svg |
||||
|
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html |
||||
|
:alt: License: LGPL-3 |
||||
|
|
||||
|
============================ |
||||
|
Colorize field in tree views |
||||
|
============================ |
||||
|
|
||||
|
This module aims to add support for dynamically coloring fields in tree view |
||||
|
according to data in the record. |
||||
|
|
||||
|
It provides attributes on fields with the similar syntax as the ``colors`` attribute |
||||
|
in tree tags. |
||||
|
|
||||
|
Further, it provides a ``color_field`` attribute on tree tags's ``colors`` to use |
||||
|
a field's value as color. |
||||
|
|
||||
|
Features |
||||
|
======== |
||||
|
|
||||
|
* Add attribute ``bg_color`` on field's ``options`` to color background of a cell in tree view |
||||
|
* Add attribute ``fg_color`` on field's ``options`` to change text color of a cell in tree view |
||||
|
* Add attribute ``color_field`` on the tree element's ``colors`` to use as color |
||||
|
|
||||
|
Usage |
||||
|
===== |
||||
|
|
||||
|
* In the tree view declaration, put ``options='"bg_color": "red: customer==True"`` attribute in the ``field`` tag:: |
||||
|
|
||||
|
... |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree string="View name"> |
||||
|
... |
||||
|
<field name="name" options='"bg_color": "red: customer == True"'/> |
||||
|
... |
||||
|
</tree> |
||||
|
</field> |
||||
|
... |
||||
|
|
||||
|
With this example, column which renders 'name' field will have its background colored in red. |
||||
|
|
||||
|
* In the tree view declaration, put ``options='"fg_color": "white:customer == True"'`` attribute in the ``field`` tag:: |
||||
|
|
||||
|
... |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree string="View name"> |
||||
|
... |
||||
|
<field name="name" 'options="fg_color": "white:customer == True"'/> |
||||
|
... |
||||
|
</tree> |
||||
|
</field> |
||||
|
... |
||||
|
|
||||
|
With this example, column which renders 'name' field will have its text colored in white on a customer records. |
||||
|
|
||||
|
* In the tree view declaration, use ``options='"color_field": "my_color"'`` attribute in the ``tree`` tag:: |
||||
|
|
||||
|
... |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree string="View name" colors="color_field: my_color" > |
||||
|
... |
||||
|
<field name="my_color" invisible="1"/> |
||||
|
... |
||||
|
</tree> |
||||
|
</field> |
||||
|
... |
||||
|
|
||||
|
With this example, the content of the field named `my_color` will be used to |
||||
|
populate the `my_color` CSS value. Use a function field to return whichever |
||||
|
color you want depending on the other record values. Note that this |
||||
|
overrides the rest of `colors` attributes, and that you need the tree |
||||
|
to load your field in the first place by adding it as invisible field. |
||||
|
|
||||
|
**Note that you should always use single quotes for fields' ``options`` and wrap nested values in double quotes since ``options`` is a JSON object.** |
||||
|
|
||||
|
Bug Tracker |
||||
|
=========== |
||||
|
|
||||
|
Bugs are tracked on `GitHub Issues |
||||
|
<https://github.com/OCA/web/issues>`_. In case of trouble, please |
||||
|
check there if your issue has already been reported. If you spotted it first, |
||||
|
help us smash it by providing a detailed and welcomed feedback. |
||||
|
|
||||
|
Credits |
||||
|
======= |
||||
|
|
||||
|
Contributors |
||||
|
------------ |
||||
|
|
||||
|
* Damien Crier <damien.crier@camptocamp.com> |
||||
|
* Holger Brunn <hbrunn@therp.nl> |
||||
|
* Artem Kostyuk <a.kostyuk@mobilunity.com> |
||||
|
|
||||
|
Maintainer |
||||
|
---------- |
||||
|
|
||||
|
.. image:: https://odoo-community.org/logo.png |
||||
|
:alt: Odoo Community Association |
||||
|
:target: https://odoo-community.org |
||||
|
|
||||
|
This module is maintained by the OCA. |
||||
|
|
||||
|
OCA, or the Odoo Community Association, is a nonprofit organization whose |
||||
|
mission is to support the collaborative development of Odoo features and |
||||
|
promote its widespread use. |
||||
|
|
||||
|
To contribute to this module, please visit https://odoo-community.org. |
@ -0,0 +1,2 @@ |
|||||
|
# Copyright 2015-2018 Camptocamp SA, Damien Crier |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
@ -0,0 +1,19 @@ |
|||||
|
# Copyright 2015-2018 Camptocamp SA, Damien Crier |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
{ |
||||
|
'name': 'Colorize field in tree views', |
||||
|
'summary': 'Allows you to dynamically color fields on tree views', |
||||
|
'category': 'Hidden/Dependency', |
||||
|
'version': '11.0.1.0.0', |
||||
|
'depends': ['web'], |
||||
|
'author': "Camptocamp, Therp BV, Odoo Community Association (OCA)", |
||||
|
'license': 'AGPL-3', |
||||
|
'website': 'https://github.com/OCA/web', |
||||
|
'demo': [ |
||||
|
"demo/res_users.xml", |
||||
|
], |
||||
|
'data': [ |
||||
|
'views/web_tree_dynamic_colored_field.xml', |
||||
|
], |
||||
|
'installable': True, |
||||
|
} |
@ -0,0 +1,24 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<odoo> |
||||
|
<record id="view_users_tree" model="ir.ui.view"> |
||||
|
<field name="model">res.users</field> |
||||
|
<field name="inherit_id" ref="base.view_users_tree" /> |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree position="attributes"> |
||||
|
<attribute name="colors">color_field: lang</attribute> |
||||
|
</tree> |
||||
|
<field name="login_date" position="attributes"> |
||||
|
<attribute name="options">{ |
||||
|
"bg_color": "#9e1635: login_date == False", |
||||
|
"fg_color": "white: login_date == False" |
||||
|
}</attribute> |
||||
|
</field> |
||||
|
<field name="name" position="attributes"> |
||||
|
<attribute name="options"> { |
||||
|
"bg_color": "blue; #653b5b: login == 'admin'", |
||||
|
"fg_color": "white" |
||||
|
}</attribute> |
||||
|
</field> |
||||
|
</field> |
||||
|
</record> |
||||
|
</odoo> |
After Width: 128 | Height: 128 | Size: 9.2 KiB |
@ -0,0 +1,129 @@ |
|||||
|
odoo.define('web_tree_dynamic_colored_field', function (require) { |
||||
|
'use strict'; |
||||
|
|
||||
|
var ListRenderer = require('web.ListRenderer'); |
||||
|
var pyeval = require('web.pyeval'); |
||||
|
|
||||
|
ListRenderer.include({ |
||||
|
/** |
||||
|
* Look up for a `color_field` parameter in tree `colors` attribute |
||||
|
* |
||||
|
* @override |
||||
|
*/ |
||||
|
_renderBody: function () { |
||||
|
if (this.arch.attrs.colors) { |
||||
|
var colorField = this.arch.attrs.colors.split(';') |
||||
|
.filter(color => color.trim().startsWith('color_field'))[0] |
||||
|
.split(':')[1] |
||||
|
.trim(); |
||||
|
// validate the presence of that field in tree view
|
||||
|
var fieldNames = _(this.columns).map( |
||||
|
(value) => { return value.attrs.name; } |
||||
|
); |
||||
|
if (fieldNames.indexOf(colorField) === -1) { |
||||
|
console.warn( |
||||
|
"No field named '" + colorField + "' present in view." |
||||
|
); |
||||
|
} else { |
||||
|
this.colorField = colorField; |
||||
|
} |
||||
|
} |
||||
|
return this._super(); |
||||
|
}, |
||||
|
/** |
||||
|
* Colorize a cell during it's render |
||||
|
* |
||||
|
* @override |
||||
|
*/ |
||||
|
_renderBodyCell: function (record, node, colIndex, options) { |
||||
|
var $td = this._super.apply(this, arguments); |
||||
|
var ctx = this.getEvalContext(record); |
||||
|
this.applyColorize($td, record, node, ctx); |
||||
|
return $td; |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* Colorize the current cell depending on expressions provided. |
||||
|
* |
||||
|
* @param {Query Node} $td a <td> tag inside a table representing a list view |
||||
|
* @param {Object} node an XML node (must be a <field>) |
||||
|
*/ |
||||
|
applyColorize: function ($td, record, node, ctx) { |
||||
|
// safely resolve value of `color_field` given in <tree>
|
||||
|
var treeColor = record.data[this.colorField]; |
||||
|
if (treeColor) { |
||||
|
$td.css('color', treeColor); |
||||
|
} |
||||
|
// apply <field>'s own `options`
|
||||
|
if (!node.attrs.options) { return; } |
||||
|
var nodeOptions = JSON.parse(node.attrs.options); |
||||
|
this.applyColorizeHelper($td, nodeOptions, node, 'fg_color', 'color', ctx); |
||||
|
this.applyColorizeHelper($td, nodeOptions, node, 'bg_color', 'background-color', ctx); |
||||
|
}, |
||||
|
/** |
||||
|
* @param {Object} nodeOptions a mapping of nodeOptions parameters to the color itself |
||||
|
* @param {Object} node an XML node (must be a <field>) |
||||
|
* @param {string} nodeAttribute an attribute of a node to apply a style onto |
||||
|
* @param {string} cssAttribute a real CSS-compatible attribute |
||||
|
*/ |
||||
|
applyColorizeHelper: function ($td, nodeOptions, node, nodeAttribute, cssAttribute, ctx) { |
||||
|
if (nodeOptions[nodeAttribute]) { |
||||
|
var colors = _(nodeOptions[nodeAttribute].split(';')) |
||||
|
.chain() |
||||
|
.map(this.pairColors) |
||||
|
.value() |
||||
|
.filter(function CheckUndefined(value, index, ar) { |
||||
|
return value !== undefined; |
||||
|
}); |
||||
|
for (var i=0, len=colors.length; i<len; ++i) { |
||||
|
var pair = colors[i], |
||||
|
color = pair[0], |
||||
|
expression = pair[1]; |
||||
|
if (py.evaluate(expression, ctx).toJSON()) { |
||||
|
$td.css(cssAttribute, color); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* Parse `<color>: <field> <operator> <value>` forms to |
||||
|
* evaluatable expressions |
||||
|
* |
||||
|
* @param {string} pairColor `color: expression` pair |
||||
|
*/ |
||||
|
pairColors: function (pairColor) { |
||||
|
if (pairColor !== "") { |
||||
|
var pairList = pairColor.split(':'), |
||||
|
color = pairList[0], |
||||
|
// if one passes a bare color instead of an expression,
|
||||
|
// then we consider that color is to be shown in any case
|
||||
|
expression = pairList[1]? pairList[1] : 'True'; |
||||
|
return [color, py.parse(py.tokenize(expression)), expression]; |
||||
|
} |
||||
|
return undefined; |
||||
|
}, |
||||
|
/** |
||||
|
* Construct domain evaluation context, mostly by passing |
||||
|
* record's fields's values to local scope. |
||||
|
* |
||||
|
* @param {Object} record a record to build a context from |
||||
|
*/ |
||||
|
getEvalContext: function (record) { |
||||
|
var ctx = _.extend( |
||||
|
{}, |
||||
|
record.data, |
||||
|
pyeval.context() |
||||
|
); |
||||
|
for (var key in ctx) { |
||||
|
var value = ctx[key]; |
||||
|
if (ctx[key] instanceof moment) { |
||||
|
// date/datetime fields are represented w/ Moment objects
|
||||
|
// docs: https://momentjs.com/
|
||||
|
ctx[key] = value.format('YYYY-MM-DD hh:mm:ss'); |
||||
|
} |
||||
|
} |
||||
|
return ctx; |
||||
|
} |
||||
|
}); |
||||
|
}); |
@ -0,0 +1,8 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<template id="assets_backend" name="web_tree_dynamic_colored_field assets" inherit_id="web.assets_backend"> |
||||
|
<xpath expr="." position="inside"> |
||||
|
<script type="text/javascript" src="/web_tree_dynamic_colored_field/static/src/js/web_tree_dynamic_colored_field.js"></script> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
</odoo> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue