From e871d8a88ea59bda7b9e47233cbdc6b68e56ea45 Mon Sep 17 00:00:00 2001 From: Carlos Lopez Date: Tue, 22 Apr 2025 09:48:48 -0500 Subject: [PATCH] [MIG] web_editor_class_selector: Migration to version 18.0 --- web_editor_class_selector/README.rst | 18 +++-- web_editor_class_selector/__manifest__.py | 13 ++-- .../static/description/index.html | 8 ++- .../src/js/css_selector/css_selector.esm.js | 24 +++++++ .../src/js/css_selector/css_selector.xml | 20 ++++++ .../css_selector/css_selector_plugin.esm.js | 71 +++++++++++++++++++ .../js/{backend => fields}/html_field.esm.js | 20 +++--- .../src/js/odoo-editor/OdooEditor.esm.js | 68 ------------------ .../static/src/js/odoo-editor/commands.esm.js | 12 ---- .../static/src/js/odoo-editor/toolbar.esm.js | 13 ---- .../js/{odoo-editor => utils}/utils.esm.js | 9 +-- .../static/src/js/wysiwyg/wysiwyg.esm.js | 17 +++-- .../static/src/xml/web_editor.xml | 37 ---------- .../views/web_editor_class_views.xml | 8 +-- 14 files changed, 163 insertions(+), 175 deletions(-) create mode 100644 web_editor_class_selector/static/src/js/css_selector/css_selector.esm.js create mode 100644 web_editor_class_selector/static/src/js/css_selector/css_selector.xml create mode 100644 web_editor_class_selector/static/src/js/css_selector/css_selector_plugin.esm.js rename web_editor_class_selector/static/src/js/{backend => fields}/html_field.esm.js (53%) delete mode 100644 web_editor_class_selector/static/src/js/odoo-editor/OdooEditor.esm.js delete mode 100644 web_editor_class_selector/static/src/js/odoo-editor/commands.esm.js delete mode 100644 web_editor_class_selector/static/src/js/odoo-editor/toolbar.esm.js rename web_editor_class_selector/static/src/js/{odoo-editor => utils}/utils.esm.js (86%) delete mode 100644 web_editor_class_selector/static/src/xml/web_editor.xml diff --git a/web_editor_class_selector/README.rst b/web_editor_class_selector/README.rst index f9b51cda2..12896bea4 100644 --- a/web_editor_class_selector/README.rst +++ b/web_editor_class_selector/README.rst @@ -17,13 +17,13 @@ Web editor class selector :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/17.0/web_editor_class_selector + :target: https://github.com/OCA/web/tree/18.0/web_editor_class_selector :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_editor_class_selector + :target: https://translation.odoo-community.org/projects/web-18-0/web-18-0-web_editor_class_selector :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| @@ -60,7 +60,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. @@ -85,6 +85,14 @@ 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. +.. |maintainer-carlos-lopez-tecnativa| image:: https://github.com/carlos-lopez-tecnativa.png?size=40px + :target: https://github.com/carlos-lopez-tecnativa + :alt: carlos-lopez-tecnativa + +Current `maintainer `__: + +|maintainer-carlos-lopez-tecnativa| + +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_editor_class_selector/__manifest__.py b/web_editor_class_selector/__manifest__.py index 70c7eddb3..7c386c00a 100644 --- a/web_editor_class_selector/__manifest__.py +++ b/web_editor_class_selector/__manifest__.py @@ -1,6 +1,6 @@ { "name": "Web editor class selector", - "version": "17.0.1.1.0", + "version": "18.0.1.0.0", "summary": "", "author": "Tecnativa, Odoo Community Association (OCA)", "website": "https://github.com/OCA/web", @@ -17,15 +17,14 @@ ], "assets": { "web.assets_backend": [ - "web_editor_class_selector/static/src/js/backend/**/*", - ], - "web_editor.backend_assets_wysiwyg": [ - "web_editor_class_selector/static/src/js/odoo-editor/**/*", - "web_editor_class_selector/static/src/js/wysiwyg/**/*", + "web_editor_class_selector/static/src/js/css_selector/**/*", "web_editor_class_selector/static/src/scss/demo_styles.scss", - "web_editor_class_selector/static/src/xml/**/", + "web_editor_class_selector/static/src/js/fields/**/*", + "web_editor_class_selector/static/src/js/utils/**/*", + "web_editor_class_selector/static/src/js/wysiwyg/**/*", ], }, + "maintainers": ["carlos-lopez-tecnativa"], "installable": True, "auto_install": False, "license": "AGPL-3", diff --git a/web_editor_class_selector/static/description/index.html b/web_editor_class_selector/static/description/index.html index ee0d6aea9..a9a93015f 100644 --- a/web_editor_class_selector/static/description/index.html +++ b/web_editor_class_selector/static/description/index.html @@ -369,7 +369,7 @@ ul.auto-toc { !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! source digest: sha256:53a338e09db97f68da45d08f963625f60a4069424d8d2f75bcca9887a201824b !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

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

