diff --git a/README.md b/README.md index a407905f837..d432b47492d 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ addon | version | maintainers | summary [web_company_context_highlight](web_company_context_highlight/) | 19.0.1.0.0 | pverkest | Highlight the company switcher when multiple companies are selected [web_dark_mode](web_dark_mode/) | 19.0.1.0.0 | | Enabled Dark Mode for the Odoo Backend [web_date_format_numeric](web_date_format_numeric/) | 19.0.1.0.0 | | Display all date/datetime fields in numeric format -[web_dialog_size](web_dialog_size/) | 19.0.1.0.0 | | A module that lets the user expand a dialog box to the full screen width. +[web_dialog_size](web_dialog_size/) | 19.0.1.0.1 | | A module that lets the user expand a dialog box to the full screen width. [web_editor_class_selector](web_editor_class_selector/) | 19.0.1.0.0 | carlos-lopez-tecnativa | Web editor class selector [web_environment_ribbon](web_environment_ribbon/) | 19.0.1.0.0 | | Web Environment Ribbon [web_favicon](web_favicon/) | 19.0.1.0.0 | | Allows to set a custom shortcut icon (aka favicon) @@ -47,7 +47,8 @@ addon | version | maintainers | summary [web_timeline](web_timeline/) | 19.0.1.0.0 | | Interactive visualization chart to show events in time [web_tree_many2one_clickable](web_tree_many2one_clickable/) | 19.0.1.0.0 | | Open the linked resource when clicking on their name [web_widget_bokeh_chart](web_widget_bokeh_chart/) | 19.0.1.0.1 | LoisRForgeFlow JasminSForgeFlow | This widget allows to display charts using Bokeh library. -[web_widget_one2many_tree_line_duplicate](web_widget_one2many_tree_line_duplicate/) | 19.0.1.0.0 | | Web Widget One2many Tree Line Duplicate +[web_widget_numeric_step](web_widget_numeric_step/) | 19.0.1.0.0 | rafaelbn yajo | Web Widget Numeric Step +[web_widget_one2many_tree_line_duplicate](web_widget_one2many_tree_line_duplicate/) | 19.0.1.0.1 | | Web Widget One2many Tree Line Duplicate [web_widget_product_label_section_and_note_full_label](web_widget_product_label_section_and_note_full_label/) | 19.0.1.0.0 | | Display the full label in the product_label_section_and_note widget. [web_widget_product_label_section_and_note_name_visibility](web_widget_product_label_section_and_note_name_visibility/) | 19.0.1.0.0 | carlos-lopez-tecnativa | Alternate the visibility of the product and description. [web_widget_section_and_note_text_scrollable](web_widget_section_and_note_text_scrollable/) | 19.0.1.0.0 | ivantodorovich | Make the text field of Section and Note widget scrollable diff --git a/setup/_metapackage/pyproject.toml b/setup/_metapackage/pyproject.toml index 3500ebf845d..8d5b0dc06cc 100644 --- a/setup/_metapackage/pyproject.toml +++ b/setup/_metapackage/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "odoo-addons-oca-web" -version = "19.0.20260825.0" +version = "19.0.20260828.0" dependencies = [ "odoo-addon-web_calendar_slot_duration==19.0.*", "odoo-addon-web_chatter_position==19.0.*", @@ -28,6 +28,7 @@ dependencies = [ "odoo-addon-web_timeline==19.0.*", "odoo-addon-web_tree_many2one_clickable==19.0.*", "odoo-addon-web_widget_bokeh_chart==19.0.*", + "odoo-addon-web_widget_numeric_step==19.0.*", "odoo-addon-web_widget_one2many_tree_line_duplicate==19.0.*", "odoo-addon-web_widget_product_label_section_and_note_full_label==19.0.*", "odoo-addon-web_widget_product_label_section_and_note_name_visibility==19.0.*", diff --git a/web_dialog_size/README.rst b/web_dialog_size/README.rst index d2a45b12b5c..124fef5b90a 100644 --- a/web_dialog_size/README.rst +++ b/web_dialog_size/README.rst @@ -11,7 +11,7 @@ Web Dialog Size !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:82dac89574909c0b51e36915e82361c0f70787d7b1b237ff449addfb0e5093da + !! source digest: sha256:c49a428f4ac5966464e95d7c3c89f8bdcc397ec405c21996eec3d20f7c87fbd7 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/web_dialog_size/__manifest__.py b/web_dialog_size/__manifest__.py index 19fb6f15ee9..c80a05404cc 100644 --- a/web_dialog_size/__manifest__.py +++ b/web_dialog_size/__manifest__.py @@ -15,7 +15,7 @@ "Odoo Community Association (OCA)", "website": "https://github.com/OCA/web", "category": "web", - "version": "19.0.1.0.0", + "version": "19.0.1.0.1", "license": "AGPL-3", "depends": ["web"], "installable": True, diff --git a/web_dialog_size/static/description/index.html b/web_dialog_size/static/description/index.html index a56289ab9d3..802d13de630 100644 --- a/web_dialog_size/static/description/index.html +++ b/web_dialog_size/static/description/index.html @@ -372,7 +372,7 @@

Web Dialog Size

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:82dac89574909c0b51e36915e82361c0f70787d7b1b237ff449addfb0e5093da +!! source digest: sha256:c49a428f4ac5966464e95d7c3c89f8bdcc397ec405c21996eec3d20f7c87fbd7 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

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

A module that lets the user expand/restore the dialog box size through a diff --git a/web_dialog_size/static/src/js/web_dialog_size.esm.js b/web_dialog_size/static/src/js/web_dialog_size.esm.js index 07f4802392d..71cac2d5cab 100644 --- a/web_dialog_size/static/src/js/web_dialog_size.esm.js +++ b/web_dialog_size/static/src/js/web_dialog_size.esm.js @@ -6,6 +6,12 @@ import {patch} from "@web/core/utils/patch"; import {useService} from "@web/core/utils/hooks"; import {browser} from "@web/core/browser/browser"; +function triggerWindowResize() { + requestAnimationFrame(() => { + window.dispatchEvent(new Event("resize")); + }); +} + export class ExpandButton extends Component { setup() { this.original_size = this.props.getoriginalsize @@ -18,13 +24,13 @@ export class ExpandButton extends Component { dialog_button_extend() { this.props.setsize("dialog_full_screen"); browser.localStorage.setItem("odoo.web_dialog_size.value", "true"); - this.render(); + triggerWindowResize(); } dialog_button_restore() { this.props.setsize(this.original_size); browser.localStorage.setItem("odoo.web_dialog_size.value", "false"); - this.render(); + triggerWindowResize(); } } diff --git a/web_widget_numeric_step/README.rst b/web_widget_numeric_step/README.rst new file mode 100644 index 00000000000..a4b871d0ba7 --- /dev/null +++ b/web_widget_numeric_step/README.rst @@ -0,0 +1,168 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +======================= +Web Widget Numeric Step +======================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:9025ad79e52a5b2790d7a9406dc6aa4fd495d56b12bb3fea65d626b83ded7bb5 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/license-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/19.0/web_widget_numeric_step + :alt: OCA/web +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/web-19-0/web-19-0-web_widget_numeric_step + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/web&target_branch=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This widget changes input number field and make it easier to increment +the number thanks to 2 buttons (+ and -). Use JS native logic for input +number, so you can use the options ``min``, ``max``, ``step``, +``placeholder``. + +Demo available at Settings > Users & Companies > Users > \*Select One\* +> See 'Credit Limit' field + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +In your xml view, add ``widget="numeric_step"`` This will add the 2 +buttons "+" and "-" just next to the input field in edit mode. Iteration +step by default is 1. + +|image1| + +**Optional** + +Add an option to choose the step iteration and limits (min and max +values). + +Example for an 0.25 step, min to -1 and max to 10 : + +.. code:: xml + + days + +**Available Options** + +- step > Amount to increase/decrease (default: 1.0) +- min > Min. value allowed (default: no limit) +- max > Max. value allowed (default: no limit) +- auto_select > Select the content when the element get focus (default: + False) +- placeholder > Define the placeholder text (default: None) +- class > Define additional classes for the input (default: None) + +**Examples** + +Iteration with 0.25 step, min to -1 and max to 10. + +Start to increment with button, continue incrementing with scrolling +mouse. + +|image2| + +Iteration with 10 step, max limit 15, placeholder with onchange + +|image3| + +**Demo** + +You can test the feature by going to Settings > Technical > Scheduled +Actions. The field "Execute Every" is configured to use the widget with +2 step, min to 0 and max to 40. + +.. |image1| image:: https://raw.githubusercontent.com/OCA/web/19.0/web_widget_numeric_step/static/description/add_two_buttons.png +.. |image2| image:: https://raw.githubusercontent.com/OCA/web/19.0/web_widget_numeric_step/static/description/step0,25andlimits.gif +.. |image3| image:: https://raw.githubusercontent.com/OCA/web/19.0/web_widget_numeric_step/static/description/step10_limit15_placeholder117_with_onchange.gif + +Known issues / Roadmap +====================== + +When the value is entered using the keyboard, the limits set in the +widget can be exceeded + +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 to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* GRAP +* Tecnativa + +Contributors +------------ + +- `GRAP `__: + + - Quentin DUPONT + +- `Tecnativa `__: + + - Alexandre Díaz + - Carlos Roca + +- Helly kapatel +- Thanakrit Pintana +- Dhara Solanki + +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. + +.. |maintainer-rafaelbn| image:: https://github.com/rafaelbn.png?size=40px + :target: https://github.com/rafaelbn + :alt: rafaelbn +.. |maintainer-yajo| image:: https://github.com/yajo.png?size=40px + :target: https://github.com/yajo + :alt: yajo + +Current `maintainers `__: + +|maintainer-rafaelbn| |maintainer-yajo| + +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_numeric_step/__init__.py b/web_widget_numeric_step/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/web_widget_numeric_step/__manifest__.py b/web_widget_numeric_step/__manifest__.py new file mode 100644 index 00000000000..73cf7400e3e --- /dev/null +++ b/web_widget_numeric_step/__manifest__.py @@ -0,0 +1,22 @@ +# Copyright 2019 GRAP - Quentin DUPONT +# Copyright 2020 Tecnativa - Alexandre Díaz +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +{ + "name": "Web Widget Numeric Step", + "category": "web", + "version": "19.0.1.0.0", + "author": "GRAP, Tecnativa, Odoo Community Association (OCA)", + "license": "AGPL-3", + "website": "https://github.com/OCA/web", + "depends": ["web"], + "demo": ["demo/ir_cron.xml"], + "assets": { + "web.assets_backend": [ + "web_widget_numeric_step/static/src/*", + ], + }, + "maintainers": ["rafaelbn", "yajo"], + "auto_install": False, + "installable": True, +} diff --git a/web_widget_numeric_step/demo/ir_cron.xml b/web_widget_numeric_step/demo/ir_cron.xml new file mode 100644 index 00000000000..1a4f7bdc47e --- /dev/null +++ b/web_widget_numeric_step/demo/ir_cron.xml @@ -0,0 +1,13 @@ + + + + ir.cron + + + + numeric_step + {'step': 2, 'min': 0, 'max': 40} + + + + diff --git a/web_widget_numeric_step/i18n/de.po b/web_widget_numeric_step/i18n/de.po new file mode 100644 index 00000000000..d16afa183f6 --- /dev/null +++ b/web_widget_numeric_step/i18n/de.po @@ -0,0 +1,39 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_widget_numeric_step +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-10-13 20:46+0000\n" +"Last-Translator: Corneliuus \n" +"Language-Team: none\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: web_widget_numeric_step +#. odoo-javascript +#: code:addons/web_widget_numeric_step/static/src/numeric_step.xml:0 +msgid "Minus" +msgstr "Minus" + +#. module: web_widget_numeric_step +#. odoo-javascript +#: code:addons/web_widget_numeric_step/static/src/numeric_step.esm.js:0 +msgid "Numeric Step" +msgstr "" + +#. module: web_widget_numeric_step +#. odoo-javascript +#: code:addons/web_widget_numeric_step/static/src/numeric_step.xml:0 +msgid "Plus" +msgstr "Plus" + +#, python-format +#~ msgid "Value" +#~ msgstr "Wert" diff --git a/web_widget_numeric_step/i18n/es.po b/web_widget_numeric_step/i18n/es.po new file mode 100644 index 00000000000..ea627175cfb --- /dev/null +++ b/web_widget_numeric_step/i18n/es.po @@ -0,0 +1,39 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_widget_numeric_step +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-10-15 20:36+0000\n" +"Last-Translator: Ivorra78 \n" +"Language-Team: none\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: web_widget_numeric_step +#. odoo-javascript +#: code:addons/web_widget_numeric_step/static/src/numeric_step.xml:0 +msgid "Minus" +msgstr "Menos" + +#. module: web_widget_numeric_step +#. odoo-javascript +#: code:addons/web_widget_numeric_step/static/src/numeric_step.esm.js:0 +msgid "Numeric Step" +msgstr "Paso Numérico" + +#. module: web_widget_numeric_step +#. odoo-javascript +#: code:addons/web_widget_numeric_step/static/src/numeric_step.xml:0 +msgid "Plus" +msgstr "Más" + +#, python-format +#~ msgid "Value" +#~ msgstr "Valor" diff --git a/web_widget_numeric_step/i18n/fr.po b/web_widget_numeric_step/i18n/fr.po new file mode 100644 index 00000000000..c47a151521a --- /dev/null +++ b/web_widget_numeric_step/i18n/fr.po @@ -0,0 +1,35 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_widget_number_ux_choice +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-08-30 12:07+0000\n" +"PO-Revision-Date: 2019-08-30 12:07+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: web_widget_numeric_step +#. odoo-javascript +#: code:addons/web_widget_numeric_step/static/src/numeric_step.xml:0 +msgid "Minus" +msgstr "Moins" + +#. module: web_widget_numeric_step +#. odoo-javascript +#: code:addons/web_widget_numeric_step/static/src/numeric_step.esm.js:0 +msgid "Numeric Step" +msgstr "" + +#. module: web_widget_numeric_step +#. odoo-javascript +#: code:addons/web_widget_numeric_step/static/src/numeric_step.xml:0 +msgid "Plus" +msgstr "Plus" diff --git a/web_widget_numeric_step/i18n/it.po b/web_widget_numeric_step/i18n/it.po new file mode 100644 index 00000000000..c56a4c0d27f --- /dev/null +++ b/web_widget_numeric_step/i18n/it.po @@ -0,0 +1,39 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_widget_numeric_step +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-11-27 11:33+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: web_widget_numeric_step +#. odoo-javascript +#: code:addons/web_widget_numeric_step/static/src/numeric_step.xml:0 +msgid "Minus" +msgstr "Meno" + +#. module: web_widget_numeric_step +#. odoo-javascript +#: code:addons/web_widget_numeric_step/static/src/numeric_step.esm.js:0 +msgid "Numeric Step" +msgstr "Passo numerico" + +#. module: web_widget_numeric_step +#. odoo-javascript +#: code:addons/web_widget_numeric_step/static/src/numeric_step.xml:0 +msgid "Plus" +msgstr "Più" + +#, python-format +#~ msgid "Value" +#~ msgstr "Valore" diff --git a/web_widget_numeric_step/i18n/web_widget_numeric_step.pot b/web_widget_numeric_step/i18n/web_widget_numeric_step.pot new file mode 100644 index 00000000000..04ad3512428 --- /dev/null +++ b/web_widget_numeric_step/i18n/web_widget_numeric_step.pot @@ -0,0 +1,32 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_widget_numeric_step +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 19.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: web_widget_numeric_step +#. odoo-javascript +#: code:addons/web_widget_numeric_step/static/src/numeric_step.xml:0 +msgid "Minus" +msgstr "" + +#. module: web_widget_numeric_step +#. odoo-javascript +#: code:addons/web_widget_numeric_step/static/src/numeric_step.esm.js:0 +msgid "Numeric Step" +msgstr "" + +#. module: web_widget_numeric_step +#. odoo-javascript +#: code:addons/web_widget_numeric_step/static/src/numeric_step.xml:0 +msgid "Plus" +msgstr "" diff --git a/web_widget_numeric_step/pyproject.toml b/web_widget_numeric_step/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/web_widget_numeric_step/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/web_widget_numeric_step/readme/CONTRIBUTORS.md b/web_widget_numeric_step/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..3ab6f274527 --- /dev/null +++ b/web_widget_numeric_step/readme/CONTRIBUTORS.md @@ -0,0 +1,8 @@ +- [GRAP](http://www.grap.coop): + - Quentin DUPONT \<\> +- [Tecnativa](https://www.tecnativa.com/): + - Alexandre Díaz + - Carlos Roca +- Helly kapatel \<\> +- Thanakrit Pintana \<\> +- Dhara Solanki \<\> diff --git a/web_widget_numeric_step/readme/DESCRIPTION.md b/web_widget_numeric_step/readme/DESCRIPTION.md new file mode 100644 index 00000000000..c679491a009 --- /dev/null +++ b/web_widget_numeric_step/readme/DESCRIPTION.md @@ -0,0 +1,6 @@ +This widget changes input number field and make it easier to increment +the number thanks to 2 buttons (+ and -). Use JS native logic for input +number, so you can use the options `min`, `max`, `step`, `placeholder`. + +Demo available at Settings \> Users & Companies \> Users \> \*Select +One\* \> See 'Credit Limit' field diff --git a/web_widget_numeric_step/readme/ROADMAP.md b/web_widget_numeric_step/readme/ROADMAP.md new file mode 100644 index 00000000000..953fb14c997 --- /dev/null +++ b/web_widget_numeric_step/readme/ROADMAP.md @@ -0,0 +1 @@ +When the value is entered using the keyboard, the limits set in the widget can be exceeded diff --git a/web_widget_numeric_step/readme/USAGE.md b/web_widget_numeric_step/readme/USAGE.md new file mode 100644 index 00000000000..5d5e2d88b4a --- /dev/null +++ b/web_widget_numeric_step/readme/USAGE.md @@ -0,0 +1,45 @@ +In your xml view, add `widget="numeric_step"` This will add the 2 +buttons "+" and "-" just next to the input field in edit mode. Iteration +step by default is 1. + +![](../static/description/add_two_buttons.png) + +**Optional** + +Add an option to choose the step iteration and limits (min and max +values). + +Example for an 0.25 step, min to -1 and max to 10 : + +``` xml + days +``` + +**Available Options** + +- step \> Amount to increase/decrease (default: 1.0) +- min \> Min. value allowed (default: no limit) +- max \> Max. value allowed (default: no limit) +- auto_select \> Select the content when the element get focus (default: + False) +- placeholder \> Define the placeholder text (default: None) +- class \> Define additional classes for the input (default: None) + +**Examples** + +Iteration with 0.25 step, min to -1 and max to 10. + +Start to increment with button, continue incrementing with scrolling +mouse. + +![](../static/description/step0,25andlimits.gif) + +Iteration with 10 step, max limit 15, placeholder with onchange + +![](../static/description/step10_limit15_placeholder117_with_onchange.gif) + +**Demo** + +You can test the feature by going to Settings > Technical > Scheduled Actions. The +field "Execute Every" is configured to use the widget with 2 step, min to 0 and max +to 40. \ No newline at end of file diff --git a/web_widget_numeric_step/static/description/add_two_buttons.png b/web_widget_numeric_step/static/description/add_two_buttons.png new file mode 100644 index 00000000000..7a60f2dea9b Binary files /dev/null and b/web_widget_numeric_step/static/description/add_two_buttons.png differ diff --git a/web_widget_numeric_step/static/description/icon.png b/web_widget_numeric_step/static/description/icon.png new file mode 100644 index 00000000000..3a662b992dd Binary files /dev/null and b/web_widget_numeric_step/static/description/icon.png differ diff --git a/web_widget_numeric_step/static/description/index.html b/web_widget_numeric_step/static/description/index.html new file mode 100644 index 00000000000..254fdf7cf8f --- /dev/null +++ b/web_widget_numeric_step/static/description/index.html @@ -0,0 +1,490 @@ + + + + + +README.rst + + + +

+ + + +Odoo Community Association + +
+

Web Widget Numeric Step

+ +

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

+

This widget changes input number field and make it easier to increment +the number thanks to 2 buttons (+ and -). Use JS native logic for input +number, so you can use the options min, max, step, +placeholder.

+

Demo available at Settings > Users & Companies > Users > *Select One* +> See ‘Credit Limit’ field

+

Table of contents

+ +
+

Usage

+

In your xml view, add widget="numeric_step" This will add the 2 +buttons “+” and “-” just next to the input field in edit mode. Iteration +step by default is 1.

+

image1

+

Optional

+

Add an option to choose the step iteration and limits (min and max +values).

+

Example for an 0.25 step, min to -1 and max to 10 :

+
+<field name="sale_delay" widget="numeric_step" options="{'step': 0.25, 'min': -1, 'max': 10}" /> days
+
+

Available Options

+
    +
  • step > Amount to increase/decrease (default: 1.0)
  • +
  • min > Min. value allowed (default: no limit)
  • +
  • max > Max. value allowed (default: no limit)
  • +
  • auto_select > Select the content when the element get focus (default: +False)
  • +
  • placeholder > Define the placeholder text (default: None)
  • +
  • class > Define additional classes for the input (default: None)
  • +
+

Examples

+

Iteration with 0.25 step, min to -1 and max to 10.

+

Start to increment with button, continue incrementing with scrolling +mouse.

+

image2

+

Iteration with 10 step, max limit 15, placeholder with onchange

+

image3

+

Demo

+

You can test the feature by going to Settings > Technical > Scheduled +Actions. The field “Execute Every” is configured to use the widget with +2 step, min to 0 and max to 40.

+
+
+

Known issues / Roadmap

+

When the value is entered using the keyboard, the limits set in the +widget can be exceeded

+
+
+

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 to smash it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • GRAP
  • +
  • Tecnativa
  • +
+
+
+

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.

+

Current maintainers:

+

rafaelbn yajo

+

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_numeric_step/static/description/step0,25andlimits.gif b/web_widget_numeric_step/static/description/step0,25andlimits.gif new file mode 100644 index 00000000000..ce6780e1b75 Binary files /dev/null and b/web_widget_numeric_step/static/description/step0,25andlimits.gif differ diff --git a/web_widget_numeric_step/static/description/step10_limit15_placeholder117_with_onchange.gif b/web_widget_numeric_step/static/description/step10_limit15_placeholder117_with_onchange.gif new file mode 100644 index 00000000000..709498e3cf3 Binary files /dev/null and b/web_widget_numeric_step/static/description/step10_limit15_placeholder117_with_onchange.gif differ diff --git a/web_widget_numeric_step/static/src/numeric_step.esm.js b/web_widget_numeric_step/static/src/numeric_step.esm.js new file mode 100644 index 00000000000..002591b87f7 --- /dev/null +++ b/web_widget_numeric_step/static/src/numeric_step.esm.js @@ -0,0 +1,89 @@ +import {FloatField} from "@web/views/fields/float/float_field"; +import {_t} from "@web/core/l10n/translation"; +import {registry} from "@web/core/registry"; +import {standardFieldProps} from "@web/views/fields/standard_field_props"; + +export class NumericStep extends FloatField { + setup() { + super.setup(); + } + _onStepClick(ev) { + const mode = ev.target.dataset.mode; + this._doStep(mode); + } + _onKeyDown(ev) { + if (ev.keyCode === 38) { + this._doStep("plus"); + } else if (ev.keyCode === 40) { + this._doStep("minus"); + } + } + _onWheel(ev) { + ev.preventDefault(); + if (!this._lastWheelTime) { + this._lastWheelTime = 0; + } + const now = Date.now(); + const throttleLimit = 100; + if (now - this._lastWheelTime >= throttleLimit) { + this._lastWheelTime = now; + + if (ev.deltaY > 0) { + this._doStep("minus"); + } else { + this._doStep("plus"); + } + } + } + updateField(val) { + return this.props.record.update({[this.props.name]: val}); + } + _doStep(mode) { + let cval = this.props.record.data[this.props.name]; + if (mode === "plus") { + cval += this.props.step; + } else if (mode === "minus") { + cval -= this.props.step; + } + if (cval < this.props.min) { + cval = this.props.min; + } else if (cval > this.props.max) { + cval = this.props.max; + } + this.updateField(cval); + } +} + +NumericStep.template = "web_widget_numeric_step"; +NumericStep.props = { + ...standardFieldProps, + inputType: {type: String, optional: true}, + step: {type: Number, optional: true}, + min: {type: Number, optional: true}, + max: {type: Number, optional: true}, + placeholder: {type: String, optional: true}, + additional_class: {type: String, optional: true}, +}; +NumericStep.defaultProps = { + ...FloatField.defaultProps, + inputType: "text", +}; + +export const numericStep = { + component: NumericStep, + supportedTypes: ["float"], + displayName: _t("Numeric Step"), + extractProps: ({attrs, options}) => { + return { + name: attrs.name, + inputType: attrs.type, + step: options.step || 1, + min: options.min, + max: options.max, + placeholder: attrs.placeholder, + additional_class: attrs.class, + }; + }, +}; + +registry.category("fields").add("numeric_step", numericStep); diff --git a/web_widget_numeric_step/static/src/numeric_step.scss b/web_widget_numeric_step/static/src/numeric_step.scss new file mode 100644 index 00000000000..04a55184f07 --- /dev/null +++ b/web_widget_numeric_step/static/src/numeric_step.scss @@ -0,0 +1,22 @@ +// Copyright 2023 Moduon Team S.L. +// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +.widget_numeric_step { + // Hide the buttons until the user hovers if possible + @media (hover: hover) { + .btn_numeric_step { + visibility: hidden; + } + } + &:hover .btn_numeric_step { + visibility: visible; + } +} + +.o_numeric_step_cell { + // Default for old browsers + min-width: 15 * $btn-padding-x; + // Value hardcoded in `FIXED_FIELD_COLUMN_WIDTHS.float` + width of 2 + // FontAwesome icons + 2 buttons * 2 horizontal paddings + min-width: calc(92px + 2ex + 4 * #{$btn-padding-x}); +} diff --git a/web_widget_numeric_step/static/src/numeric_step.xml b/web_widget_numeric_step/static/src/numeric_step.xml new file mode 100644 index 00000000000..f6aa28637b9 --- /dev/null +++ b/web_widget_numeric_step/static/src/numeric_step.xml @@ -0,0 +1,47 @@ + + + diff --git a/web_widget_one2many_tree_line_duplicate/README.rst b/web_widget_one2many_tree_line_duplicate/README.rst index 1bb82515397..3b8f5387efc 100644 --- a/web_widget_one2many_tree_line_duplicate/README.rst +++ b/web_widget_one2many_tree_line_duplicate/README.rst @@ -11,7 +11,7 @@ Web Widget One2many Tree Line Duplicate !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:e5b95135142c797c5a7addebf73d134f9acbec555ff441d0c2baf718accd04f0 + !! source digest: sha256:3b891d75bd44e3d0168c0baf1a0dc436298293a61dc316fe13c5f60afb0b3ff4 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/web_widget_one2many_tree_line_duplicate/__manifest__.py b/web_widget_one2many_tree_line_duplicate/__manifest__.py index 7389a638daf..0fc49b5824a 100644 --- a/web_widget_one2many_tree_line_duplicate/__manifest__.py +++ b/web_widget_one2many_tree_line_duplicate/__manifest__.py @@ -4,7 +4,7 @@ { "name": "Web Widget One2many Tree Line Duplicate", "category": "web", - "version": "19.0.1.0.0", + "version": "19.0.1.0.1", "author": "Tecnativa, Odoo Community Association (OCA)", "license": "AGPL-3", "website": "https://github.com/OCA/web", diff --git a/web_widget_one2many_tree_line_duplicate/static/description/index.html b/web_widget_one2many_tree_line_duplicate/static/description/index.html index ab0938d05c1..22afc18a8f9 100644 --- a/web_widget_one2many_tree_line_duplicate/static/description/index.html +++ b/web_widget_one2many_tree_line_duplicate/static/description/index.html @@ -372,7 +372,7 @@

Web Widget One2many Tree Line Duplicate

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:e5b95135142c797c5a7addebf73d134f9acbec555ff441d0c2baf718accd04f0 +!! source digest: sha256:3b891d75bd44e3d0168c0baf1a0dc436298293a61dc316fe13c5f60afb0b3ff4 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

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

Allow to add a icon to clone the line.

diff --git a/web_widget_one2many_tree_line_duplicate/static/src/list/list_renderer.esm.js b/web_widget_one2many_tree_line_duplicate/static/src/list/list_renderer.esm.js index 5ffd8ba6355..333d3beaef0 100644 --- a/web_widget_one2many_tree_line_duplicate/static/src/list/list_renderer.esm.js +++ b/web_widget_one2many_tree_line_duplicate/static/src/list/list_renderer.esm.js @@ -5,6 +5,20 @@ import {ListRenderer} from "@web/views/list/list_renderer"; import {patch} from "@web/core/utils/patch"; import {exprToBoolean} from "@web/core/utils/strings"; import {browser} from "@web/core/browser/browser"; +import {x2ManyCommands} from "@web/core/orm_service"; + +const SCALAR_TYPES = [ + "integer", + "float", + "monetary", + "char", + "text", + "boolean", + "selection", + "date", + "datetime", +]; +const MANY2ONE_TYPES = ["many2one", "many2one_reference", "reference"]; patch(ListRenderer.prototype, { setup() { @@ -47,40 +61,146 @@ patch(ListRenderer.prototype, { } return nbCols; }, - async onCloneIconClick(record) { - const list = this.props.list; - const left = await list.leaveEditMode(); - if (!left) { - return; - } - // Snapshot of the source's scalar values, including the readonly computed - // ones (subtotals...), so the copy is exact. duplicateRecords creates the - // line running its onchanges, which recompute editable fields (e.g. - // price_unit from the product) and discard the manual values. We re-apply - // this snapshot with withoutOnchange so those values are kept. - const scalarTypes = [ - "integer", - "float", - "monetary", - "char", - "text", - "boolean", - "selection", - "date", - "datetime", - ]; + /** + * Snapshot of the record's values, including the readonly computed ones + * (subtotals...), so the copy is exact. duplicateRecords creates the line + * running its onchanges, which recompute editable fields (e.g. price_unit + * from the product) and discard the manual values. We re-apply this + * snapshot with withoutOnchange so those values are kept. + * + * @param {Record} record record to copy the values from + * @param {StaticList} list list the record belongs to + * @returns {Object} changes to apply on the copy + */ + getDuplicateSnapshot(record, list) { const snapshot = {}; for (const [name, value] of Object.entries(record.data)) { const field = record.fields[name]; if ( - field && - name !== "display_name" && - name !== list.handleField && - scalarTypes.includes(field.type) + !field || + name === "display_name" || + name === list.handleField || + name === list.config.relationField ) { + continue; + } + if (SCALAR_TYPES.includes(field.type)) { snapshot[name] = value; + } else if (MANY2ONE_TYPES.includes(field.type)) { + // Always invisible many2ones are read as a plain id (see + // getFieldsSpec), so we wrap it and let the model complete the + // value (display_name...) when applying the change. The rest are + // copied as a new object, so both records don't share it. + snapshot[name] = + typeof value === "number" + ? {id: value} + : value && Object.assign({}, value); + } else if (field.type === "many2many") { + // SET (and not LINK) so the copy ends up with exactly the same + // records as the source: this way we also drop the ones the + // onchange added on its own. + snapshot[name] = [x2ManyCommands.set([...value.currentIds])]; + } + // One2many fields can't be set through a snapshot: they are copied + // sub-record by sub-record in duplicateOne2manyValues(). + } + return snapshot; + }, + /** + * Fetches the values of the sub-records of a one2many that is always + * invisible in the list: those are read with their ids only (see + * getFieldsSpec), so their datapoints are empty and copying them as they are + * would end up creating empty (and usually invalid) records. + * + * @param {Record} record source record + * @param {String} fieldName name of the one2many field + */ + async loadOne2manyValues(record, fieldName) { + const invisible = record.activeFields[fieldName].invisible; + if (invisible !== "True" && invisible !== "1") { + return; + } + const list = record.data[fieldName]; + const lines = list.records.filter((line) => line.resId); + if (!lines.length) { + return; + } + const values = await list.model._loadRecords( + {...list.config, resIds: lines.map((line) => line.resId)}, + list.evalContext + ); + for (const line of lines) { + const lineValues = values.find((vals) => vals.id === line.resId); + if (lineValues) { + line._applyValues(lineValues); + } + } + }, + /** + * Recreates on the copy the sub-records of every one2many field of the + * source. They are the only values the snapshot can't carry, as each + * sub-record has to be created (and filled) on its own. The lines the + * onchanges may have generated on the copy are dropped first, so both + * records end up with exactly the same content. + * + * @param {Record} record source record + * @param {Record} newRecord copy of the source record + */ + async duplicateOne2manyValues(record, newRecord) { + for (const [name, sourceList] of Object.entries(record.data)) { + const field = record.fields[name]; + if (!field || field.type !== "one2many" || !(name in newRecord.data)) { + continue; + } + const targetList = newRecord.data[name]; + if ( + !Object.keys(sourceList.activeFields).length || + !Object.keys(targetList.activeFields).length + ) { + // The sub-records have no fields to copy (the field has no + // sub-view here). + continue; } + await this.loadOne2manyValues(record, name); + if (targetList.records.length) { + // DELETE for the lines the onchange created on the fly, UNLINK + // for the existing ones it linked: this way we only discard the + // pending commands, without touching any stored record. + await targetList._applyCommands( + targetList.records.map((line) => + line.resId + ? [x2ManyCommands.UNLINK, line.resId] + : [x2ManyCommands.DELETE, line._virtualId] + ) + ); + } + for (const line of sourceList.records) { + const newLine = await targetList._createNewRecordDatapoint({ + mode: "readonly", + }); + const snapshot = this.getDuplicateSnapshot(line, targetList); + if (Object.keys(snapshot).length) { + await newLine._update(snapshot, { + withoutOnchange: true, + withoutParentUpdate: true, + }); + } + // Nested one2manys are copied the same way, recursively. + await this.duplicateOne2manyValues(line, newLine); + // Added at the end, like the core does when duplicating: the + // record is filled before being part of the list, so the + // intermediate values are never rendered. + await targetList._addRecord(newLine, {position: "bottom"}); + } + } + }, + async onCloneIconClick(record) { + const list = this.props.list; + const left = await list.leaveEditMode(); + if (!left) { + return; } + const snapshot = this.getDuplicateSnapshot(record, list); // Run everything in a single model transaction and notify only once, at // the end, so the intermediate (onchange-recomputed) values are never // rendered: the line appears directly with the original values, without @@ -91,15 +211,14 @@ patch(ListRenderer.prototype, { // The duplicate is inserted right after the source line; identify it // by position (references aren't stable across the re-wrapping). const newRecord = list.records[sourceIndex + 1]; - if ( - newRecord && - newRecord.id !== record.id && - Object.keys(snapshot).length - ) { - await newRecord._update(snapshot, { - withoutOnchange: true, - withoutParentUpdate: true, - }); + if (newRecord && newRecord.id !== record.id) { + if (Object.keys(snapshot).length) { + await newRecord._update(snapshot, { + withoutOnchange: true, + withoutParentUpdate: true, + }); + } + await this.duplicateOne2manyValues(record, newRecord); } await list._onUpdate(); });