diff --git a/addons/mass_mailing/__manifest__.py b/addons/mass_mailing/__manifest__.py index 48b401d0b55..640590597ed 100644 --- a/addons/mass_mailing/__manifest__.py +++ b/addons/mass_mailing/__manifest__.py @@ -97,6 +97,10 @@ 'web/static/lib/bootstrap/scss/_variables.scss', 'mass_mailing/static/src/scss/mass_mailing.ui.scss', ], + 'web_editor.assets_wysiwyg': [ + 'mass_mailing/static/src/js/snippets.editor.js', + 'mass_mailing/static/src/js/wysiwyg.js', + ], 'web.assets_common': [ 'mass_mailing/static/src/js/tours/**/*', ], diff --git a/addons/mass_mailing/static/src/js/mass_mailing_widget.js b/addons/mass_mailing/static/src/js/mass_mailing_widget.js index 601deb4411b..8c6c4f378d0 100644 --- a/addons/mass_mailing/static/src/js/mass_mailing_widget.js +++ b/addons/mass_mailing/static/src/js/mass_mailing_widget.js @@ -72,7 +72,10 @@ var MassMailingFieldHtml = FieldHtml.extend({ self._isDirty = self.wysiwyg.isDirty(); self._doAction(); + const $editorEnable = $editable.closest('.editor_enable'); + $editorEnable.removeClass('editor_enable'); convertInline.toInline($editable, self.cssRules, self.wysiwyg.$iframe); + $editorEnable.addClass('editor_enable'); self.trigger_up('field_changed', { dataPointID: self.dataPointID, @@ -105,6 +108,18 @@ var MassMailingFieldHtml = FieldHtml.extend({ // Private //-------------------------------------------------------------------------- + /** + * Adds automatic editor messages on drag&drop zone elements. + * + * @private + */ + _addEditorMessages: function () { + const $editable = this.wysiwyg.getEditable().find('.o_editable'); + this.$editorMessageElements = $editable + .not('[data-editor-message]') + .attr('data-editor-message', _t('DRAG BUILDING BLOCKS HERE')); + $editable.filter(':empty').attr('contenteditable', false); + }, /** * @override */ @@ -304,7 +319,9 @@ var MassMailingFieldHtml = FieldHtml.extend({ const options = this._super.apply(this, arguments); options.resizable = false; options.defaultDataForLinkTools = { isNewWindow: true }; - if (!this._wysiwygSnippetsActive) { + if (this._wysiwygSnippetsActive) { + options.wysiwygAlias = 'mass_mailing.wysiwyg'; + } else { delete options.snippets; } return options; @@ -508,6 +525,7 @@ var MassMailingFieldHtml = FieldHtml.extend({ } selectTheme(e); + this._addEditorMessages(); // Wait the next tick because some mutation have to be processed by // the Odoo editor before resetting the history. setTimeout(() => { diff --git a/addons/mass_mailing/static/src/js/snippets.editor.js b/addons/mass_mailing/static/src/js/snippets.editor.js new file mode 100644 index 00000000000..9bf8b202fac --- /dev/null +++ b/addons/mass_mailing/static/src/js/snippets.editor.js @@ -0,0 +1,95 @@ +odoo.define('mass_mailing.snippets.editor', function (require) { +'use strict'; + +const snippetsEditor = require('web_editor.snippet.editor'); + +const MassMailingSnippetsMenu = snippetsEditor.SnippetsMenu.extend({ + custom_events: _.extend({}, snippetsEditor.SnippetsMenu.prototype.custom_events, { + drop_zone_over: '_onDropZoneOver', + drop_zone_out: '_onDropZoneOut', + drop_zone_start: '_onDropZoneStart', + drop_zone_stop: '_onDropZoneStop', + }), + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + /** + * @override + */ + start: function () { + return this._super(...arguments).then(() => { + this.$editable = this.options.wysiwyg.getEditable(); + }); + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @override + */ + _insertDropzone: function ($hook) { + const $hookParent = $hook.parent(); + const $dropzone = this._super(...arguments); + $dropzone.attr('data-editor-message', $hookParent.attr('data-editor-message')); + $dropzone.attr('data-editor-sub-message', $hookParent.attr('data-editor-sub-message')); + return $dropzone; + }, + + //-------------------------------------------------------------------------- + // Handler + //-------------------------------------------------------------------------- + + /** + * @override + */ + _onDropZoneOver: function () { + this.$editable.find('.o_editable').css('background-color', ''); + }, + /** + * @override + */ + _onDropZoneOut: function () { + const $oEditable = this.$editable.find('.o_editable'); + if ($oEditable.find('.oe_drop_zone.oe_insert:not(.oe_vertical):only-child').length) { + $oEditable[0].style.setProperty('background-color', 'transparent', 'important'); + } + }, + /** + * @override + */ + _onDropZoneStart: function () { + const $oEditable = this.$editable.find('.o_editable'); + if ($oEditable.find('.oe_drop_zone.oe_insert:not(.oe_vertical):only-child').length) { + $oEditable[0].style.setProperty('background-color', 'transparent', 'important'); + } + }, + /** + * @override + */ + _onDropZoneStop: function () { + const $oEditable = this.$editable.find('.o_editable'); + $oEditable.css('background-color', ''); + if (!$oEditable.find('.oe_drop_zone.oe_insert:not(.oe_vertical):only-child').length) { + $oEditable.attr('contenteditable', true); + } + }, + /** + * @override + */ + _onSnippetRemoved: function () { + this._super(...arguments); + const $oEditable = this.$editable.find('.o_editable'); + if (!$oEditable.children().length) { + $oEditable.empty(); // remove any superfluous whitespace + $oEditable.attr('contenteditable', false); + } + }, +}); + +return MassMailingSnippetsMenu; + +}); diff --git a/addons/mass_mailing/static/src/js/wysiwyg.js b/addons/mass_mailing/static/src/js/wysiwyg.js new file mode 100644 index 00000000000..fdaad692501 --- /dev/null +++ b/addons/mass_mailing/static/src/js/wysiwyg.js @@ -0,0 +1,21 @@ +odoo.define('mass_mailing.wysiwyg', function (require) { +'use strict'; + +var Wysiwyg = require('web_editor.wysiwyg'); +var MassMailingSnippetsMenu = require('mass_mailing.snippets.editor'); + +const MassMailingWysiwyg = Wysiwyg.extend({ + /** + * @override + */ + _createSnippetsMenuInstance: function (options={}) { + return new MassMailingSnippetsMenu(this, Object.assign({ + wysiwyg: this, + selectorEditableArea: '.o_editable', + }, options)); + }, +}); + +return MassMailingWysiwyg; + +}); diff --git a/addons/mass_mailing/static/src/scss/mass_mailing.ui.scss b/addons/mass_mailing/static/src/scss/mass_mailing.ui.scss index 941a8b6d203..6de84747277 100644 --- a/addons/mass_mailing/static/src/scss/mass_mailing.ui.scss +++ b/addons/mass_mailing/static/src/scss/mass_mailing.ui.scss @@ -273,6 +273,29 @@ body.editor_enable.o_basic_theme.o_in_iframe { font-size: 14px; } +.editor_enable .o_mass_mailing_iframe { + .o_editable:empty, .o_editable > .oe_drop_zone.oe_insert:not(.oe_vertical):only-child { + background-color: white; + border: 2px dashed #999999; + padding: 112px 0px; + text-align: center !important; + color: #999999; + margin: 5px; + height: auto; + + &:before { + content: attr(data-editor-message); + display: block; + font-size: 20px; + line-height: 50px; // Useful for the "wizz" animation on snippet click to be more visible + } + &:after { + content: attr(data-editor-sub-message); + display: block; + } + } +} + .o_mass_mailing_iframe { //this will display the email body without padding @@ -284,5 +307,4 @@ body.editor_enable.o_basic_theme.o_in_iframe { .iframe-editor-wrapper { margin-top: -2px; } - } diff --git a/addons/web_editor/static/src/js/editor/snippets.editor.js b/addons/web_editor/static/src/js/editor/snippets.editor.js index 029e833061b..c30d4ab0f5a 100644 --- a/addons/web_editor/static/src/js/editor/snippets.editor.js +++ b/addons/web_editor/static/src/js/editor/snippets.editor.js @@ -1317,6 +1317,7 @@ var SnippetsMenu = Widget.extend({ if ($oeStructure.length && !$oeStructure.children().length && this.$snippets) { // If empty oe_structure, encourage using snippets in there by // making them "wizz" in the panel. + this._updateRightPanelContent({content: [], tab: this.tabs.BLOCKS}); this.$snippets.odooBounce(); return; } @@ -2474,6 +2475,7 @@ var SnippetsMenu = Widget.extend({ dropped = true; $(this).first().after($toInsert).addClass('invisible'); $toInsert.removeClass('oe_snippet_body'); + self.trigger_up('drop_zone_over'); }, out: function () { var prev = $toInsert.prev(); @@ -2483,6 +2485,7 @@ var SnippetsMenu = Widget.extend({ $(this).removeClass('invisible'); $toInsert.addClass('oe_snippet_body'); } + self.trigger_up('drop_zone_out'); }, }); @@ -2497,6 +2500,7 @@ var SnippetsMenu = Widget.extend({ self.draggableComponent.$scrollTarget.on('scroll.scrolling_element', function () { self.$el.trigger('scroll'); }); + self.trigger_up('drop_zone_start'); }, stop: async function (ev, ui) { const doc = self.options.wysiwyg.odooEditor.document; @@ -2577,6 +2581,7 @@ var SnippetsMenu = Widget.extend({ } self.$el.find('.oe_snippet_thumbnail').removeClass('o_we_already_dragging'); } + self.trigger_up('drop_zone_stop'); }, }, }); diff --git a/addons/web_editor/static/src/js/frontend/loader.js b/addons/web_editor/static/src/js/frontend/loader.js index 43b745e6c4d..0434715ddd9 100644 --- a/addons/web_editor/static/src/js/frontend/loader.js +++ b/addons/web_editor/static/src/js/frontend/loader.js @@ -19,14 +19,15 @@ exports.loadWysiwyg = loadWysiwyg; * @param {object} options The wysiwyg options */ exports.createWysiwyg = async (parent, options, additionnalAssets = []) => { + const wysiwygAlias = options.wysiwygAlias || 'web_editor.wysiwyg'; if (!wysiwygPromise) { wysiwygPromise = new Promise(async (resolve) => { await loadWysiwyg(additionnalAssets); // Wait the loading of the service and his dependencies (use string to // avoid parsing of require function). const stringFunction = `return new Promise(resolve => { - odoo.define('web_editor.wysiwig.loaded', require => { - ` + 'require' + `('web_editor.wysiwyg'); + odoo.define('${wysiwygAlias}.loaded', require => { + ` + 'require' + `('${wysiwygAlias}'); resolve(); }); });`; @@ -35,7 +36,7 @@ exports.createWysiwyg = async (parent, options, additionnalAssets = []) => { }); } await wysiwygPromise; - const Wysiwyg = odoo.__DEBUG__.services['web_editor.wysiwyg']; + const Wysiwyg = odoo.__DEBUG__.services[wysiwygAlias]; return new Wysiwyg(parent, options); }; diff --git a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js index 56dcc5f4ca8..99492df6aff 100644 --- a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js +++ b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js @@ -216,10 +216,7 @@ const Wysiwyg = Widget.extend({ if (options.snippets) { $(this.odooEditor.document.body).addClass('editor_enable'); - this.snippetsMenu = new snippetsEditor.SnippetsMenu(this, Object.assign({ - wysiwyg: this, - selectorEditableArea: '.o_editable', - }, options)); + this.snippetsMenu = this._createSnippetsMenuInstance(options); await this._insertSnippetMenu(); this._onBeforeUnload = (event) => { @@ -1055,6 +1052,18 @@ const Wysiwyg = Widget.extend({ // Private //-------------------------------------------------------------------------- + /** + * Returns an instance of the snippets menu. + * + * @param {Object} [options] + * @returns {widget} + */ + _createSnippetsMenuInstance: function (options={}) { + return new snippetsEditor.SnippetsMenu(this, Object.assign({ + wysiwyg: this, + selectorEditableArea: '.o_editable', + }, options)); + }, _configureToolbar: function (options) { const $toolbar = this.toolbar.$el; $toolbar.on('mousedown', e => e.preventDefault());