+

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

This module allows users to create custom CSS class records, which can then be selected and applied directly in the HTML editor. Note: The actual CSS file containing the class definitions is not provided by this @@ -408,7 +408,7 @@ supported)

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.

@@ -428,7 +428,9 @@ If you spotted it first, help us to smash 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.

+

Current maintainer:

+

carlos-lopez-tecnativa

+

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_editor_class_selector/static/src/js/css_selector/css_selector.esm.js b/web_editor_class_selector/static/src/js/css_selector/css_selector.esm.js new file mode 100644 index 000000000..303128139 --- /dev/null +++ b/web_editor_class_selector/static/src/js/css_selector/css_selector.esm.js @@ -0,0 +1,24 @@ +import {Component, useState} from "@odoo/owl"; +import {Dropdown} from "@web/core/dropdown/dropdown"; +import {DropdownItem} from "@web/core/dropdown/dropdown_item"; +import {toolbarButtonProps} from "@html_editor/main/toolbar/toolbar"; + +export class CssSelector extends Component { + static template = "web_editor_class_selector.CssSelector"; + static props = { + getItems: Function, + getDisplay: Function, + onSelected: Function, + ...toolbarButtonProps, + }; + static components = {Dropdown, DropdownItem}; + + setup() { + this.items = this.props.getItems(); + this.state = useState(this.props.getDisplay()); + } + + onSelected(item) { + this.props.onSelected(item); + } +} diff --git a/web_editor_class_selector/static/src/js/css_selector/css_selector.xml b/web_editor_class_selector/static/src/js/css_selector/css_selector.xml new file mode 100644 index 000000000..3a0ac6018 --- /dev/null +++ b/web_editor_class_selector/static/src/js/css_selector/css_selector.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + diff --git a/web_editor_class_selector/static/src/js/css_selector/css_selector_plugin.esm.js b/web_editor_class_selector/static/src/js/css_selector/css_selector_plugin.esm.js new file mode 100644 index 000000000..fccc1e13f --- /dev/null +++ b/web_editor_class_selector/static/src/js/css_selector/css_selector_plugin.esm.js @@ -0,0 +1,71 @@ +import {CssSelector} from "./css_selector.esm"; +import {Plugin} from "@html_editor/plugin"; +import {_t} from "@web/core/l10n/translation"; +import {reactive} from "@odoo/owl"; +import {closestElement} from "@html_editor/utils/dom_traversal"; +import {isVisibleTextNode} from "@html_editor/utils/dom_info"; +import {withSequence} from "@html_editor/utils/resource"; + +export class CssSelectorPlugin extends Plugin { + static id = "css_selector_plugin"; + static dependencies = ["selection", "format"]; + resources = { + toolbar_groups: [withSequence(60, {id: "css-selector"})], + toolbar_items: [ + { + id: "css-selector", + groupId: "css-selector", + title: _t("Custom CSS"), + Component: CssSelector, + props: { + getItems: () => this.custom_class_css, + getDisplay: () => this.custom_css, + onSelected: (item) => { + this.dependencies.format.formatSelection(item.class_name, { + formatProps: {className: item.class_name}, + applyStyle: true, + }); + this.updateCustomCssSelectorParams(); + }, + }, + }, + ], + /** Handlers */ + selectionchange_handlers: [this.updateCustomCssSelectorParams.bind(this)], + post_undo_handlers: [this.updateCustomCssSelectorParams.bind(this)], + post_redo_handlers: [this.updateCustomCssSelectorParams.bind(this)], + }; + + setup() { + this.custom_css = reactive({displayName: this.defaultCustomCssName}); + this.custom_class_css = this.config.custom_class_css; + } + updateCustomCssSelectorParams() { + this.custom_css.displayName = this.customCssName; + } + get defaultCustomCssName() { + return _t("Custom CSS"); + } + get customCssName() { + const selectedNodes = this.dependencies.selection + .getSelectedNodes() + .filter( + (n) => + n.nodeType === Node.TEXT_NODE && + closestElement(n).isContentEditable && + isVisibleTextNode(n) + ); + let activeLabel = this.defaultCustomCssName; + for (const selectedTextNode of selectedNodes) { + const parentNode = selectedTextNode.parentElement; + for (const customCss of this.custom_class_css) { + const isActive = parentNode.classList.contains(customCss.class_name); + if (isActive) { + activeLabel = customCss.name; + break; + } + } + } + return activeLabel; + } +} diff --git a/web_editor_class_selector/static/src/js/backend/html_field.esm.js b/web_editor_class_selector/static/src/js/fields/html_field.esm.js similarity index 53% rename from web_editor_class_selector/static/src/js/backend/html_field.esm.js rename to web_editor_class_selector/static/src/js/fields/html_field.esm.js index 67b45aae3..dd82d961b 100644 --- a/web_editor_class_selector/static/src/js/backend/html_field.esm.js +++ b/web_editor_class_selector/static/src/js/fields/html_field.esm.js @@ -1,5 +1,5 @@ -/** @odoo-module **/ -import {HtmlField} from "@web_editor/js/backend/html_field"; +import {CssSelectorPlugin} from "../css_selector/css_selector_plugin.esm"; +import {HtmlField} from "@html_editor/fields/html_field"; import {patch} from "@web/core/utils/patch"; import {useService} from "@web/core/utils/hooks"; @@ -18,14 +18,12 @@ patch(HtmlField.prototype, { ); }); }, - get wysiwygOptions() { - // Provide the custom_class_css to the toolbar through the toolbarOptions. - return { - ...super.wysiwygOptions, - toolbarOptions: { - ...super.wysiwygOptions.toolbarOptions, - custom_class_css: this.custom_class_css, - }, - }; + getConfig() { + // Add the new Plugin to the list of plugins. + // Provide the custom_class_css to the toolbar. + const config = super.getConfig(...arguments); + config.Plugins.push(CssSelectorPlugin); + config.custom_class_css = this.custom_class_css; + return config; }, }); diff --git a/web_editor_class_selector/static/src/js/odoo-editor/OdooEditor.esm.js b/web_editor_class_selector/static/src/js/odoo-editor/OdooEditor.esm.js deleted file mode 100644 index 74734b0fe..000000000 --- a/web_editor_class_selector/static/src/js/odoo-editor/OdooEditor.esm.js +++ /dev/null @@ -1,68 +0,0 @@ -/** @odoo-module **/ -import { - closestElement, - getSelectedNodes, - isVisibleTextNode, -} from "@web_editor/js/editor/odoo-editor/src/utils/utils"; -import {OdooEditor} from "@web_editor/js/editor/odoo-editor/src/OdooEditor"; -import {_t} from "@web/core/l10n/translation"; -import {patch} from "@web/core/utils/patch"; - -patch(OdooEditor.prototype, { - _updateToolbar(show) { - const res = super._updateToolbar(show); - if (!this.toolbar || !this.custom_class_css) { - return res; - } - const sel = this.document.getSelection(); - if (!this.isSelectionInEditable(sel)) { - return res; - } - // Get selected nodes within td to handle non-p elements like h1, h2... - // Targeting
to ensure span stays inside its corresponding block node. - const selectedNodesInTds = [ - ...this.editable.querySelectorAll(".o_selected_td"), - ].map((node) => closestElement(node).querySelector("br")); - const selectedNodes = getSelectedNodes(this.editable).filter( - (n) => - n.nodeType === Node.TEXT_NODE && - closestElement(n).isContentEditable && - isVisibleTextNode(n) - ); - const selectedTextNodes = selectedNodes.length - ? selectedNodes - : selectedNodesInTds; - let activeLabel = ""; - for (const selectedTextNode of selectedTextNodes) { - const parentNode = selectedTextNode.parentElement; - for (const customCss of this.custom_class_css) { - const button = this.toolbar.querySelector("#" + customCss.class_name); - if (button) { - const isActive = parentNode.classList.contains( - customCss.class_name - ); - button.classList.toggle("active", isActive); - - if (isActive) { - activeLabel = button.textContent; - } - } - } - } - // Show current class active in the toolbar - // or remove active class if nothing is selected - const styleSection = this.toolbar.querySelector("#custom_class"); - if (styleSection) { - if (!activeLabel) { - const css_selectors = this.toolbar.querySelectorAll(".css_selector"); - for (const node of css_selectors) { - node.classList.toggle("active", false); - } - } - styleSection.querySelector("button span").textContent = activeLabel - ? activeLabel - : _t("Custom CSS"); - } - return res; - }, -}); diff --git a/web_editor_class_selector/static/src/js/odoo-editor/commands.esm.js b/web_editor_class_selector/static/src/js/odoo-editor/commands.esm.js deleted file mode 100644 index e04641be3..000000000 --- a/web_editor_class_selector/static/src/js/odoo-editor/commands.esm.js +++ /dev/null @@ -1,12 +0,0 @@ -/** @odoo-module **/ -import {editorCommands} from "@web_editor/js/editor/odoo-editor/src/commands/commands"; -import {formatSelection} from "@web_editor/js/editor/odoo-editor/src/utils/utils"; - -const newCommands = { - setCustomCss: (editor, ...args) => { - const selectedId = parseInt(args[0], 10); - const record = editor.custom_class_css.find((item) => item.id === selectedId); - formatSelection(editor, record.class_name); - }, -}; -Object.assign(editorCommands, newCommands); diff --git a/web_editor_class_selector/static/src/js/odoo-editor/toolbar.esm.js b/web_editor_class_selector/static/src/js/odoo-editor/toolbar.esm.js deleted file mode 100644 index 6e2afe703..000000000 --- a/web_editor_class_selector/static/src/js/odoo-editor/toolbar.esm.js +++ /dev/null @@ -1,13 +0,0 @@ -/** @odoo-module */ - -import {Toolbar} from "@web_editor/js/editor/toolbar"; -import {patch} from "@web/core/utils/patch"; - -patch(Toolbar.props, { - ...Toolbar.props, - custom_class_css: {type: Array, optional: true}, -}); -patch(Toolbar.defaultProps, { - ...Toolbar.defaultProps, - custom_class_css: [], -}); diff --git a/web_editor_class_selector/static/src/js/odoo-editor/utils.esm.js b/web_editor_class_selector/static/src/js/utils/utils.esm.js similarity index 86% rename from web_editor_class_selector/static/src/js/odoo-editor/utils.esm.js rename to web_editor_class_selector/static/src/js/utils/utils.esm.js index 706df1302..2c1ccfc5d 100644 --- a/web_editor_class_selector/static/src/js/odoo-editor/utils.esm.js +++ b/web_editor_class_selector/static/src/js/utils/utils.esm.js @@ -1,10 +1,7 @@ -/** @odoo-module **/ -import { - closestElement, - formatsSpecs, -} from "@web_editor/js/editor/odoo-editor/src/utils/utils"; +import {closestElement} from "@html_editor/utils/dom_traversal"; +import {formatsSpecs} from "@html_editor/utils/formatting"; -// This function is called in the _configureToolbar method of the Wysiwyg class +// This function is called in the getEditorConfig method of the Wysiwyg class // It generates the new formatsSpecs object with the custom CSS class export function createCustomCssFormats(custom_class_css) { const newformatsSpecs = {}; diff --git a/web_editor_class_selector/static/src/js/wysiwyg/wysiwyg.esm.js b/web_editor_class_selector/static/src/js/wysiwyg/wysiwyg.esm.js index fccd793b1..eff2a2778 100644 --- a/web_editor_class_selector/static/src/js/wysiwyg/wysiwyg.esm.js +++ b/web_editor_class_selector/static/src/js/wysiwyg/wysiwyg.esm.js @@ -1,17 +1,16 @@ -/** @odoo-module **/ -import {Wysiwyg} from "@web_editor/js/wysiwyg/wysiwyg"; -import {createCustomCssFormats} from "../odoo-editor/utils.esm"; +import {Wysiwyg} from "@html_editor/wysiwyg"; +import {createCustomCssFormats} from "../utils/utils.esm"; import {patch} from "@web/core/utils/patch"; patch(Wysiwyg.prototype, { - _configureToolbar(options) { - super._configureToolbar(options); + getEditorConfig() { + const res = super.getEditorConfig(...arguments); if ( - options.toolbarOptions.custom_class_css && - options.toolbarOptions.custom_class_css.length > 0 + this.props.config.custom_class_css && + this.props.config.custom_class_css.length > 0 ) { - this.odooEditor.custom_class_css = options.toolbarOptions.custom_class_css; - createCustomCssFormats(options.toolbarOptions.custom_class_css); + createCustomCssFormats(this.props.config.custom_class_css); } + return res; }, }); diff --git a/web_editor_class_selector/static/src/xml/web_editor.xml b/web_editor_class_selector/static/src/xml/web_editor.xml deleted file mode 100644 index 9d4d7912e..000000000 --- a/web_editor_class_selector/static/src/xml/web_editor.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - diff --git a/web_editor_class_selector/views/web_editor_class_views.xml b/web_editor_class_selector/views/web_editor_class_views.xml index bd3dfe375..e50291710 100644 --- a/web_editor_class_selector/views/web_editor_class_views.xml +++ b/web_editor_class_selector/views/web_editor_class_views.xml @@ -1,14 +1,14 @@ - view.web.editor.class.tree + view.web.editor.class.list web.editor.class - + - + @@ -50,7 +50,7 @@ Web Editor Class ir.actions.act_window web.editor.class - tree,form + list,form

Click here to add new Web Editor Class.