diff --git a/web_widget_child_selector/README.rst b/web_widget_child_selector/README.rst new file mode 100644 index 000000000..02694bdee --- /dev/null +++ b/web_widget_child_selector/README.rst @@ -0,0 +1,88 @@ +========================= +Web Widget Child Selector +========================= + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github + :target: https://github.com/OCA/web/tree/11.0/web_widget_child_selector + :alt: OCA/web +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/web-11-0/web-11-0-web_widget_child_selector + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/162/11.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows to use a new widget for many2one fields that are made hierarchically. +Now, you can navigate easily between the hierarchy. + +When we are using readonly, the behaviour is similar than Many2one, but on edition +we are able to select the parents and childs in order to navigate properly. + +.. image:: https://raw.githubusercontent.com/web_widget_child_selector/static/description/edit_mode.png + :alt: Edition Screenshot + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +Use child_selection widget on a field. +If necessary we can use child_selection_field on options in order to define +which field we will show on edition only. +For example, name instead of display_name. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +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 +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Creu Blanca + +Contributors +~~~~~~~~~~~~ + +* Enric Tobella + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +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. + +This module is part of the `OCA/web `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/web_widget_child_selector/__init__.py b/web_widget_child_selector/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/web_widget_child_selector/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/web_widget_child_selector/__manifest__.py b/web_widget_child_selector/__manifest__.py new file mode 100644 index 000000000..5fc1932bc --- /dev/null +++ b/web_widget_child_selector/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright 2019 Creu Blanca +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + 'name': 'Web Widget Child Selector', + 'summary': "Widget used for navigation on hierarchy fields", + 'version': '11.0.1.0.0', + 'license': 'AGPL-3', + 'author': 'Creu Blanca,Odoo Community Association (OCA)', + 'website': 'https://github.com/OCA/web', + 'depends': [ + 'web', + ], + 'data': [ + 'views/assets.xml', + ], + 'qweb': [ + 'static/src/xml/widget_child_selector.xml', + ], +} diff --git a/web_widget_child_selector/models/__init__.py b/web_widget_child_selector/models/__init__.py new file mode 100644 index 000000000..0e4444933 --- /dev/null +++ b/web_widget_child_selector/models/__init__.py @@ -0,0 +1 @@ +from . import base diff --git a/web_widget_child_selector/models/base.py b/web_widget_child_selector/models/base.py new file mode 100644 index 000000000..dbe2a4944 --- /dev/null +++ b/web_widget_child_selector/models/base.py @@ -0,0 +1,38 @@ +# Copyright 2019 Creu Blanca +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import models, _ + + +class Base(models.AbstractModel): + _inherit = 'base' + + def get_record_parent(self): + self.ensure_one() + if not hasattr(self, self._parent_name): + return False + parent = getattr(self, self._parent_name) + if not parent: + return False + return parent.name_get()[0] + + def _get_record_parents(self, field): + if not self: + return [(False, _('Root'))] + return getattr( + self, self._parent_name + )._get_record_parents(field) + [(self.id, str(getattr(self, field)))] + + def _get_record_direct_childs(self, field): + if not hasattr(self, self._parent_name): + return [] + return [(r.id, str(getattr(r, field))) for r in self.search([( + self._parent_name, '=', self.id or False + )])] + + def get_record_direct_childs_parents(self, options): + field = options.get('child_selection_field', 'display_name') + return { + 'childs': self._get_record_direct_childs(field), + 'parents': self._get_record_parents(field) + } diff --git a/web_widget_child_selector/readme/CONTRIBUTORS.rst b/web_widget_child_selector/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..93ec993e0 --- /dev/null +++ b/web_widget_child_selector/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Enric Tobella diff --git a/web_widget_child_selector/readme/DESCRIPTION.rst b/web_widget_child_selector/readme/DESCRIPTION.rst new file mode 100644 index 000000000..b4ac0a18a --- /dev/null +++ b/web_widget_child_selector/readme/DESCRIPTION.rst @@ -0,0 +1,8 @@ +This module allows to use a new widget for many2one fields that are made hierarchically. +Now, you can navigate easily between the hierarchy. + +When we are using readonly, the behaviour is similar than Many2one, but on edition +we are able to select the parents and childs in order to navigate properly. + +.. image:: /web_widget_child_selector/static/description/edit_mode.png + :alt: Edition Screenshot diff --git a/web_widget_child_selector/readme/USAGE.rst b/web_widget_child_selector/readme/USAGE.rst new file mode 100644 index 000000000..e490e60c7 --- /dev/null +++ b/web_widget_child_selector/readme/USAGE.rst @@ -0,0 +1,4 @@ +Use child_selection widget on a field. +If necessary we can use child_selection_field on options in order to define +which field we will show on edition only. +For example, name instead of display_name. diff --git a/web_widget_child_selector/static/description/edit_mode.png b/web_widget_child_selector/static/description/edit_mode.png new file mode 100644 index 000000000..f6059749d Binary files /dev/null and b/web_widget_child_selector/static/description/edit_mode.png differ diff --git a/web_widget_child_selector/static/description/icon.png b/web_widget_child_selector/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/web_widget_child_selector/static/description/icon.png differ diff --git a/web_widget_child_selector/static/description/index.html b/web_widget_child_selector/static/description/index.html new file mode 100644 index 000000000..cae6fbe17 --- /dev/null +++ b/web_widget_child_selector/static/description/index.html @@ -0,0 +1,431 @@ + + + + + + +Web Widget Child Selector + + + +
+

