diff --git a/web_widget_numeric_step/README.rst b/web_widget_numeric_step/README.rst index eed8b55a3..6a270d8db 100644 --- a/web_widget_numeric_step/README.rst +++ b/web_widget_numeric_step/README.rst @@ -14,7 +14,7 @@ Web Widget Numeric Step :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/15.0/web_widget_numeric_step + :target: https://github.com/OCA/web/tree/16.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-15-0/web-15-0-web_widget_numeric_step @@ -60,7 +60,6 @@ Example for an 0.25 step, min to -1 and max to 10 : - 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) **Examples** @@ -108,6 +107,7 @@ Contributors * Helly kapatel * Thanakrit Pintana +* Dhara Solanki Maintainers ~~~~~~~~~~~ @@ -122,6 +122,6 @@ 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. +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/__manifest__.py b/web_widget_numeric_step/__manifest__.py index 1e07c05de..48eea0bfd 100644 --- a/web_widget_numeric_step/__manifest__.py +++ b/web_widget_numeric_step/__manifest__.py @@ -10,14 +10,10 @@ "license": "AGPL-3", "website": "https://github.com/OCA/web", "depends": ["web"], - "demo": ["demo/res_users_view.xml"], "assets": { "web.assets_backend": [ - "web_widget_numeric_step/static/src/js/numeric_step.js", - "web_widget_numeric_step/static/src/css/numeric_step.scss", - ], - "web.assets_qweb": [ "web_widget_numeric_step/static/src/xml/numeric_step.xml", + "web_widget_numeric_step/static/src/js/numeric_step.esm.js", ], }, "auto_install": False, diff --git a/web_widget_numeric_step/demo/res_users_view.xml b/web_widget_numeric_step/demo/res_users_view.xml deleted file mode 100644 index c57e1c7a9..000000000 --- a/web_widget_numeric_step/demo/res_users_view.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - res.users - - - - - - - - - - diff --git a/web_widget_numeric_step/readme/CONTRIBUTORS.rst b/web_widget_numeric_step/readme/CONTRIBUTORS.rst index 31329b39f..3af1d6666 100644 --- a/web_widget_numeric_step/readme/CONTRIBUTORS.rst +++ b/web_widget_numeric_step/readme/CONTRIBUTORS.rst @@ -9,3 +9,4 @@ * Helly kapatel * Thanakrit Pintana +* Dhara Solanki diff --git a/web_widget_numeric_step/static/description/add_two_buttons.png b/web_widget_numeric_step/static/description/add_two_buttons.png index 2670f06ec..7a60f2dea 100644 Binary files a/web_widget_numeric_step/static/description/add_two_buttons.png and b/web_widget_numeric_step/static/description/add_two_buttons.png differ diff --git a/web_widget_numeric_step/static/description/index.html b/web_widget_numeric_step/static/description/index.html index 3ddd75ad5..493a87c4b 100644 --- a/web_widget_numeric_step/static/description/index.html +++ b/web_widget_numeric_step/static/description/index.html @@ -367,7 +367,7 @@ ul.auto-toc { !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

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

+

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

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

@@ -457,7 +457,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome

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.

