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