[IMP] web_widget_product_label_section_and_note: Auto-resize textarea for multiline text.

Before this change, when the text was large and multiline, the textarea did not resize, and the text was not displayed correctly. Now, the textarea adjusts according to the text. These changes are backported from V18.
pull/3080/head
Carlos Lopez 2024-12-12 07:07:58 -05:00
parent 8d42b1676d
commit fe81a03937
7 changed files with 166 additions and 6 deletions

View File

@ -7,7 +7,7 @@ Web widget product label section and note
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:b34f3ca01ada6453f702e988c896537cf322d1f7dae827582f4e07313735dc66
!! source digest: sha256:db9a30e28410d3ef4ad626f850f766eedb3845976f424d1bbae3350674397d0d
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
@ -57,7 +57,7 @@ Usage
Known issues / Roadmap
======================
- Add compatibility with `sale` module
- Add compatibility with `sale_product_configurator` module
- Add compatibility with `purchase_product_matrix` module
- When this module is installed, the PDF report will always display the column `name` as a combination of the `product code`, `product name`, and `description`. This behavior may differ from the expected behavior, where only the column `name` is displayed and can be customized independently.

View File

@ -1,6 +1,6 @@
{
"name": "Web widget product label section and note",
"version": "16.0.1.0.0",
"version": "16.0.1.0.1",
"summary": "unify the product and name into a single column",
"author": "Tecnativa, Odoo Community Association (OCA), Odoo S.A.",
"website": "https://github.com/OCA/web",
@ -13,6 +13,7 @@
],
"assets": {
"web.assets_backend": [
"web_widget_product_label_section_and_note/static/src/core/utils/**/*",
"web_widget_product_label_section_and_note/static/src/components/**/*",
],
},

View File

@ -1,3 +1,3 @@
- Add compatibility with `sale` module
- Add compatibility with `sale_product_configurator` module
- Add compatibility with `purchase_product_matrix` module
- When this module is installed, the PDF report will always display the column `name` as a combination of the `product code`, `product name`, and `description`. This behavior may differ from the expected behavior, where only the column `name` is displayed and can be customized independently.

View File

