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 @@ -