From dc140ef1159b104d6c01abffbdd9048eab96e153 Mon Sep 17 00:00:00 2001 From: qsm-odoo Date: Wed, 30 Nov 2022 18:08:44 +0000 Subject: [PATCH] [FIX] web_editor, website: add cover/contain option for grid images As a fix, this introduces a new option for images in grid mode. When an image is alone in a column which later becomes a grid item, or when an image is directly added as a grid item via the dedicated option, the image used `object-fit: cover` so that when the image is resized as a grid item, it fits the dimensions of the selected grid area. This confused some users as the image did not appear the same depending on the screen size. Indeed, if an image is set to take 5 columns as width and 3 rows as height, it does not ensure the ratio in pixels to stay the same depending on the screen size: the grid is always made of 12 columns (so the width of each column depends on the screen width), while the rows are always 50px tall. We could enforce the ratio of grid items to stay the same or limit the ratio loss by reducing the 50px height on smaller breakpoints but that would actually increase another problem: for colored text grid items, their text would more easily overflow their fixed area. In the end, using the grid mode is about compromises, even if it allows to achieve nice things and to have more freedom. This commit although adds a new option to mitigate the issue for images: users now have the possibility to switch the default "cover" mode of grid images to "contain": in that mode, the whole image will always be visible (and thus keeps the same ratio) and is just "contained" in the grid area which is selected as dimension. opw-3069234 closes odoo/odoo#107172 X-original-commit: faf19ef7f87fc043fb9a814516e01b8eeafd9b61 Signed-off-by: Quentin Smetz (qsm) --- .../static/src/js/editor/snippets.editor.js | 14 ++++- .../static/src/js/editor/snippets.options.js | 2 +- .../static/src/scss/web_editor.frontend.scss | 15 +++-- .../static/src/js/editor/snippets.options.js | 55 +++++++++++++++++++ addons/website/views/snippets/snippets.xml | 8 +++ 5 files changed, 87 insertions(+), 7 deletions(-) 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 5712d450473..f23d9981890 100644 --- a/addons/web_editor/static/src/js/editor/snippets.editor.js +++ b/addons/web_editor/static/src/js/editor/snippets.editor.js @@ -1302,7 +1302,7 @@ var SnippetEditor = Widget.extend({ gridUtils._resizeGrid(rowEl); } else if (this.$target[0].classList.contains('o_grid_item') && this.dropped) { // Case when dropping a grid item in a non-grid dropzone. - this.$target[0].classList.remove('o_grid_item', 'o_grid_item_image'); + this.$target[0].classList.remove('o_grid_item', 'o_grid_item_image', 'o_grid_item_image_contain'); this.$target[0].style.removeProperty('grid-area'); } @@ -1342,7 +1342,7 @@ var SnippetEditor = Widget.extend({ if (this.$target[0].classList.contains('o_grid_item')) { // Case when a grid column is dropped near a non-grid // dropzone. - this.$target[0].classList.remove('o_grid_item', 'o_grid_item_image'); + this.$target[0].classList.remove('o_grid_item', 'o_grid_item_image', 'o_grid_item_image_contain'); this.$target[0].style.removeProperty('z-index'); this.$target[0].style.removeProperty('grid-area'); } @@ -2656,6 +2656,7 @@ var SnippetsMenu = Widget.extend({ _computeSnippetTemplates: function (html) { var self = this; var $html = $(html); + this._patchForComputeSnippetTemplates($html); var $scroll = $html.siblings('#o_scroll'); this.templateOptions = []; @@ -2800,6 +2801,15 @@ var SnippetsMenu = Widget.extend({ this.$el.addClass('o_loaded'); $(this.el.ownerDocument.body).addClass('editor_has_snippets'); }, + /** + * Eases patching the XML definition for snippets and options in stable + * versions. Note: in the future, we will probably move to other ways to + * define snippets and options. + * + * @private + * @param {jQuery} + */ + _patchForComputeSnippetTemplates($html) {}, /** * Creates a snippet editor to associated to the given snippet. If the given * snippet already has a linked snippet editor, the function only returns 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 8182b942662..e5adc663f4d 100644 --- a/addons/web_editor/static/src/js/editor/snippets.options.js +++ b/addons/web_editor/static/src/js/editor/snippets.options.js @@ -5143,7 +5143,7 @@ registry.layout_column = SnippetOptionWidget.extend({ gridUtils._reloadLazyImages(columnEl); // Removing the grid properties. - columnEl.classList.remove('o_grid_item', 'o_grid_item_image'); + columnEl.classList.remove('o_grid_item', 'o_grid_item_image', 'o_grid_item_image_contain'); columnEl.style.removeProperty('grid-area'); columnEl.style.removeProperty('z-index'); } diff --git a/addons/web_editor/static/src/scss/web_editor.frontend.scss b/addons/web_editor/static/src/scss/web_editor.frontend.scss index 5b6d081b2e5..d949eae7ea9 100644 --- a/addons/web_editor/static/src/scss/web_editor.frontend.scss +++ b/addons/web_editor/static/src/scss/web_editor.frontend.scss @@ -57,8 +57,15 @@ --gutter-x: 30px; } -.o_grid_item_image > img:not([data-shape]) { - width: 100% !important; - height: 100% !important; - object-fit: cover !important; +.o_grid_item_image { + > img { + width: 100% !important; + height: 100% !important; + object-fit: cover !important; + } + + &.o_grid_item_image_contain > img, + > img[data-shape] { + object-fit: contain !important; + } } diff --git a/addons/website/static/src/js/editor/snippets.options.js b/addons/website/static/src/js/editor/snippets.options.js index 36d40a6a05a..daba07839f5 100644 --- a/addons/website/static/src/js/editor/snippets.options.js +++ b/addons/website/static/src/js/editor/snippets.options.js @@ -3612,6 +3612,61 @@ options.registry.SwitchableViews = options.Class.extend({ } }); +options.registry.GridImage = options.Class.extend({ + + //-------------------------------------------------------------------------- + // Options + //-------------------------------------------------------------------------- + + /** + * @see this.selectClass for parameters + */ + changeGridImageMode(previewMode, widgetValue, params) { + const imageGridItemEl = this._getImageGridItem(); + if (imageGridItemEl) { + imageGridItemEl.classList.toggle('o_grid_item_image_contain', widgetValue === 'contain'); + } + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * Returns the parent column if it is marked as a grid item containing an + * image. + * + * @returns {?HTMLElement} + */ + _getImageGridItem() { + const parentEl = this.$target[0].parentNode; + if (parentEl && parentEl.classList.contains('o_grid_item_image')) { + return parentEl; + } + return null; + }, + /** + * @override + */ + _computeVisibility() { + return this._super(...arguments) + && !!this._getImageGridItem() + && !('shape' in this.$target[0].dataset); + }, + /** + * @override + */ + _computeWidgetState(methodName, params) { + if (methodName === 'changeGridImageMode') { + const imageGridItemEl = this._getImageGridItem(); + return imageGridItemEl && imageGridItemEl.classList.contains('o_grid_item_image_contain') + ? 'contain' + : 'cover'; + } + return this._super(...arguments); + }, +}); + return { UrlPickerUserValueWidget: UrlPickerUserValueWidget, FontFamilyPickerUserValueWidget: FontFamilyPickerUserValueWidget, diff --git a/addons/website/views/snippets/snippets.xml b/addons/website/views/snippets/snippets.xml index 693386c8ed2..0cb13b047de 100644 --- a/addons/website/views/snippets/snippets.xml +++ b/addons/website/views/snippets/snippets.xml @@ -1346,6 +1346,14 @@ + +
+ + Cover + Contain + +
+