Web Widget Child Selector

+ + +

Beta License: AGPL-3 OCA/web Translate me on Weblate Try me on Runbot

+

This module allows to use a new widget for many2one fields that are made hierarchically. +Now, you can navigate easily between the hierarchy.

+

When we are using readonly, the behaviour is similar than Many2one, but on edition +we are able to select the parents and childs in order to navigate properly.

+Edition Screenshot +

Table of contents

+ +
+

Usage

+

Use child_selection widget on a field. +If necessary we can use child_selection_field on options in order to define +which field we will show on edition only. +For example, name instead of display_name.

+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +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 +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Creu Blanca
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

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.

+

This module is part of the OCA/web project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/web_widget_child_selector/static/src/js/widget_child_selector.js b/web_widget_child_selector/static/src/js/widget_child_selector.js new file mode 100644 index 000000000..e94a500b2 --- /dev/null +++ b/web_widget_child_selector/static/src/js/widget_child_selector.js @@ -0,0 +1,95 @@ +odoo.define('web.web_widget_child_selector', function(require) { + "use strict"; + + var relational_fields = require('web.relational_fields'); + var field_registry = require('web.field_registry'); + var core = require('web.core'); + var qweb = core.qweb; + var FieldMany2One = relational_fields.FieldMany2One; + + var FieldChildSelector = FieldMany2One.extend({ + template: "FieldChildSelector", + events: _.extend({}, FieldMany2One.prototype.events, { + 'click .o_child_selection_button': '_onChildSelectionClick', + }), + start: function () { + // booleean indicating that the content of the input isn't synchronized + // with the current m2o value (for instance, the user is currently + // typing something in the input, and hasn't selected a value yet). + + this.$input_dropdown = this.$('.o_input_dropdown'); + this.$input_value = this.$('.o_input_value') + return this._super.apply(this, arguments); + }, + _renderReadonly: function () { + var value = _.escape((this.m2o_value || "").trim()).split("\n").join("
"); + this.$el.html(value); + if (!this.nodeOptions.no_open && this.value) { + this.$el.attr('href', _.str.sprintf('#id=%s&model=%s', this.value.res_id, this.field.relation)); + this.$el.addClass('o_form_uri'); + } + }, + _set_childs: function() { + var self = this; + this.childs = {}; + this.parents = {}; + this.$input_dropdown.empty(); + this.$input_value.empty(); + var resources = []; + if (this.value.res_id) + resources = [this.value.res_id] + this._rpc({ + model: this.field.relation, + method: 'get_record_direct_childs_parents', + args: [ resources, this.nodeOptions], + context: this.record.getContext(this.recordParams), + }) + .then(function (data) { + _.each(data['parents'], function(parent, key) { + self.parents[key] = parent; + }); + _.each(data['childs'], function(child, key) { + self.childs[key] = child; + }); + self.$input_dropdown.append(qweb.render('FieldChildSelectorChild', { + 'childs': self.childs, + })); + self.$input_value.append(qweb.render('FieldChildSelectorParent', { + 'parents': self.parents, + })); + }); + }, + _onChildSelectionParent: function(event) { + var self = this; + this._rpc({ + model: this.field.relation, + method: 'get_record_parent', + args: [[this.value.res_id || false]], + context: this.record.getContext(this.recordParams), + }) + .then(function (parent) { + if (parent) + self._setValue({ + id: parent[0], display_name: parent[1] + }) + else + self._setValue({ + id: false, display_name: false + }); + }); + }, + _onChildSelectionClick: function(event) { + var target = $(event.target); + var index = target.data('index'); + var type = target.data('type'); + var value = (type === 'child') ? this.childs[index]: this.parents[index]; + this._setValue({id: value[0], display_name: value[1]}); + }, + _renderEdit: function() { + this._set_childs(); + }, + }); + + field_registry.add('child_selector', FieldChildSelector); + return FieldChildSelector; +}) diff --git a/web_widget_child_selector/static/src/less/widget_child_selector.less b/web_widget_child_selector/static/src/less/widget_child_selector.less new file mode 100644 index 000000000..f33199066 --- /dev/null +++ b/web_widget_child_selector/static/src/less/widget_child_selector.less @@ -0,0 +1,9 @@ +.btn.o_child_selection_button { + white-space:normal; + width:100%; + margin:2px; +} +a.o_child_selection_button { + cursor: pointer, +} + diff --git a/web_widget_child_selector/static/src/xml/widget_child_selector.xml b/web_widget_child_selector/static/src/xml/widget_child_selector.xml new file mode 100644 index 000000000..edad93cc0 --- /dev/null +++ b/web_widget_child_selector/static/src/xml/widget_child_selector.xml @@ -0,0 +1,36 @@ + + + + + + + + + +
+ +
+
+ + +
+
+ +
+
+
+ + + + / +
+ + + + + + diff --git a/web_widget_child_selector/views/assets.xml b/web_widget_child_selector/views/assets.xml new file mode 100644 index 000000000..036bb5cc0 --- /dev/null +++ b/web_widget_child_selector/views/assets.xml @@ -0,0 +1,9 @@ + + +