diff --git a/addons/web_editor/static/src/js/common/utils.js b/addons/web_editor/static/src/js/common/utils.js index 16fa0e08db0..3e227f08dd1 100644 --- a/addons/web_editor/static/src/js/common/utils.js +++ b/addons/web_editor/static/src/js/common/utils.js @@ -1,5 +1,6 @@ /** @odoo-module **/ +import {SIZES, MEDIAS_BREAKPOINTS} from "@web/core/ui/ui_service"; import { normalizeCSSColor, isCSSColor, @@ -462,6 +463,18 @@ function _shouldEditableMediaBeEditable(mediaEl) { && nonEditableAncestorRootEl.parentElement && nonEditableAncestorRootEl.parentElement.isContentEditable; } +/** + * Checks if the view of the targeted element is mobile. + * + * @param {HTMLElement} targetEl - target of the editor + * @returns {boolean} + */ +function _isMobileView(targetEl) { + const mobileViewThreshold = MEDIAS_BREAKPOINTS[SIZES.LG].minWidth; + const clientWidth = targetEl.ownerDocument.defaultView?.frameElement?.clientWidth || + targetEl.ownerDocument.documentElement.clientWidth; + return clientWidth && clientWidth < mobileViewThreshold; +} export default { COLOR_PALETTE_COMPATIBILITY_COLOR_NAMES: COLOR_PALETTE_COMPATIBILITY_COLOR_NAMES, @@ -488,4 +501,5 @@ export default { addBackgroundImageAttributes: _addBackgroundImageAttributes, isBackgroundImageAttribute: _isBackgroundImageAttribute, shouldEditableMediaBeEditable: _shouldEditableMediaBeEditable, + isMobileView: _isMobileView, }; 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 84b2d6f1f23..7b09fe3184e 100644 --- a/addons/web_editor/static/src/js/editor/snippets.editor.js +++ b/addons/web_editor/static/src/js/editor/snippets.editor.js @@ -2513,7 +2513,7 @@ var SnippetsMenu = Widget.extend({ this.invisibleDOMMap = new Map(); const $invisibleDOMPanelEl = $(this.invisibleDOMPanelEl); $invisibleDOMPanelEl.find('.o_we_invisible_entry').remove(); - const isMobile = this.options.wysiwyg.websiteService?.context.isMobile; + const isMobile = this._isMobile(); const invisibleSelector = `.o_snippet_invisible, ${isMobile ? '.o_snippet_mobile_invisible' : '.o_snippet_desktop_invisible'}`; const $selector = this.options.enableTranslation ? this.$body : globalSelector.all(); let $invisibleSnippets = $selector.find(invisibleSelector).addBack(invisibleSelector); @@ -3680,6 +3680,14 @@ var SnippetsMenu = Widget.extend({ Tooltip.getInstance(el)?.hide(); } }, + /** + * Returns whether the edited content is a mobile view content. + * + * @returns {boolean} + */ + _isMobile() { + return weUtils.isMobileView(this.$body[0]); + }, //-------------------------------------------------------------------------- // Handlers 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 6a861b1c294..0c71c8411b1 100644 --- a/addons/web_editor/static/src/js/editor/snippets.options.js +++ b/addons/web_editor/static/src/js/editor/snippets.options.js @@ -31,7 +31,6 @@ import { getDataURLBinarySize, } from "@web_editor/js/editor/image_processing"; import * as OdooEditorLib from "@web_editor/js/editor/odoo-editor/src/OdooEditor"; -import {SIZES, MEDIAS_BREAKPOINTS} from "@web/core/ui/ui_service"; import { pick } from "@web/core/utils/objects"; import { _t } from "@web/core/l10n/translation"; import { @@ -4013,8 +4012,7 @@ const SnippetOptionWidget = Widget.extend({ if (moveUpOrLeft || moveDownOrRight) { // The arrows are not displayed if the target is in a grid and if // not in mobile view. - const mobileViewThreshold = MEDIAS_BREAKPOINTS[SIZES.LG].minWidth; - const isMobileView = this.$target[0].ownerDocument.defaultView.frameElement.clientWidth < mobileViewThreshold; + const isMobileView = weUtils.isMobileView(this.$target[0]); if (this.$target[0].classList.contains('o_grid_item') && !isMobileView) { return false; } @@ -4683,8 +4681,7 @@ registry.sizing = SnippetOptionWidget.extend({ async updateUIVisibility() { await this._super(...arguments); - const mobileViewThreshold = MEDIAS_BREAKPOINTS[SIZES.LG].minWidth; - const isMobileView = this.$target[0].ownerDocument.defaultView.frameElement.clientWidth < mobileViewThreshold; + const isMobileView = weUtils.isMobileView(this.$target[0]); const isGrid = this.$target[0].classList.contains('o_grid_item'); if (this.$target[0].parentNode && this.$target[0].parentNode.classList.contains('row')) { // Hiding/showing the correct resize handles if we are in grid mode @@ -5280,8 +5277,7 @@ registry.layout_column = SnippetOptionWidget.extend({ await this._super(previewMode, widgetValue, params); const rowEl = this.$target[0]; - const mobileViewThreshold = MEDIAS_BREAKPOINTS[SIZES.LG].minWidth; - const isMobileView = rowEl.ownerDocument.defaultView.frameElement.clientWidth < mobileViewThreshold; + const isMobileView = weUtils.isMobileView(rowEl); if (["row-gap", "column-gap"].includes(params.cssProperty) && !isMobileView) { // Reset the animation. this._removeGridPreview(); @@ -8025,10 +8021,7 @@ registry.BackgroundShape = SnippetOptionWidget.extend({ shapeToSelect = possibleShapes[1]; } // Only show on mobile by default if toggled from mobile view - const mobileViewThreshold = MEDIAS_BREAKPOINTS[SIZES.LG].minWidth; - const isMobileView = this.$target[0].ownerDocument - .defaultView.frameElement.clientWidth < mobileViewThreshold; - const showOnMobile = isMobileView; + const showOnMobile = weUtils.isMobileView(this.$target[0]); this.trigger_up('snippet_edition_request', {exec: () => { // options for shape will only be available after _toggleShape() returned this._requestUserValueWidgets('bg_shape_opt')[0].enable(); diff --git a/addons/website/static/src/js/editor/snippets.editor.js b/addons/website/static/src/js/editor/snippets.editor.js index b2b1a2c8a98..fe3877fa7d0 100644 --- a/addons/website/static/src/js/editor/snippets.editor.js +++ b/addons/website/static/src/js/editor/snippets.editor.js @@ -4,6 +4,7 @@ import { _t } from "@web/core/l10n/translation"; import Dialog from "@web/legacy/js/core/dialog"; import weSnippetEditor from "@web_editor/js/editor/snippets.editor"; import wSnippetOptions from "@website/js/editor/snippets.options"; +import wUtils from "@website/js/utils"; import * as OdooEditorLib from "@web_editor/js/editor/odoo-editor/src/utils/utils"; import { renderToElement } from "@web/core/utils/render"; const getDeepRange = OdooEditorLib.getDeepRange; @@ -302,6 +303,12 @@ const wSnippetMenu = weSnippetEditor.SnippetsMenu.extend({ _isValidSelection(sel) { return sel.rangeCount && [...this.getEditableArea()].some(el => el.contains(sel.anchorNode)); }, + /** + * @override + */ + _isMobile() { + return wUtils.isMobile(this); + }, //-------------------------------------------------------------------------- // Handlers diff --git a/addons/website/static/src/js/editor/snippets.options.js b/addons/website/static/src/js/editor/snippets.options.js index 95a8ec3aa0b..b8c9dfedc8e 100644 --- a/addons/website/static/src/js/editor/snippets.options.js +++ b/addons/website/static/src/js/editor/snippets.options.js @@ -2583,12 +2583,7 @@ options.registry.DeviceVisibility = options.Class.extend({ } // Update invisible elements. - let isMobile; - this.trigger_up('service_context_get', { - callback: (ctx) => { - isMobile = ctx['isMobile']; - }, - }); + const isMobile = wUtils.isMobile(this); this.trigger_up('snippet_option_visibility_update', {show: widgetValue !== (isMobile ? 'no_mobile' : 'no_desktop')}); }, /** diff --git a/addons/website/static/src/js/utils.js b/addons/website/static/src/js/utils.js index d9b9d9b9a62..d18ffdfd01b 100644 --- a/addons/website/static/src/js/utils.js +++ b/addons/website/static/src/js/utils.js @@ -416,6 +416,23 @@ export function generateGMapLink(dataset) { + '&ie=UTF8&iwloc=&output=embed'; } +/** + * Checks if the edited content is currently previewed as in a mobile device. + * + * @param {Object} self - context object ("this") + * @returns {boolean} + */ +function isMobile(self) { + let isMobile; + self.trigger_up("service_context_get", { + callback: (ctx) => { + isMobile = ctx["isMobile"]; + }, + }); + + return isMobile; +} + export default { loadAnchors: loadAnchors, autocompleteWithPages: autocompleteWithPages, @@ -427,4 +444,5 @@ export default { svgToPNG: svgToPNG, generateGMapIframe: generateGMapIframe, generateGMapLink: generateGMapLink, + isMobile: isMobile, }; diff --git a/addons/website/static/src/snippets/s_process_steps/options.js b/addons/website/static/src/snippets/s_process_steps/options.js index 0922d24aad3..4f2f6e91fdd 100644 --- a/addons/website/static/src/snippets/s_process_steps/options.js +++ b/addons/website/static/src/snippets/s_process_steps/options.js @@ -2,7 +2,6 @@ import options from '@web_editor/js/editor/snippets.options'; import weUtils from '@web_editor/js/common/utils'; -import {SIZES, MEDIAS_BREAKPOINTS} from '@web/core/ui/ui_service'; options.registry.StepsConnector = options.Class.extend({ /** @@ -80,9 +79,7 @@ options.registry.StepsConnector = options.Class.extend({ // We don't use the service_context_get intentionally because the // connectors are hidden as soon as the page is smaller than 992px // (the BS lg breakpoint). - const mobileViewThreshold = MEDIAS_BREAKPOINTS[SIZES.LG].minWidth; - const isMobileView = this.$target[0].ownerDocument.documentElement.clientWidth < - mobileViewThreshold; + const isMobileView = weUtils.isMobileView(this.$target[0]); return !isMobileView && this._super(...arguments); }, /**