From a9e79f8bda8e18f44cfc823e5eb6b3b200de42b5 Mon Sep 17 00:00:00 2001 From: Antoine Guenet Date: Tue, 22 Mar 2022 13:46:22 +0000 Subject: [PATCH] [ADD] web_editor, mass_mailing: add a "Design" tab to mass_mailing This adds a tab to mass_mailing, that will be used to style the mailing globally. task-2789287 Part-of: odoo/odoo#86881 --- .../static/src/js/snippets.editor.js | 73 +++++++++++++++++++ addons/mass_mailing/views/snippets_themes.xml | 8 +- .../static/src/scss/wysiwyg_snippets.scss | 14 ++++ 3 files changed, 94 insertions(+), 1 deletion(-) diff --git a/addons/mass_mailing/static/src/js/snippets.editor.js b/addons/mass_mailing/static/src/js/snippets.editor.js index 9bf8b202fac..20ef9a44584 100644 --- a/addons/mass_mailing/static/src/js/snippets.editor.js +++ b/addons/mass_mailing/static/src/js/snippets.editor.js @@ -1,15 +1,25 @@ odoo.define('mass_mailing.snippets.editor', function (require) { 'use strict'; +const {_lt} = require('web.core'); const snippetsEditor = require('web_editor.snippet.editor'); const MassMailingSnippetsMenu = snippetsEditor.SnippetsMenu.extend({ + events: _.extend({}, snippetsEditor.SnippetsMenu.prototype.events, { + 'click .o_we_customize_design_btn': '_onDesignTabClick', + }), custom_events: _.extend({}, snippetsEditor.SnippetsMenu.prototype.custom_events, { drop_zone_over: '_onDropZoneOver', drop_zone_out: '_onDropZoneOut', drop_zone_start: '_onDropZoneStart', drop_zone_stop: '_onDropZoneStop', }), + tabs: _.extend({}, snippetsEditor.SnippetsMenu.prototype.tabs, { + DESIGN: 'design', + }), + optionsTabStructure: [ + ['design-options', _lt("Design Options")], + ], //-------------------------------------------------------------------------- // Public @@ -38,6 +48,13 @@ const MassMailingSnippetsMenu = snippetsEditor.SnippetsMenu.extend({ $dropzone.attr('data-editor-sub-message', $hookParent.attr('data-editor-sub-message')); return $dropzone; }, + /** + * @override + */ + _updateRightPanelContent: function ({content, tab}) { + this._super(...arguments); + this.$('.o_we_customize_design_btn').toggleClass('active', tab === this.tabs.DESIGN); + }, //-------------------------------------------------------------------------- // Handler @@ -88,6 +105,62 @@ const MassMailingSnippetsMenu = snippetsEditor.SnippetsMenu.extend({ $oEditable.attr('contenteditable', false); } }, + /** + * @private + */ + async _onDesignTabClick() { + // Note: nothing async here but start the loading effect asap + let releaseLoader; + try { + const promise = new Promise(resolve => releaseLoader = resolve); + this._execWithLoadingEffect(() => promise, false, 0); + // loader is added to the DOM synchronously + await new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve))); + // ensure loader is rendered: first call asks for the (already done) DOM update, + // second call happens only after rendering the first "updates" + + if (!this.topFakeOptionEl) { + let el; + for (const [elementName, title] of this.optionsTabStructure) { + const newEl = document.createElement(elementName); + newEl.dataset.name = title; + if (el) { + el.appendChild(newEl); + } else { + this.topFakeOptionEl = newEl; + } + el = newEl; + } + this.bottomFakeOptionEl = el; + this.el.appendChild(this.topFakeOptionEl); + } + + // Need all of this in that order so that: + // - the element is visible and can be enabled and the onFocus method is + // called each time. + // - the element is hidden afterwards so it does not take space in the + // DOM, same as the overlay which may make a scrollbar appear. + this.topFakeOptionEl.classList.remove('d-none'); + const editorPromise = this._activateSnippet($(this.bottomFakeOptionEl)); + releaseLoader(); // because _activateSnippet uses the same mutex as the loader + releaseLoader = undefined; + const editor = await editorPromise; + this.topFakeOptionEl.classList.add('d-none'); + editor.toggleOverlay(false); + + this._updateRightPanelContent({ + tab: this.tabs.DESIGN, + }); + } catch (e) { + // Normally the loading effect is removed in case of error during the action but here + // the actual activity is happening outside of the action, the effect must therefore + // be cleared in case of error as well + if (releaseLoader) { + releaseLoader(); + } + throw e; + } + }, }); return MassMailingSnippetsMenu; diff --git a/addons/mass_mailing/views/snippets_themes.xml b/addons/mass_mailing/views/snippets_themes.xml index 2605f92de0d..44c29a8b82e 100644 --- a/addons/mass_mailing/views/snippets_themes.xml +++ b/addons/mass_mailing/views/snippets_themes.xml @@ -13,7 +13,9 @@ - + @@ -532,5 +534,9 @@ data-img="/mass_mailing/static/src/img/snippets_options/align_stretch.svg"/> + + +
+
diff --git a/addons/web_editor/static/src/scss/wysiwyg_snippets.scss b/addons/web_editor/static/src/scss/wysiwyg_snippets.scss index 3f3c521e4fb..00fe8ea2ced 100644 --- a/addons/web_editor/static/src/scss/wysiwyg_snippets.scss +++ b/addons/web_editor/static/src/scss/wysiwyg_snippets.scss @@ -1545,6 +1545,20 @@ body.editor_enable.editor_has_snippets { &.o_we_full_row > div { flex: 1 1 auto; } + + &.o_short_title we-title, .o_short_title we-title { + width: unset !important; + padding-right: 0 !important; + } + &.o_long_title we-title, .o_long_title we-title { + width: fit-content !important; + padding-right: 10px !important; + } + &.o_design_tab_title { + we-title { + font-weight: 600; + } + } } %o-we-inline {