mirror of
https://github.com/OCA/web.git
synced 2025-02-22 13:21:25 +02:00
@@ -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.
|
||||
|
||||
|
||||
@@ -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/**/*",
|
||||
],
|
||||
},
|
||||
|
||||
@@ -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.
|
||||
@@ -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>
|
||||
|
||||
@@ -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(
|
||||
() => {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -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});
|
||||
}
|
||||
Reference in New Issue
Block a user