Adwait
Adwait

Reputation: 1

I want to Add a new pre-defined style option in Odoo 16 Web Editor Toolbar

  1. **I want to Add a new pre-defined style option in Odoo 16 Web Editor Toolbar. **

I am unable to make out if the problem lies in xpath or somewhere else.

  1. The add-on is web_editor and the relevant template is [id=web_editor.toolbar] located at odoo/addons/web_editor/static/src/xml/editor.xml

  2. Styles are defined at xpath: //div[@id='style']/ul[@class='dropdown-menu'] Each '<li>' tag contains a style.

  3. I've created a new file in my custom addon folder named my_addon. It is placed at my_addon/static/src/views/html_toolbar.xml This extends the template web_editor.toolbar and adds a new '<li>' tag for the style.

**html_toolbar.xml **

<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
    <t t-name="my_addon.toolbarcustom" t-inherit="web_editor.toolbar" t-inherit-mode="extension" owl="1">
        <xpath expr="//div[@id='style']/ul[@class='dropdown-menu']/li[last()]" position="after">
            <li id="span-dropdown-item">
                <a class="dropdown-item" href="#" id="span_id" data-call="setTag" data-arg1="span">
                    <span>Span</span>
                </a>
            </li>
        </xpath>
    </t>
</templates>
  1. I've included the html_editor.xml file in manifest.py
    'assets': {
        'web.assets_backend': [
            'my_addon/static/src/views/html_toolbar.xml'
        ]
  1. The xpath expr="//div[@id='style']/ul[@class='dropdown-menu']/li[last()]" works out on online debuggers. Upon running and updating my_addon, it doesn't reflect a newly added style. If I add a new li tag directly in editor.xml, it does reflect in toolbar.

There's something I am unable to decipher here. Much thanks in advance for any help.

Upvotes: 0

Views: 793

Answers (1)

Ahrimann Steiner
Ahrimann Steiner

Reputation: 1314

In your manifest file, You should use - instead of web.assets_backend: web.assets_wysiwyg ...and use as directory: src/xml instead of src/views:

    'assets': {
        'web.assets_wysiwyg': [
            'my_addon/static/src/xml/html_toolbar.xml'
        ]

The majority of custom code written will fit into these bundles:

web.assets_common: Loaded everywhere (frontend, backend, point of sale).

web.assets_backend: Only loaded into the "backend" of the application. By backend, I'm talking about where you login as a backend user at /web/login. This bundle is excluded from the frontend website.

web.assets_frontend: The opposite of web.assets_backend, only loaded into the frontend website.

web.assets_qweb: Loads QWeb XML files.

web.assets_wysiwyg: Loads assets into the backend wysiwyg text editor.

website.assets_editor: Loads assets into the frontend website edit mode.

web.assets_tests: Loads assets for frontend testing and tours.

web._assets_primary_variables: Used to load custom scss variables for styles.

Source: https://holdenrehg.com/blog/2021-10-08_odoo-manifest-asset-bundles

The structure commonly used in odoo16 for such a template is slightly different from the one that you use ; for example, the website_forum addon uses t-jquery instead of xpath to append new element:

    <t t-name="website_forum.web_editor_toolbar" t-extend="web_editor.toolbar" primary="True">
        <t t-jquery="li#heading1-dropdown-item" t-operation="replace"/>
        <t t-jquery="li#heading2-dropdown-item" t-operation="replace"/>
        <t t-jquery="li#heading3-dropdown-item" t-operation="replace"/>
        <t t-jquery="div#font-size" t-operation="replace"/>
        <t t-jquery="div#colorInputButtonGroup" t-operation="replace"/>
        <t t-jquery="div#toolbar" t-operation="append">
            <div id="history" class="btn-group">
                <div id="undo" data-call="undo" class="btn fa fa-undo"/>
                <div id="redo" data-call="redo" class="btn fa fa-repeat"/>
            </div>
        </t>
    </t>

Moreover, you might need some js to interact with it... Just as example (from the website_forum addon): website_forum.js:

        _.each($('textarea.o_wysiwyg_loader'), function (textarea) {
            var $textarea = $(textarea);
            var editorKarma = $textarea.data('karma') || 0; // default value for backward compatibility
            var $form = $textarea.closest('form');
            var hasFullEdit = parseInt($("#karma").val()) >= editorKarma;

            var options = {
                toolbarTemplate: 'website_forum.web_editor_toolbar',
                recordInfo: {
                    context: self._getContext(),
                    res_model: 'forum.post',
                    // Id is retrieved from URL, which is either:
                    // - /forum/name-1/post/something-5
                    // - /forum/name-1/post/something-5/edit
                    // TODO: Make this more robust.
                    res_id: +window.location.pathname.split('-').slice(-1)[0].split('/')[0],
                },
                resizable: true,
                userGeneratedContent: true,
                height: 350,
            };
            options.allowCommandLink = hasFullEdit;
            options.allowCommandImage = hasFullEdit;
            wysiwygLoader.loadFromTextarea(self, $textarea[0], options).then(wysiwyg => {
                if (!hasFullEdit) {
                    wysiwyg.toolbar.$el.find('#link, #media').remove();
                }
                // float-start class messes up the post layout OPW 769721
                $form.find('.note-editable').find('img.float-start').removeClass('float-start');
            });
        });

-------------------- ALTERNATIVE ? ----------------------

Maybe, you could use the Powerbox for your purpose ?

Example (from https://www.odoo.com/documentation/16.0/fr/developer/reference/frontend/odoo_editor.html#powerbox)

Say we want to add a new command Document to the Powerbox, just for the mass_mailing module. We want to add it to a new category called Documentation and we want it all the way at the top of the Powerbox.

mass_mailing extends web_editor’s Wysiwyg class, which instantiates the editor in its start method. Before doing so, it calls its own _getPowerboxOptions method, which can conveniently be overridden to add our new commands.

Since mass_mailing already overrides _getPowerboxOptions, let’s just add our new command to it:

_getPowerboxOptions: function () {
    const options = this._super();
    // (existing code before the return statement)
    options.categories.push({
        name: _t('Documentation'),
        priority: 300,
    });
    options.commands.push({
        name: _t('Document'),
        category: _t('Documentation'),
        description: _t("Add this text to your mailing's documentation"),
        fontawesome: 'fa-book',
        priority: 1, // This is the only command in its category anyway.
    });
    return options;
}

Upvotes: 0

Related Questions