From e84ac770c6535f24d521e791b380d68264954b81 Mon Sep 17 00:00:00 2001
From: JasminSForgeFlow
Date: Fri, 7 Mar 2025 17:14:27 +0530
Subject: [PATCH] [MIG] web_remember_tree_column_width: Migration to 18.0
---
web_remember_tree_column_width/README.rst | 20 +-
.../__manifest__.py | 2 +-
.../readme/CONTRIBUTORS.md | 1 +
.../readme/CREDITS.md | 6 -
.../static/description/index.html | 34 +-
.../static/src/js/column_width_hook.esm.js | 443 ++++++++++++++++++
.../static/src/js/list_renderer.esm.js | 73 +--
7 files changed, 478 insertions(+), 101 deletions(-)
delete mode 100644 web_remember_tree_column_width/readme/CREDITS.md
create mode 100644 web_remember_tree_column_width/static/src/js/column_width_hook.esm.js
diff --git a/web_remember_tree_column_width/README.rst b/web_remember_tree_column_width/README.rst
index ed8587139..5906fbb13 100644
--- a/web_remember_tree_column_width/README.rst
+++ b/web_remember_tree_column_width/README.rst
@@ -17,13 +17,13 @@ Web Remember Tree Column Width
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github
- :target: https://github.com/OCA/web/tree/17.0/web_remember_tree_column_width
+ :target: https://github.com/OCA/web/tree/18.0/web_remember_tree_column_width
:alt: OCA/web
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
- :target: https://translation.odoo-community.org/projects/web-17-0/web-17-0-web_remember_tree_column_width
+ :target: https://translation.odoo-community.org/projects/web-18-0/web-18-0-web_remember_tree_column_width
: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=17.0
+ :target: https://runboat.odoo-community.org/builds?repo=OCA/web&target_branch=18.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
@@ -42,7 +42,7 @@ 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 `_.
+`feedback `_.
Do not contact contributors directly about support or help with technical issues.
@@ -63,15 +63,7 @@ Contributors
- Cuong Nguyen Mtm
-Other credits
--------------
-
-- Vauxoo
-
-The migration of this module from 15.0 to 16.0 was financially supported
-by:
-
-- Komit (https://komit-consulting.com/)
+- Jasmin Solanki
Maintainers
-----------
@@ -100,6 +92,6 @@ Current `maintainers `__:
|maintainer-frahikLV| |maintainer-luisg123v| |maintainer-cuongnmtm|
-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_remember_tree_column_width/__manifest__.py b/web_remember_tree_column_width/__manifest__.py
index 38ed4370f..f2a63b3ba 100644
--- a/web_remember_tree_column_width/__manifest__.py
+++ b/web_remember_tree_column_width/__manifest__.py
@@ -5,7 +5,7 @@
"website": "https://github.com/OCA/web",
"license": "LGPL-3",
"category": "Extra Tools",
- "version": "17.0.1.0.0",
+ "version": "18.0.1.0.0",
"maintainers": [
"frahikLV",
"luisg123v",
diff --git a/web_remember_tree_column_width/readme/CONTRIBUTORS.md b/web_remember_tree_column_width/readme/CONTRIBUTORS.md
index 9377fab2b..763d20923 100644
--- a/web_remember_tree_column_width/readme/CONTRIBUTORS.md
+++ b/web_remember_tree_column_width/readme/CONTRIBUTORS.md
@@ -2,3 +2,4 @@
- Tomás Álvarez \<\>
- [Komit](https://komit-consulting.com/):
- Cuong Nguyen Mtm \<\>
+- Jasmin Solanki \<\>
\ No newline at end of file
diff --git a/web_remember_tree_column_width/readme/CREDITS.md b/web_remember_tree_column_width/readme/CREDITS.md
deleted file mode 100644
index b4496150a..000000000
--- a/web_remember_tree_column_width/readme/CREDITS.md
+++ /dev/null
@@ -1,6 +0,0 @@
-- Vauxoo
-
-The migration of this module from 15.0 to 16.0 was financially supported
-by:
-
-- Komit ()
diff --git a/web_remember_tree_column_width/static/description/index.html b/web_remember_tree_column_width/static/description/index.html
index 862b1a578..1c8dd4ebd 100644
--- a/web_remember_tree_column_width/static/description/index.html
+++ b/web_remember_tree_column_width/static/description/index.html
@@ -8,10 +8,11 @@
/*
:Author: David Goodger (goodger@python.org)
-:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
+:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
+Despite the name, some widely supported CSS2 features are used.
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
@@ -274,7 +275,7 @@ pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
-pre.code .ln { color: grey; } /* line numbers */
+pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
@@ -300,7 +301,7 @@ span.option {
span.pre {
white-space: pre }
-span.problematic {
+span.problematic, pre.problematic {
color: red }
span.section-subtitle {
@@ -368,7 +369,7 @@ ul.auto-toc {
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:ec03536e8e88c5e3dbb117d391ba923b60e328998f72c81cee3b41c8ecaea9c2
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
-

+

Remember the tree columns’ widths across sessions, and after filtering,
grouping, or reordering.
Table of contents
@@ -378,8 +379,7 @@ grouping, or reordering.
Credits
@@ -389,7 +389,7 @@ grouping, or reordering.
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.
+feedback.
Do not contact contributors directly about support or help with technical issues.
@@ -409,29 +409,21 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
Cuong Nguyen Mtm <cuong.nmtm@komit-consulting.com>
-
-
-
-
-
-
The migration of this module from 15.0 to 16.0 was financially supported
-by:
-
-
+
This module is maintained by the OCA.
-

+
+
+
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:

-
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_remember_tree_column_width/static/src/js/column_width_hook.esm.js b/web_remember_tree_column_width/static/src/js/column_width_hook.esm.js
new file mode 100644
index 000000000..3ad76af78
--- /dev/null
+++ b/web_remember_tree_column_width/static/src/js/column_width_hook.esm.js
@@ -0,0 +1,443 @@
+/* eslint init-declarations: 0 */
+/* eslint no-undef: 0 */
+/* eslint no-use-before-define: 0 */
+
+// Copy file web/static/src/views/list/column_width_hook.js and added custom code for remeber width of column
+
+import {useDebounced} from "@web/core/utils/timing";
+import {browser} from "@web/core/browser/browser";
+import {useComponent, useEffect, useExternalListener} from "@odoo/owl";
+
+// Hardcoded widths
+const DEFAULT_MIN_WIDTH = 80;
+const SELECTOR_WIDTH = 20;
+const OPEN_FORM_VIEW_BUTTON_WIDTH = 54;
+const DELETE_BUTTON_WIDTH = 12;
+const FIELD_WIDTHS = {
+ boolean: [20, 100], // [minWidth, maxWidth]
+ char: [80], // Only minWidth, no maxWidth
+ date: 80, // MinWidth = maxWidth
+ datetime: 145,
+ float: 93,
+ integer: 71,
+ many2many: [80],
+ many2one_reference: [80],
+ many2one: [80],
+ monetary: 105,
+ one2many: [80],
+ reference: [80],
+ selection: [80],
+ text: [80, 1200],
+};
+
+/**
+ * Compute ideal widths based on the rules described on top of this file.
+ *
+ * @params {Element} table
+ * @params {Object} state
+ * @params {Number} allowedWidth
+ * @params {Number[]} startingWidths
+ * @returns {Number[]}
+ */
+function computeWidths(table, state, allowedWidth, startingWidths) {
+ let _columnWidths;
+ const headers = [...table.querySelectorAll("thead th")];
+ const columns = state.columns;
+
+ // Starting point: compute widths
+ if (startingWidths) {
+ _columnWidths = startingWidths.slice();
+ } else if (state.isEmpty) {
+ // Table is empty => uniform distribution as starting point
+ _columnWidths = headers.map(() => allowedWidth / headers.length);
+ } else {
+ // Table contains records => let the browser compute ideal widths
+ // Set table layout auto and remove inline style
+ table.style.tableLayout = "auto";
+ headers.forEach((th) => {
+ th.style.width = null;
+ });
+ // Toggle a className used to remove style that could interfere with the ideal width
+ // computation algorithm (e.g. prevent text fields from being wrapped during the
+ // computation, to prevent them from being completely crushed)
+ table.classList.add("o_list_computing_widths");
+ _columnWidths = headers.map((th) => th.getBoundingClientRect().width);
+ table.classList.remove("o_list_computing_widths");
+ }
+
+ // Force columns to comply with their min and max widths
+ if (state.hasSelectors) {
+ _columnWidths[0] = SELECTOR_WIDTH;
+ }
+ if (state.hasOpenFormViewColumn) {
+ const index = _columnWidths.length - (state.hasActionsColumn ? 2 : 1);
+ _columnWidths[index] = OPEN_FORM_VIEW_BUTTON_WIDTH;
+ }
+ if (state.hasActionsColumn) {
+ _columnWidths[_columnWidths.length - 1] = DELETE_BUTTON_WIDTH;
+ }
+ const columnWidthSpecs = getWidthSpecs(columns);
+ const columnOffset = state.hasSelectors ? 1 : 0;
+ for (let columnIndex = 0; columnIndex < columns.length; columnIndex++) {
+ const thIndex = columnIndex + columnOffset;
+ const {minWidth, maxWidth} = columnWidthSpecs[columnIndex];
+ if (_columnWidths[thIndex] < minWidth) {
+ _columnWidths[thIndex] = minWidth;
+ } else if (maxWidth && _columnWidths[thIndex] > maxWidth) {
+ _columnWidths[thIndex] = maxWidth;
+ }
+ }
+
+ // Expand/shrink columns for the table to fill 100% of available space
+ const totalWidth = _columnWidths.reduce((tot, width) => tot + width, 0);
+ let diff = totalWidth - allowedWidth;
+ if (diff >= 1) {
+ // Case 1: table overflows its parent => shrink some columns
+ const shrinkableColumns = [];
+ let totalAvailableSpace = 0; // Total space we can gain by shrinking columns
+ for (let columnIndex = 0; columnIndex < columns.length; columnIndex++) {
+ const thIndex = columnIndex + columnOffset;
+ const {minWidth, canShrink} = columnWidthSpecs[columnIndex];
+ if (_columnWidths[thIndex] > minWidth && canShrink) {
+ shrinkableColumns.push({thIndex, minWidth});
+ totalAvailableSpace += _columnWidths[thIndex] - minWidth;
+ }
+ }
+ if (diff > totalAvailableSpace) {
+ // We can't find enough space => set all columns to their min width, and there'll be an
+ // horizontal scrollbar
+ for (const {thIndex, minWidth} of shrinkableColumns) {
+ _columnWidths[thIndex] = minWidth;
+ }
+ } else {
+ // There's enough available space among shrinkable columns => shrink them uniformly
+ let remainingColumnsToShrink = shrinkableColumns.length;
+ while (diff >= 1) {
+ const colDiff = diff / remainingColumnsToShrink;
+ for (const {thIndex, minWidth} of shrinkableColumns) {
+ const currentWidth = _columnWidths[thIndex];
+ if (currentWidth === minWidth) {
+ continue;
+ }
+ const newWidth = Math.max(currentWidth - colDiff, minWidth);
+ diff -= currentWidth - newWidth;
+ _columnWidths[thIndex] = newWidth;
+ if (newWidth === minWidth) {
+ remainingColumnsToShrink--;
+ }
+ }
+ }
+ }
+ } else if (diff <= -1) {
+ // Case 2: table is narrower than its parent => expand some columns
+ diff = -diff; // For better readability
+ const expandableColumns = [];
+ for (let columnIndex = 0; columnIndex < columns.length; columnIndex++) {
+ const thIndex = columnIndex + columnOffset;
+ const maxWidth = columnWidthSpecs[columnIndex].maxWidth;
+ if (!maxWidth || _columnWidths[thIndex] < maxWidth) {
+ expandableColumns.push({thIndex, maxWidth});
+ }
+ }
+ // Expand all expandable columns uniformly (i.e. at most, expand columns with a maxWidth
+ // to their maxWidth)
+ let remainingExpandableColumns = expandableColumns.length;
+ while (diff >= 1 && remainingExpandableColumns > 0) {
+ const colDiff = diff / remainingExpandableColumns;
+ for (const {thIndex, maxWidth} of expandableColumns) {
+ const currentWidth = _columnWidths[thIndex];
+ const newWidth = Math.min(
+ currentWidth + colDiff,
+ maxWidth || Number.MAX_VALUE
+ );
+ diff -= newWidth - currentWidth;
+ _columnWidths[thIndex] = newWidth;
+ if (newWidth === maxWidth) {
+ remainingExpandableColumns--;
+ }
+ }
+ }
+ if (diff >= 1) {
+ // All columns have a maxWidth and have been expanded to their max => expand them more
+ for (let columnIndex = 0; columnIndex < columns.length; columnIndex++) {
+ const thIndex = columnIndex + columnOffset;
+ _columnWidths[thIndex] += diff / columns.length;
+ }
+ }
+ }
+ return _columnWidths;
+}
+
+/**
+ * Returns for each column its minimal and (if any) maximal widths.
+ *
+ * @param {Object[]} columns
+ * @returns {Object[]} each entry in this array has a minWidth and optionally a maxWidth key
+ */
+function getWidthSpecs(columns) {
+ return columns.map((column) => {
+ let minWidth;
+ let maxWidth;
+ if (column.attrs && column.attrs.width) {
+ minWidth = maxWidth = parseInt(column.attrs.width.split("px")[0]);
+ } else {
+ let width;
+ if (column.type === "field") {
+ if (column.field.listViewWidth) {
+ width = column.field.listViewWidth;
+ if (typeof width === "function") {
+ width = width({
+ type: column.fieldType,
+ hasLabel: column.hasLabel,
+ });
+ }
+ } else {
+ width = FIELD_WIDTHS[column.widget || column.fieldType];
+ }
+ } else if (column.type === "widget") {
+ width = column.widget.listViewWidth;
+ }
+ if (width) {
+ minWidth = Array.isArray(width) ? width[0] : width;
+ maxWidth = Array.isArray(width) ? width[1] : width;
+ } else {
+ minWidth = DEFAULT_MIN_WIDTH;
+ }
+ }
+ return {minWidth, maxWidth, canShrink: column.type === "field"};
+ });
+}
+
+/**
+ * Given an html element, returns the sum of its left and right padding.
+ *
+ * @param {HTMLElement} el
+ * @returns {Number}
+ */
+function getHorizontalPadding(el) {
+ const {paddingLeft, paddingRight} = getComputedStyle(el);
+ return parseFloat(paddingLeft) + parseFloat(paddingRight);
+}
+
+export function useMagicColumnWidths(tableRef, getState) {
+ const renderer = useComponent();
+ let columnWidths = null;
+ let allowedWidth = 0;
+ let hasAlwaysBeenEmpty = true;
+ let parentWidthFixed = false;
+ let hash;
+ let _resizing = false;
+
+ /**
+ * Apply the column widths in the DOM. If necessary, compute them first (e.g. if they haven't
+ * been computed yet, or if columns have changed).
+ *
+ * Note: the following code manipulates the DOM directly to avoid having to wait for a
+ * render + patch which would occur on the next frame and cause flickering.
+ */
+ function forceColumnWidths() {
+ const table = tableRef.el;
+ const headers = [...table.querySelectorAll("thead th")];
+ const state = getState();
+ const resModel = state.model.config.resModel;
+
+ // Generate a hash to be able to detect when the columns change
+ const columns = state.columns;
+ // The last part of the hash is there to detect that static columns changed (typically, the
+ // selector column, which isn't displayed on small screens)
+ const nextHash = `${columns.map((column) => column.id).join("/")}/${headers.length}`;
+ if (nextHash !== hash) {
+ hash = nextHash;
+ resetWidths();
+ }
+ // If the table has always been empty until now, and it now contains records, we want to
+ // recompute the widths based on the records (typical case: we removed a filter).
+ // Exception: we were in an empty editable list, and we just added a first record.
+ if (hasAlwaysBeenEmpty && !state.isEmpty) {
+ hasAlwaysBeenEmpty = false;
+ const rows = table.querySelectorAll(".o_data_row");
+ if (rows.length !== 1 || !rows[0].classList.contains("o_selected_row")) {
+ resetWidths();
+ }
+ }
+
+ const parentPadding = getHorizontalPadding(table.parentNode);
+ const cellPaddings = headers.map((th) => getHorizontalPadding(th));
+ const totalCellPadding = cellPaddings.reduce(
+ (total, padding) => padding + total,
+ 0
+ );
+ const nextAllowedWidth =
+ table.parentNode.clientWidth - parentPadding - totalCellPadding;
+ const allowedWidthDiff = Math.abs(allowedWidth - nextAllowedWidth);
+ allowedWidth = nextAllowedWidth;
+
+ // When a vertical scrollbar appears/disappears, it may (depending on the browser/os) change
+ // the available width. When it does, we want to keep the current widths, but tweak them a
+ // little bit s.t. the table fits in the new available space.
+ if (!columnWidths || allowedWidthDiff > 0) {
+ columnWidths = computeWidths(table, state, allowedWidth, columnWidths);
+ }
+
+ // Custom code to get width from browser storage and update in list
+ // custom code start here
+ headers.forEach((el, elIndex) => {
+ const fieldName =
+ (state.columns[elIndex] && state.columns[elIndex].name) || "";
+ if (
+ !el.classList.contains("o_list_button") &&
+ fieldName &&
+ resModel &&
+ browser.localStorage
+ ) {
+ const storedWidth = browser.localStorage.getItem(
+ `odoo.columnWidth.${resModel}.${fieldName}`
+ );
+ if (storedWidth) {
+ columnWidths[elIndex + 1] = parseInt(storedWidth, 10);
+ }
+ }
+ });
+ // Custom code end here
+
+ // Set the computed widths in the DOM.
+ table.style.tableLayout = "fixed";
+ headers.forEach((th, index) => {
+ th.style.width = `${Math.floor(columnWidths[index] + cellPaddings[index])}px`;
+ });
+ }
+
+ /**
+ * Resets the widths. After next patch, ideal widths will be recomputed.
+ */
+ function resetWidths() {
+ columnWidths = null;
+ // Unset widths that might have been set on the table by resizing a column
+ tableRef.el.style.width = null;
+ if (parentWidthFixed) {
+ tableRef.el.parentElement.style.width = null;
+ }
+ }
+
+ /**
+ * Handles the resize feature on the column headers
+ *
+ * @private
+ * @param {MouseEvent} ev
+ */
+ function onStartResize(ev) {
+ _resizing = true;
+ const table = tableRef.el;
+ const th = ev.target.closest("th");
+ const handler = th.querySelector(".o_resize");
+ table.style.width = `${Math.floor(table.getBoundingClientRect().width)}px`;
+ const thPosition = [...th.parentNode.children].indexOf(th);
+ const resizingColumnElements = [...table.getElementsByTagName("tr")]
+ .filter((tr) => tr.children.length === th.parentNode.children.length)
+ .map((tr) => tr.children[thPosition]);
+ const initialX = ev.clientX;
+ const initialWidth = th.getBoundingClientRect().width;
+ const initialTableWidth = table.getBoundingClientRect().width;
+ const resizeStoppingEvents = ["keydown", "pointerdown", "pointerup"];
+
+ // Fix the width so that if the resize overflows, it doesn't affect the layout of the parent
+ if (!table.parentElement.style.width) {
+ parentWidthFixed = true;
+ table.parentElement.style.width = `${Math.floor(
+ table.parentElement.getBoundingClientRect().width
+ )}px`;
+ }
+
+ // Apply classes to table and selected column
+ table.classList.add("o_resizing");
+ for (const el of resizingColumnElements) {
+ el.classList.add("o_column_resizing");
+ handler.classList.add("bg-primary", "opacity-100");
+ handler.classList.remove("bg-black-25", "opacity-50-hover");
+ }
+ // Mousemove event : resize header
+ const resizeHeader = (ev) => {
+ ev.preventDefault();
+ ev.stopPropagation();
+ const delta = ev.clientX - initialX;
+ const newWidth = Math.max(10, initialWidth + delta);
+ const tableDelta = newWidth - initialWidth;
+ th.style.width = `${Math.floor(newWidth)}px`;
+ table.style.width = `${Math.floor(initialTableWidth + tableDelta)}px`;
+ };
+ window.addEventListener("pointermove", resizeHeader);
+
+ // Mouse or keyboard events : stop resize
+ const stopResize = (ev) => {
+ _resizing = false;
+
+ // Store current column widths to freeze them
+ const headers = [...table.querySelectorAll("thead th")];
+ columnWidths = headers.map((th) => {
+ return th.getBoundingClientRect().width - getHorizontalPadding(th);
+ });
+
+ // Ignores the 'left mouse button down' event as it used to start resizing
+ if (ev.type === "pointerdown" && ev.button === 0) {
+ return;
+ }
+ ev.preventDefault();
+ ev.stopPropagation();
+
+ table.classList.remove("o_resizing");
+ for (const el of resizingColumnElements) {
+ el.classList.remove("o_column_resizing");
+ handler.classList.remove("bg-primary", "opacity-100");
+ handler.classList.add("bg-black-25", "opacity-50-hover");
+ }
+
+ window.removeEventListener("pointermove", resizeHeader);
+ for (const eventType of resizeStoppingEvents) {
+ window.removeEventListener(eventType, stopResize);
+ }
+
+ // Custom code to set width to browser storage
+ // custom code start here
+ const th = ev.target.closest("th");
+ const fieldName = th.dataset.name;
+ const resModel = this.props.list.model.config.resModel;
+ if (resModel && fieldName && browser.localStorage) {
+ browser.localStorage.setItem(
+ "odoo.columnWidth." + resModel + "." + fieldName,
+ parseInt((th.style.width || "0").replace("px", ""), 10) || 0
+ );
+ }
+ // Custom code end here
+
+ // We remove the focus to make sure that the there is no focus inside
+ // the tr. If that is the case, there is some css to darken the whole
+ // thead, and it looks quite weird with the small css hover effect.
+ document.activeElement.blur();
+ };
+ // We have to listen to several events to properly stop the resizing function. Those are:
+ // - pointerdown (e.g. pressing right click)
+ // - pointerup : logical flow of the resizing feature (drag & drop)
+ // - keydown : (e.g. pressing 'Alt' + 'Tab' or 'Windows' key)
+ for (const eventType of resizeStoppingEvents) {
+ window.addEventListener(eventType, stopResize);
+ }
+ }
+
+ // Side effects
+ if (renderer.constructor.useMagicColumnWidths) {
+ useEffect(forceColumnWidths);
+ const debouncedResizeCallback = useDebounced(() => {
+ resetWidths();
+ forceColumnWidths();
+ }, 200);
+ useExternalListener(window, "resize", debouncedResizeCallback);
+ }
+
+ // API
+ return {
+ get resizing() {
+ return _resizing;
+ },
+ onStartResize,
+ };
+}
diff --git a/web_remember_tree_column_width/static/src/js/list_renderer.esm.js b/web_remember_tree_column_width/static/src/js/list_renderer.esm.js
index 58609d795..ccfc4a024 100644
--- a/web_remember_tree_column_width/static/src/js/list_renderer.esm.js
+++ b/web_remember_tree_column_width/static/src/js/list_renderer.esm.js
@@ -1,66 +1,21 @@
-/** @odoo-module **/
-
import {ListRenderer} from "@web/views/list/list_renderer";
-import {browser} from "@web/core/browser/browser";
+import {useMagicColumnWidths} from "./column_width_hook.esm";
import {patch} from "@web/core/utils/patch";
patch(ListRenderer.prototype, {
- /**
- * @override
- */
- computeColumnWidthsFromContent(allowedWidth) {
- const columnWidths = super.computeColumnWidthsFromContent(allowedWidth);
- const table = this.tableRef.el;
- const thElements = [...table.querySelectorAll("thead th")];
- thElements.forEach((el, elIndex) => {
- const fieldName = $(el).data("name");
- if (
- !el.classList.contains("o_list_button") &&
- this.props.list.resModel &&
- fieldName &&
- browser.localStorage
- ) {
- const storedWidth = browser.localStorage.getItem(
- `odoo.columnWidth.${this.props.list.resModel}.${fieldName}`
- );
- if (storedWidth) {
- columnWidths[elIndex] = parseInt(storedWidth, 10);
- }
- }
+ setup() {
+ super.setup();
+ this.columnWidths = useMagicColumnWidths(this.tableRef, () => {
+ return {
+ columns: this.columns,
+ isEmpty:
+ !this.props.list.records.length ||
+ this.props.list.model.useSampleModel,
+ hasSelectors: this.hasSelectors,
+ hasOpenFormViewColumn: this.hasOpenFormViewColumn,
+ hasActionsColumn: this.hasActionsColumn,
+ model: this.props.list.model,
+ };
});
- return columnWidths;
- },
-
- /**
- * @override
- */
- onStartResize(ev) {
- super.onStartResize(ev);
- const resizeStoppingEvents = ["keydown", "mousedown", "mouseup"];
- const $th = $(ev.target.closest("th"));
- if (!$th || !$th.is("th")) {
- return;
- }
- const saveWidth = (saveWidthEv) => {
- if (saveWidthEv.type === "mousedown" && saveWidthEv.which === 1) {
- return;
- }
- ev.preventDefault();
- ev.stopPropagation();
- const fieldName = $th.length ? $th.data("name") : undefined;
- if (this.props.list.resModel && fieldName && browser.localStorage) {
- browser.localStorage.setItem(
- "odoo.columnWidth." + this.props.list.resModel + "." + fieldName,
- parseInt(($th[0].style.width || "0").replace("px", ""), 10) || 0
- );
- }
- for (const eventType of resizeStoppingEvents) {
- browser.removeEventListener(eventType, saveWidth);
- }
- document.activeElement.blur();
- };
- for (const eventType of resizeStoppingEvents) {
- browser.addEventListener(eventType, saveWidth);
- }
},
});