diff --git a/addons/web_editor/static/src/js/editor/snippets.options.js b/addons/web_editor/static/src/js/editor/snippets.options.js
index 1fac434bc09..5d41c04cc4c 100644
--- a/addons/web_editor/static/src/js/editor/snippets.options.js
+++ b/addons/web_editor/static/src/js/editor/snippets.options.js
@@ -6605,6 +6605,111 @@ registry.MultipleItems = SnippetOptionWidget.extend({
_removeItemCallback($target) {},
});
+registry.SelectTemplate = SnippetOptionWidget.extend({
+ custom_events: Object.assign({}, SnippetOptionWidget.prototype.custom_events, {
+ 'user_value_widget_opening': '_onWidgetOpening',
+ }),
+
+ /**
+ * @constructor
+ */
+ init() {
+ this._super(...arguments);
+ this.containerSelector = '';
+ this.selectTemplateWidgetName = '';
+ },
+ /**
+ * @constructor
+ */
+ async start() {
+ this.containerEl = this.containerSelector ? this.$target.find(this.containerSelector)[0] : this.$target[0];
+ this._templates = {};
+ return this._super(...arguments);
+ },
+
+ //--------------------------------------------------------------------------
+ // Options
+ //--------------------------------------------------------------------------
+
+ /**
+ * Changes the masonry snippet layout.
+ *
+ * @see this.selectClass for parameters
+ */
+ async selectTemplate(previewMode, widgetValue, params) {
+ await this._templatesLoading;
+
+ if (previewMode === 'reset') {
+ if (!this.beforePreviewNodes) {
+ // FIXME should not be necessary: only needed because we have a
+ // strange 'reset' sent after a non-preview
+ return;
+ }
+
+ // Empty the container and restore the original content
+ while (this.containerEl.lastChild) {
+ this.containerEl.removeChild(this.containerEl.lastChild);
+ }
+ for (const node of this.beforePreviewNodes) {
+ this.containerEl.appendChild(node);
+ }
+ this.beforePreviewNodes = null;
+ return;
+ }
+
+ if (!this.beforePreviewNodes) {
+ // We are about the apply a template on non-previewed content,
+ // save that content's nodes.
+ this.beforePreviewNodes = [...this.containerEl.childNodes];
+ }
+ // Empty the container and add the template content
+ while (this.containerEl.lastChild) {
+ this.containerEl.removeChild(this.containerEl.lastChild);
+ }
+ this.containerEl.insertAdjacentHTML('beforeend', this._templates[widgetValue]);
+
+ if (!previewMode) {
+ // The original content to keep saved has to be retrieved just
+ // before the preview (if we save it now, we might miss other items
+ // added by other options or custo).
+ this.beforePreviewNodes = null;
+ }
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * @param {OdooEvent} ev
+ */
+ _onWidgetOpening(ev) {
+ if (this._templatesLoading || ev.target.getName() !== this.selectTemplateWidgetName) {
+ return;
+ }
+ const templateParams = ev.target.getMethodsParams('selectTemplate');
+ const proms = templateParams.possibleValues.map(async xmlid => {
+ if (!xmlid) {
+ return;
+ }
+ // TODO should be better and retrieve all rendering in one RPC (but
+ // those ~10 RPC are only done once per edit mode if the option is
+ // opened, so I guess this is acceptable).
+ this._templates[xmlid] = await this._rpc({
+ model: 'ir.ui.view',
+ method: 'render_public_asset',
+ args: [`${xmlid}`, {}],
+ kwargs: {
+ context: this.options.context,
+ },
+ });
+ });
+ this._templatesLoading = Promise.all(proms);
+ },
+});
+
+
return {
SnippetOptionWidget: SnippetOptionWidget,
snippetOptionRegistry: registry,
diff --git a/addons/website/static/src/js/editor/snippets.options.js b/addons/website/static/src/js/editor/snippets.options.js
index 3605ef86bd7..8d0f8302b29 100644
--- a/addons/website/static/src/js/editor/snippets.options.js
+++ b/addons/website/static/src/js/editor/snippets.options.js
@@ -3148,6 +3148,35 @@ options.registry.WebsiteAnimate = options.Class.extend({
},
});
+/**
+ * Replaces current target with the specified template layout
+ */
+options.registry.MegaMenuLayout = options.registry.SelectTemplate.extend({
+ /**
+ * @override
+ */
+ init() {
+ this._super(...arguments);
+ this.selectTemplateWidgetName = 'mega_menu_template_opt';
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ */
+ _computeWidgetState: function (methodName, params) {
+ if (methodName === 'selectTemplate') {
+ const templateDefiningClass = this.containerEl.querySelector('section')
+ .classList.value.split(' ').filter(cl => cl.startsWith('s_mega_menu'))[0];
+ return `website.${templateDefiningClass}`;
+ }
+ return this._super(...arguments);
+ },
+});
+
return {
UrlPickerUserValueWidget: UrlPickerUserValueWidget,
FontFamilyPickerUserValueWidget: FontFamilyPickerUserValueWidget,
diff --git a/addons/website/static/src/snippets/s_masonry_block/options.js b/addons/website/static/src/snippets/s_masonry_block/options.js
index 281730e6e81..b7db7d8f9c8 100644
--- a/addons/website/static/src/snippets/s_masonry_block/options.js
+++ b/addons/website/static/src/snippets/s_masonry_block/options.js
@@ -2,98 +2,13 @@
import options from 'web_editor.snippets.options';
-options.registry.MasonryLayout = options.Class.extend({
- custom_events: Object.assign({}, options.Class.prototype.custom_events, {
- 'user_value_widget_opening': '_onWidgetOpening',
- }),
-
+options.registry.MasonryLayout = options.registry.SelectTemplate.extend({
/**
* @constructor
*/
- async start() {
- this.containerEl = this.$target.find('> .container, > .container-fluid, > .o_container_small')[0];
- this._templates = {};
- return this._super(...arguments);
- },
-
- //--------------------------------------------------------------------------
- // Options
- //--------------------------------------------------------------------------
-
- /**
- * Changes the masonry snippet layout.
- *
- * @see this.selectClass for parameters
- */
- async selectMasonryTemplate(previewMode, widgetValue, params) {
- await this._templatesLoading;
-
- if (previewMode === 'reset') {
- if (!this.beforePreviewNodes) {
- // FIXME should not be necessary: only needed because we have a
- // strange 'reset' sent after a non-preview
- return;
- }
-
- // Empty the container and restore the original content
- while (this.containerEl.lastChild) {
- this.containerEl.removeChild(this.containerEl.lastChild);
- }
- for (const node of this.beforePreviewNodes) {
- this.containerEl.appendChild(node);
- }
- this.beforePreviewNodes = null;
- return;
- }
-
- if (!this.beforePreviewNodes) {
- // We are about the apply a template on non-previewed content,
- // save that content's nodes.
- this.beforePreviewNodes = [...this.containerEl.childNodes];
- }
- // Empty the container and add the template content
- while (this.containerEl.lastChild) {
- this.containerEl.removeChild(this.containerEl.lastChild);
- }
- this.containerEl.insertAdjacentHTML('beforeend', this._templates[widgetValue]);
-
- if (!previewMode) {
- // The original content to keep saved has to be retrieved just
- // before the preview (if we save it now, we might miss other items
- // added by other options or custo).
- this.beforePreviewNodes = null;
- }
- },
-
- //--------------------------------------------------------------------------
- // Handlers
- //--------------------------------------------------------------------------
-
- /**
- * @private
- * @param {OdooEvent} ev
- */
- _onWidgetOpening(ev) {
- if (this._templatesLoading || ev.target.getName() !== 'masonry_template_opt') {
- return;
- }
- const templateParams = ev.target.getMethodsParams('selectMasonryTemplate');
- const proms = templateParams.possibleValues.map(async xmlid => {
- if (!xmlid) {
- return;
- }
- // TODO should be better and retrieve all rendering in one RPC (but
- // those ~10 RPC are only done once per edit mode if masonry snippet
- // option is opened, so I guess this is acceptable).
- this._templates[xmlid] = await this._rpc({
- model: 'ir.ui.view',
- method: 'render_public_asset',
- args: [`${xmlid}`, {}],
- kwargs: {
- context: this.options.context,
- },
- });
- });
- this._templatesLoading = Promise.all(proms);
+ init() {
+ this._super(...arguments);
+ this.containerSelector = '> .container, > .container-fluid, > .o_container_small';
+ this.selectTemplateWidgetName = 'masonry_template_opt';
},
});
diff --git a/addons/website/views/snippets/s_masonry_block.xml b/addons/website/views/snippets/s_masonry_block.xml
index 16455d90d0a..33f686d995e 100644
--- a/addons/website/views/snippets/s_masonry_block.xml
+++ b/addons/website/views/snippets/s_masonry_block.xml
@@ -258,43 +258,43 @@
data-attribute-name="masonryTemplate"
data-attribute-default-value="default">
diff --git a/addons/website/views/snippets/s_mega_menu_big_icons_subtitles.xml b/addons/website/views/snippets/s_mega_menu_big_icons_subtitles.xml
index c6a27f0d764..ed0d8cff9a7 100644
--- a/addons/website/views/snippets/s_mega_menu_big_icons_subtitles.xml
+++ b/addons/website/views/snippets/s_mega_menu_big_icons_subtitles.xml
@@ -1,7 +1,7 @@
-