@ -367,7 +367,7 @@ ul.auto-toc {
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:b34f3ca01ada6453f702e988c896537cf322d1f7dae827582f4e07313735dc66
!! source digest: sha256:db9a30e28410d3ef4ad626f850f766eedb3845976f424d1bbae3350674397d0d
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/web/tree/16.0/web_widget_product_label_section_and_note"><img alt="OCA/web" src="https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/web-16-0/web-16-0-web_widget_product_label_section_and_note"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/web&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module unifies the product and name into a single column, making it more user-friendly and space-saving.</p>
@ -407,7 +407,7 @@ in a new module, it is necessary to create an inherited view to change the widge
<div class="section" id="known-issues-roadmap">
<h1><a class="toc-backref" href="#toc-entry-3">Known issues / Roadmap</a></h1>
<ul class="simple">
<li>Add compatibility with <cite>sale</cite> module</li>
<li>Add compatibility with <cite>sale_product_configurator</cite> module</li>
<li>Add compatibility with <cite>purchase_product_matrix</cite> module</li>
<li>When this module is installed, the PDF report will always display the column <cite>name</cite> as a combination of the <cite>product code</cite>, <cite>product name</cite>, and <cite>description</cite>. This behavior may differ from the expected behavior, where only the column <cite>name</cite> is displayed and can be customized independently.</li>
</ul>

View File

@ -20,6 +20,7 @@ import {X2ManyField} from "@web/views/fields/x2many/x2many_field";
import {_t} from "@web/core/l10n/translation";
import {getActiveHotkey} from "@web/core/hotkeys/hotkey_service";
import {registry} from "@web/core/registry";
import {useProductAndLabelAutoresize} from "../../core/utils/product_and_label_autoresize.esm";
export class ProductLabelSectionAndNoteListRender extends SectionAndNoteListRenderer {
setup() {
@ -138,7 +139,13 @@ export class ProductLabelSectionAndNoteField extends Many2OneField {
value: this.props.record.columnIsProductAndLabel,
});
this.labelNode = useRef("labelNodeRef");
useProductAndLabelAutoresize(this.labelNode, {
targetParentName: this.props.name,
});
this.productNode = useRef("productNodeRef");
useProductAndLabelAutoresize(this.productNode, {
targetParentName: this.props.name,
});
useEffect(
() => {

View File

@ -0,0 +1,111 @@
/** @odoo-module **/
/* Copyright Odoo S.A.
* Copyright 2024 Tecnativa - Carlos Lopez
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
import {useEffect} from "@odoo/owl";
import {browser} from "@web/core/browser/browser";
function resizeInput(input) {
// This mesures the maximum width of the input which can get from the flex layout.
input.style.width = "100%";
const maxWidth = input.clientWidth;
// Somehow Safari 16 computes input sizes incorrectly. This is fixed in Safari 17
const isSafari16 = /Version\/16.+Safari/i.test(browser.navigator.userAgent);
// Minimum width of the input
input.style.width = "10px";
if (input.value === "" && input.placeholder !== "") {
input.style.width = "auto";
return;
}
if (input.scrollWidth + 5 + (isSafari16 ? 8 : 0) > maxWidth) {
input.style.width = "100%";
return;
}
input.style.width = input.scrollWidth + 5 + (isSafari16 ? 8 : 0) + "px";
}
export function resizeTextArea(textarea, options = {}) {
const minimumHeight = options.minimumHeight || 0;
let heightOffset = 0;
const style = window.getComputedStyle(textarea);
if (style.boxSizing === "border-box") {
const paddingHeight =
parseFloat(style.paddingTop) + parseFloat(style.paddingBottom);
const borderHeight =
parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth);
heightOffset = borderHeight + paddingHeight;
}
const previousStyle = {
borderTopWidth: style.borderTopWidth,
borderBottomWidth: style.borderBottomWidth,
padding: style.padding,
};
Object.assign(textarea.style, {
height: "auto",
borderTopWidth: 0,
borderBottomWidth: 0,
paddingTop: 0,
paddingRight: style.paddingRight,
paddingBottom: 0,
paddingLeft: style.paddingLeft,
});
textarea.style.height = "auto";
const height = Math.max(minimumHeight, textarea.scrollHeight + heightOffset);
Object.assign(textarea.style, previousStyle, {height: `${height}px`});
textarea.parentElement.style.height = `${height}px`;
}
/**
* This is used on text inputs or textareas to automatically resize it based on its
* content each time it is updated. It takes the reference of the element as
* parameter and some options. Do note that it may introduce mild performance issues
* since it will force a reflow of the layout each time the element is updated.
* Do also note that it only works with textareas that are nested as only child
* of some parent div (like in the text_field component).
*
* @param {Ref} ref
*/
export function useAutoresize(ref, options = {}) {
let wasProgrammaticallyResized = false;
let resize = null;
useEffect(
(el) => {
if (el) {
resize = (programmaticResize = false) => {
wasProgrammaticallyResized = programmaticResize;
if (el instanceof HTMLInputElement) {
resizeInput(el, options);
} else {
resizeTextArea(el, options);
}
if (options.onResize) {
options.onResize(el, options);
}
};
el.addEventListener("input", () => resize(true));
const resizeObserver = new ResizeObserver(() => {
// This ensures that the resize function is not called twice on input or page load
if (wasProgrammaticallyResized) {
wasProgrammaticallyResized = false;
return;
}
resize();
});
resizeObserver.observe(el);
return () => {
el.removeEventListener("input", resize);
resizeObserver.unobserve(el);
resizeObserver.disconnect();
resize = null;
};
}
},
() => [ref.el]
);
useEffect(() => {
if (resize) {
resize(true);
}
});
}

View File

@ -0,0 +1,41 @@
/** @odoo-module **/
/* Copyright Odoo S.A.
* Copyright 2024 Tecnativa - Carlos Lopez
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
import {useAutoresize} from "./autoresize.esm";
export function productAndLabelResizeTextArea(textarea, options = {}) {
const style = window.getComputedStyle(textarea);
if (options.targetParentName) {
let target = textarea.parentElement;
let shouldContinue = true;
while (target && shouldContinue) {
const totalParentHeight = Array.from(target.children).reduce(
(total, child) => {
const childHeight = child.style.height || style.lineHeight;
return total + parseFloat(childHeight);
},
0
);
target.style.height = `${totalParentHeight}px`;
if (target.getAttribute("name") === options.targetParentName) {
shouldContinue = false;
}
target = target.parentElement;
}
}
}
/**
* This overriden version of the resizeTextArea method is specificly done for the product_label_section_and_note widget
* His necessity is found in the fact that the cell of said widget doesn't contain only the input or textarea to resize
* but also another node containing the name of the product if said data is available. This means that the autoresize
* method which sets the height of the parent cell should sometimes add an additional row to the parent cell so that
* no text overflows
*
* @param {Ref} ref
*/
export function useProductAndLabelAutoresize(ref, options = {}) {
useAutoresize(ref, {onResize: productAndLabelResizeTextArea, ...options});
}