From 1139ad7affc5dfdd7de416fd364cbb3112523c89 Mon Sep 17 00:00:00 2001 From: Benoit Socias Date: Thu, 4 Aug 2022 11:14:21 +0000 Subject: [PATCH] [IMP] web_editor, website, website_sale: hide block in desktop display Since [1] it is possible to request that some blocks are not displayed on mobile devices. This commit adds a similar option to prevent blocks from being displayed on desktops (i.e. on non-mobile devices). [1]: https://github.com/odoo/odoo/commit/9463f0f889f9dd8da6077895c125da4998a933c0 task-2900730 closes odoo/odoo#101483 X-original-commit: 3103e0553011b5c1f4078972d7a88fa3fd4068b2 Signed-off-by: Quentin Smetz (qsm) Co-authored-by: Antoine (anso) --- .../static/src/js/editor/snippets.editor.js | 19 ++++- .../wysiwyg_adapter/wysiwyg_adapter.js | 12 +++ .../snippets_options/desktop_invisible.svg | 5 ++ .../img/snippets_options/desktop_visible.svg | 3 + .../static/src/js/editor/snippets.options.js | 85 +++++++++++++------ .../static/src/scss/website.wysiwyg.scss | 42 +++++++-- .../src/snippets/s_website_form/options.js | 4 +- addons/website/views/snippets/snippets.xml | 23 +++-- .../static/src/js/website_sale.editor.js | 4 +- 9 files changed, 149 insertions(+), 48 deletions(-) create mode 100644 addons/website/static/src/img/snippets_options/desktop_invisible.svg create mode 100644 addons/website/static/src/img/snippets_options/desktop_visible.svg 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 d78b0b5ff0b..b755bc9b014 100644 --- a/addons/web_editor/static/src/js/editor/snippets.editor.js +++ b/addons/web_editor/static/src/js/editor/snippets.editor.js @@ -313,7 +313,9 @@ var SnippetEditor = Widget.extend({ if (this.isDestroyed()) { return; } - await this.toggleTargetVisibility(!this.$target.hasClass('o_snippet_invisible')); + await this.toggleTargetVisibility(!this.$target.hasClass('o_snippet_invisible') + && !this.$target.hasClass('o_snippet_mobile_invisible') + && !this.$target.hasClass('o_snippet_desktop_invisible')); const proms = _.map(this.styles, option => { return option.cleanForSave(); }); @@ -2162,7 +2164,14 @@ var SnippetsMenu = Widget.extend({ this.invisibleDOMMap = new Map(); const $invisibleDOMPanelEl = $(this.invisibleDOMPanelEl); $invisibleDOMPanelEl.find('.o_we_invisible_entry').remove(); - const $invisibleSnippets = globalSelector.all().find('.o_snippet_invisible').addBack('.o_snippet_invisible'); + let isMobile; + this.trigger_up('service_context_get', { + callback: (ctx) => { + isMobile = ctx['isMobile']; + }, + }); + const invisibleSelector = `.o_snippet_invisible, ${isMobile ? '.o_snippet_mobile_invisible' : '.o_snippet_desktop_invisible'}`; + const $invisibleSnippets = globalSelector.all().find(invisibleSelector).addBack(invisibleSelector); $invisibleDOMPanelEl.toggleClass('d-none', !$invisibleSnippets.length); @@ -3875,6 +3884,12 @@ var SnippetsMenu = Widget.extend({ for (const gridItemEl of gridItemEls) { gridUtils._reloadLazyImages(gridItemEl); } + for (const invisibleOverrideEl of this.getEditableArea().find('.o_snippet_mobile_invisible, .o_snippet_desktop_invisible')) { + invisibleOverrideEl.classList.remove('o_snippet_override_invisible'); + invisibleOverrideEl.dataset.invisible = '1'; + } + // This is async but using the main editor mutex. + this._updateInvisibleDOM(); }, /** * Undo.. diff --git a/addons/website/static/src/components/wysiwyg_adapter/wysiwyg_adapter.js b/addons/website/static/src/components/wysiwyg_adapter/wysiwyg_adapter.js index c9714bb94d3..0accc487c96 100644 --- a/addons/website/static/src/components/wysiwyg_adapter/wysiwyg_adapter.js +++ b/addons/website/static/src/components/wysiwyg_adapter/wysiwyg_adapter.js @@ -674,6 +674,17 @@ export class WysiwygAdapterComponent extends ComponentAdapter { _onContextGet(event) { return event.data.callback(this._context); } + /** + * Retrieves the website service context. + * + * @private + * @param {OdooEvent} ev + */ + _onServiceContextGet(ev) { + ev.data.callback({ + isMobile: this.websiteService.context.isMobile, + }); + } /** * Discards changes and reload the iframe. * @@ -841,6 +852,7 @@ WysiwygAdapterComponent.prototype.events = { 'gmap_api_key_request': '_onRootEventRequest', 'request_save': '_onSaveRequest', 'context_get': '_onContextGet', + 'service_context_get': '_onServiceContextGet', 'action_demand': '_handleAction', 'request_cancel': '_onCancelRequest', 'snippet_will_be_cloned': '_onSnippetWillBeCloned', diff --git a/addons/website/static/src/img/snippets_options/desktop_invisible.svg b/addons/website/static/src/img/snippets_options/desktop_invisible.svg new file mode 100644 index 00000000000..f4c01ab7666 --- /dev/null +++ b/addons/website/static/src/img/snippets_options/desktop_invisible.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/addons/website/static/src/img/snippets_options/desktop_visible.svg b/addons/website/static/src/img/snippets_options/desktop_visible.svg new file mode 100644 index 00000000000..3875c52e124 --- /dev/null +++ b/addons/website/static/src/img/snippets_options/desktop_visible.svg @@ -0,0 +1,3 @@ + + + diff --git a/addons/website/static/src/js/editor/snippets.options.js b/addons/website/static/src/js/editor/snippets.options.js index a023efe85e8..2c21bee43fe 100644 --- a/addons/website/static/src/js/editor/snippets.options.js +++ b/addons/website/static/src/js/editor/snippets.options.js @@ -2294,36 +2294,61 @@ options.registry.topMenuColor = options.Class.extend({ }); /** - * Manage the visibility of snippets on mobile. + * Manage the visibility of snippets on mobile/desktop. */ -options.registry.MobileVisibility = options.Class.extend({ - isTopOption: true, - - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- - - /** - * @override - */ - async updateUI() { - await this._super(...arguments); - const $button = this.$el.find('we-button'); - $button.attr('title', $button.hasClass('active') ? _t("Visible on mobile") : _t("Hidden on mobile")); - }, +options.registry.DeviceVisibility = options.Class.extend({ //-------------------------------------------------------------------------- // Options //-------------------------------------------------------------------------- /** - * Allows to show or hide the associated snippet in mobile display mode. + * Toggles the device visibility. * * @see this.selectClass for parameters */ - showOnMobile(previewMode, widgetValue, params) { - const classes = `d-none d-md-${this.$target.css('display')}`; - this.$target.toggleClass(classes, !widgetValue); + async toggleDeviceVisibility(previewMode, widgetValue, params) { + this.$target[0].classList.remove('d-none', 'd-md-none', + 'o_snippet_mobile_invisible', 'o_snippet_desktop_invisible', + 'o_snippet_override_invisible', + ); + const style = getComputedStyle(this.$target[0]); + this.$target[0].classList.remove(`d-md-${style['display']}`); + if (widgetValue === 'no_desktop') { + this.$target[0].classList.add('d-md-none', 'o_snippet_desktop_invisible'); + } else if (widgetValue === 'no_mobile') { + this.$target[0].classList.add(`d-md-${style['display']}`, 'd-none', 'o_snippet_mobile_invisible'); + } + + // Update invisible elements. + let isMobile; + this.trigger_up('service_context_get', { + callback: (ctx) => { + isMobile = ctx['isMobile']; + }, + }); + this.trigger_up('snippet_option_visibility_update', {show: widgetValue !== (isMobile ? 'no_mobile' : 'no_desktop')}); + }, + /** + * @override + */ + async onTargetHide() { + this.$target[0].classList.remove('o_snippet_override_invisible'); + }, + /** + * @override + */ + async onTargetShow() { + if (this.$target[0].classList.contains('o_snippet_mobile_invisible') + || this.$target[0].classList.contains('o_snippet_desktop_invisible')) { + this.$target[0].classList.add('o_snippet_override_invisible'); + } + }, + /** + * @override + */ + cleanForSave() { + this.$target[0].classList.remove('o_snippet_override_invisible'); }, //-------------------------------------------------------------------------- @@ -2334,10 +2359,16 @@ options.registry.MobileVisibility = options.Class.extend({ * @override */ async _computeWidgetState(methodName, params) { - if (methodName === 'showOnMobile') { + if (methodName === 'toggleDeviceVisibility') { const classList = [...this.$target[0].classList]; - return classList.includes('d-none') && - classList.some(className => className.startsWith('d-md-')) ? '' : 'true'; + if (classList.includes('d-none') && + classList.some(className => className.startsWith('d-md-'))) { + return 'no_mobile'; + } + if (classList.includes('d-md-none')) { + return 'no_desktop'; + } + return ''; } return await this._super(...arguments); }, @@ -2874,7 +2905,9 @@ options.registry.ConditionalVisibility = options.Class.extend({ * @override */ async onTargetHide() { - this.$target[0].classList.add('o_conditional_hidden'); + if (this.$target[0].classList.contains('o_snippet_invisible')) { + this.$target[0].classList.add('o_conditional_hidden'); + } }, /** * @override @@ -2891,7 +2924,9 @@ options.registry.ConditionalVisibility = options.Class.extend({ // snippet will be shown naturally (as the CSS rules won't apply). // Without this, the "eye" icon of the visibility panel would be shut // when entering edit mode. - this.trigger_up('snippet_option_visibility_update', { show: true }); + if (this.$target[0].classList.contains('o_snippet_invisible')) { + this.trigger_up('snippet_option_visibility_update', { show: true }); + } }, //-------------------------------------------------------------------------- diff --git a/addons/website/static/src/scss/website.wysiwyg.scss b/addons/website/static/src/scss/website.wysiwyg.scss index afa96c78faa..fa2c3c2e13c 100644 --- a/addons/website/static/src/scss/website.wysiwyg.scss +++ b/addons/website/static/src/scss/website.wysiwyg.scss @@ -33,6 +33,32 @@ html[data-edit_translations="1"] { } } +.o_snippet_override_invisible { + display: block !important; + opacity: 70%; + position: relative; + + &::before { + position: absolute; + // Content is 0px wide => use available width. + width: -webkit-fill-available; + width: -moz-available; + right: 20px; + z-index: 100; + background-color: $o-we-accent; + font-size: 0px; + content: "."; // Content is mandatory. + } + &.d-md-none::before { + height: 50px; + -webkit-mask: url("/website/static/src/img/snippets_options/desktop_invisible.svg") no-repeat 100% 100%; + } + &:not(.d-md-none)::before { + height: 30px; + -webkit-mask: url("/website/static/src/img/snippets_options/mobile_invisible.svg") no-repeat 100% 100%; + } +} + // SNIPPET PANEL $i: 1; @each $font-name, $font-config in $o-theme-font-configs { @@ -89,7 +115,7 @@ $i: 1; } } - we-button.o_we_mobile { + we-button.o_we_device { > div { // FIXME maybe there is some refactoring to do so that all SVG icons // can be properly aligned with extra CSS rules... @@ -97,21 +123,19 @@ $i: 1; align-items: center; svg { - width: 15px; - fill: $o-we-color-danger; + width: 12px; + fill: $o-we-sidebar-content-field-clickable-color; margin-bottom: 0; - margin-left: -3px; &:hover { - fill: darken($o-we-color-danger, 7.5%); + fill: $o-we-sidebar-content-field-pressed-color; } } } - &.active > div > svg { - fill: $o-we-sidebar-content-field-color; - + &.active > div svg { + fill: $o-we-color-danger; &:hover { - fill: $o-we-sidebar-content-field-pressed-color; + fill: darken($o-we-color-danger, 7.5%); } } } diff --git a/addons/website/static/src/snippets/s_website_form/options.js b/addons/website/static/src/snippets/s_website_form/options.js index b4aef8c34e9..a1c91ef48f9 100644 --- a/addons/website/static/src/snippets/s_website_form/options.js +++ b/addons/website/static/src/snippets/s_website_form/options.js @@ -1503,8 +1503,8 @@ options.registry.WebsiteFormSubmitRequired = DisableOverlayButtonOption.extend({ } }); -// Disable "Shown on Mobile" option if for an hidden field -options.registry.MobileVisibility.include({ +// Disable "Shown on Mobile/Desktop" option if for an hidden field +options.registry.DeviceVisibility.include({ //-------------------------------------------------------------------------- // Private diff --git a/addons/website/views/snippets/snippets.xml b/addons/website/views/snippets/snippets.xml index 936495b1b7b..51bf8a45f4d 100644 --- a/addons/website/views/snippets/snippets.xml +++ b/addons/website/views/snippets/snippets.xml @@ -589,14 +589,6 @@ - -
- -
-
@@ -1277,6 +1269,21 @@
+ +
+ + + + +
+
diff --git a/addons/website_sale/static/src/js/website_sale.editor.js b/addons/website_sale/static/src/js/website_sale.editor.js index af92058bc55..c6d0c490da1 100644 --- a/addons/website_sale/static/src/js/website_sale.editor.js +++ b/addons/website_sale/static/src/js/website_sale.editor.js @@ -925,8 +925,8 @@ options.registry.WebsiteSaleProductAttribute = options.Class.extend({ }, }); -// Disable "Shown on Mobile" option if for dynamic product snippets -options.registry.MobileVisibility.include({ +// Disable "Shown on Mobile/Desktop" option if for dynamic product snippets +options.registry.DeviceVisibility.include({ //-------------------------------------------------------------------------- // Private