+

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 index 1e5827236..ce6780e1b 100644 Binary files a/web_widget_numeric_step/static/description/step0,25andlimits.gif 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 index eb0b6e815..709498e3c 100644 Binary files a/web_widget_numeric_step/static/description/step10_limit15_placeholder117_with_onchange.gif and b/web_widget_numeric_step/static/description/step10_limit15_placeholder117_with_onchange.gif differ diff --git a/web_widget_numeric_step/static/src/css/numeric_step.scss b/web_widget_numeric_step/static/src/css/numeric_step.scss deleted file mode 100644 index 7ca8bb842..000000000 --- a/web_widget_numeric_step/static/src/css/numeric_step.scss +++ /dev/null @@ -1,11 +0,0 @@ -.widget_numeric_step { - display: inline-flex; -} - -.numeric_step_editing_cell { - min-width: 120px; - - .input_numeric_step { - height: auto; - } -} diff --git a/web_widget_numeric_step/static/src/js/numeric_step.esm.js b/web_widget_numeric_step/static/src/js/numeric_step.esm.js new file mode 100644 index 000000000..dcd6f233e --- /dev/null +++ b/web_widget_numeric_step/static/src/js/numeric_step.esm.js @@ -0,0 +1,92 @@ +/** @odoo-module */ + +import {registry} from "@web/core/registry"; +import {standardFieldProps} from "@web/views/fields/standard_field_props"; +import {_lt} from "@web/core/l10n/translation"; +import {FloatField} from "@web/views/fields/float/float_field"; + +export class NumericStep extends FloatField { + setup() { + super.setup(); + } + _onFocusInput(ev) { + const $el = $(ev.target).parent().find(".widget_numeric_step_btn"); + $el.removeClass("d-none"); + } + _onFocusOutInput(ev) { + const $el = $(ev.target).find(".widget_numeric_step_btn"); + $el.addClass("d-none"); + } + _onStepClick(ev) { + const $el = $(ev.target).parent().parent().find("input"); + $el.focus(); + const mode = $(ev.target).data("mode"); + this._doStep(mode); + } + _onKeyDown(ev) { + if (ev.keyCode === $.ui.keyCode.UP) { + this._doStep("plus"); + } else if (ev.keyCode === $.ui.keyCode.DOWN) { + this._doStep("minus"); + } + } + _onWheel(ev) { + ev.preventDefault(); + if (ev.deltaY > 0) { + this._doStep("minus"); + } else { + this._doStep("plus"); + } + } + updateField(val) { + return Promise.resolve(this.props.update(val)); + } + _doStep(mode) { + let cval = this.props.value; + 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); + this.props.setDirty(this._isSetDirty(cval)); + this.props.setDirty(false); + } + _isSetDirty(val) { + return this.props.value != val; + } +} + +NumericStep.template = "web_widget_numeric_step"; +NumericStep.props = { + ...standardFieldProps, + name: {type: String, optional: true}, + 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}, +}; + +NumericStep.displayName = _lt("Numeric Step"); +NumericStep.supportedTypes = ["float"]; +NumericStep.defaultProps = { + inputType: "text", +}; +NumericStep.extractProps = ({attrs}) => { + return { + name: attrs.name, + inputType: attrs.options.type, + step: attrs.options.step || 1, + min: attrs.options.min, + max: attrs.options.max, + placeholder: attrs.options.placeholder, + }; +}; + +registry.category("fields").add("numeric_step", NumericStep); diff --git a/web_widget_numeric_step/static/src/js/numeric_step.js b/web_widget_numeric_step/static/src/js/numeric_step.js deleted file mode 100644 index 8c166fe7a..000000000 --- a/web_widget_numeric_step/static/src/js/numeric_step.js +++ /dev/null @@ -1,336 +0,0 @@ -/* Copyright 2019 GRAP - Quentin DUPONT - * Copyright 2020 Tecnativa - Alexandre Díaz - * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) */ - -odoo.define("web_widget_numeric_step.field", function (require) { - "use strict"; - - const field_utils = require("web.field_utils"); - const Registry = require("web.field_registry"); - const FieldFloat = require("web.basic_fields").FieldFloat; - - const NumericStep = FieldFloat.extend({ - template: "web_widget_numeric_step", - className: "o_field_numeric_step o_field_number", - events: _.extend({}, _.omit(FieldFloat.prototype.events, ["change", "input"]), { - "mousedown .btn_numeric_step": "_onStepMouseDown", - "touchstart .btn_numeric_step": "_onStepMouseDown", - "click .btn_numeric_step": "_onStepClick", - "wheel .input_numeric_step": "_onWheel", - "keydown .input_numeric_step": "_onKeyDown", - "change .input_numeric_step": "_onChange", - "input .input_numeric_step": "_onInput", - "focusin .input_numeric_step": "_onFocusIn", - "focusout .widget_numeric_step": "_onFocusOut", - }), - supportedFieldTypes: ["float", "integer"], - - // Values in milliseconds used for mouse down smooth speed feature - DEF_CLICK_DELAY: 400, - MIN_DELAY: 50, - SUBSTRACT_DELAY_STEP: 25, - - DELAY_THROTTLE_CHANGE: 200, - - /** - * @override - */ - init: function () { - this._super.apply(this, arguments); - - // Widget config - let max_val = this.nodeOptions.max; - let min_val = this.nodeOptions.min; - if ( - !_.isUndefined(min_val) && - !_.isUndefined(max_val) && - min_val > max_val - ) { - min_val = this.nodeOptions.max; - max_val = this.nodeOptions.min; - } - - this._config = { - step: Number(this.nodeOptions.step) || 1, - min: Number(min_val), - max: Number(max_val), - autoSelect: this.nodeOptions.auto_select, - }; - - this._lazyOnChangeTrigger = _.debounce( - () => this.$input.trigger("change"), - this.DELAY_THROTTLE_CHANGE - ); - this._auto_step_interval = false; - }, - - /** - * Add global events listeners - * - * @override - */ - start: function () { - this._click_delay = this.DEF_CLICK_DELAY; - this._autoStep = false; - return this._super.apply(this, arguments).then(() => { - document.addEventListener("mouseup", this._onMouseUp.bind(this), false); - document.addEventListener( - "touchend", - this._onMouseUp.bind(this), - false - ); - }); - }, - - /** - * Transform database value to usable widget value - * - * @override - */ - _formatValue: function (value) { - if (this.mode === "edit") { - return this._sanitizeNumberValue(value); - } - return this._super.apply(this, arguments); - }, - - /** - * Transform widget value to usable database value - * - * @override - */ - _parseValue: function () { - const parsedVal = this._super.apply(this, arguments); - if (this.mode === "edit") { - return Number(parsedVal) || 0; - } - return parsedVal; - }, - - /** - * Adds HTML attributes to the input - * - * @override - */ - _prepareInput: function () { - const result = this._super.apply(this, arguments); - this.$input.attr(_.pick(this.nodeOptions, ["placeholder"])); - // InputField hard set the input type to 'text' or 'password', - // we force it again to be 'tel'. - // The widget uses 'tel' type because offers a good layout on - // mobiles and can accept alphanumeric characters. - // The bad news is that require implement all good 'number' type - // features like the minus and plus buttons, steps, min and max... - // Perhaps in a near future this can be improved to have the best of - // two types without hacky developments. - this.$input.attr("type", "tel"); - return result; - }, - - /** - * Select the proper widget input - * - * @override - */ - _renderEdit: function () { - _.defer(() => - this.$el - .parents("td.o_numeric_step_cell") - .addClass("numeric_step_editing_cell") - ); - this._prepareInput(this.$el.find("input.input_numeric_step")); - }, - - /** - * Resets the content to the formated value in readonly mode. - * - * @override - */ - _renderReadonly: function () { - this.$el - .parents("td.numeric_step_editing_cell") - .removeClass("numeric_step_editing_cell"); - this._super.apply(this, arguments); - }, - - /** - * Increase/Decrease widget input value - * - * @param {String} mode can be "plus" or "minus" - */ - _doStep: function (mode) { - let cval = 0; - try { - const field = this.record.fields[this.name]; - cval = field_utils.parse[field.type](this.$input.val()); - } catch (e) { - cval = this.value; - mode = false; // Only set the value in this case - } - if (mode === "plus") { - cval += this._config.step; - } else if (mode === "minus") { - cval -= this._config.step; - } - const nval = this._sanitizeNumberValue(cval); - if (nval !== this.lastSetValue || !mode) { - this.$input.val(nval); - // Every time that user update the value we must trigger an - // onchange method. - this._lazyOnChangeTrigger(); - } - }, - - /** - * @private - */ - _clearStepInterval: function () { - clearTimeout(this._auto_step_interval); - this._auto_step_interval = false; - this._click_delay = this.DEF_CLICK_DELAY; - }, - - // Handle Events - - /** - * @private - * @param {MouseClickEvent} ev - */ - _onStepClick: function (ev) { - if (!this._autoStep) { - const mode = ev.target.dataset.mode; - this._doStep(mode); - } - this._autoStep = false; - }, - - /** - * @private - * @param {MouseClickEvent} ev - */ - _onStepMouseDown: function (ev) { - if (ev.button === 0 && !this._auto_step_interval) { - this._auto_step_interval = setTimeout( - this._whileMouseDown.bind(this, ev), - this._click_delay - ); - } - }, - - /** - * Auto select all content when user enters into fields with this - * widget. - * - * @private - */ - _onFocusIn: function () { - if (this._config.autoSelect) { - this.$input.select(); - } - }, - - /** - * @private - * @param {FocusoutEvent} ev - */ - _onFocusOut: function () { - if (this._auto_step_interval) { - this._clearStepInterval(); - } - }, - - /** - * @private - */ - _onMouseUp: function () { - this._clearStepInterval(); - }, - - /** - * @private - * @param {MouseClickEvent} ev - */ - _whileMouseDown: function (ev) { - this._autoStep = true; - const mode = ev.target.dataset.mode; - this._doStep(mode); - if (this._click_delay > this.MIN_DELAY) { - this._click_delay -= this.SUBSTRACT_DELAY_STEP; - } - - this._auto_step_interval = false; - this._onStepMouseDown(ev); - }, - - /** - * Enable mouse wheel support - * - * @param {WheelEvent} ev - */ - _onWheel: function (ev) { - ev.preventDefault(); - if (ev.originalEvent.deltaY > 0) { - this._doStep("minus"); - } else { - this._doStep("plus"); - } - }, - - /** - * Enable keyboard arrows support - * - * @param {KeyEvent} ev - */ - _onKeyDown: function (ev) { - if (ev.keyCode === $.ui.keyCode.UP) { - this._doStep("plus"); - } else if (ev.keyCode === $.ui.keyCode.DOWN) { - this._doStep("minus"); - } - }, - - /** - * Sanitize user input value - * - * @override - */ - _onChange: function (ev) { - ev.target.value = this._sanitizeNumberValue(ev.target.value); - return this._super.apply(this, arguments); - }, - - // Helper Functions - /** - * Check limits and precision of the value. - * If the value 'is not a number', the function does nothing to - * be good with other possible modules. - * - * @param {Number} value - * @returns {Number} - */ - _sanitizeNumberValue: function (value) { - let cval = Number(value); - if (_.isNaN(cval)) { - return value; - } - if (!_.isNaN(this._config.min) && cval < this._config.min) { - cval = this._config.min; - } else if (!_.isNaN(this._config.max) && cval > this._config.max) { - cval = this._config.max; - } - - const field = this.record.fields[this.name]; - // Formatted value - return field_utils.format[field.type](cval, field, { - data: this.record.data, - escape: true, - isPassword: false, - digits: field.digits, - }); - }, - }); - - Registry.add("numeric_step", NumericStep); - - return NumericStep; -}); diff --git a/web_widget_numeric_step/static/src/xml/numeric_step.xml b/web_widget_numeric_step/static/src/xml/numeric_step.xml index b184d2e95..e645a3923 100644 --- a/web_widget_numeric_step/static/src/xml/numeric_step.xml +++ b/web_widget_numeric_step/static/src/xml/numeric_step.xml @@ -4,37 +4,43 @@ Copyright 2019 GRAP - Quentin DUPONT Copyright 2020 Tecnativa - Alexandre Díaz License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). --> - - - -
-
-
- + +
+
+
-
- - - + +
+
+
-
+