[FIX] web_editor: scroll to invisible images on crop
Steps to reproduce: - Go to a website page (in "edit" mode) > Add a "Text Image" block > Add other blocks before and after the snippet so you can scroll the page content. - Scroll in a way that makes only a part of the image visible. - Select the image and click on the "Crop" button > The crop widget is applied to the image in its current position (partially visible), which makes it impossible to crop it correctly. The goal of this commit is to prevent the issue described above by simply scrolling to a position that allows to correctly edit the image before applying the crop widget and also allowing the widget element to scroll when trying to crop an image that overflows the current viewport. task-3420186 closes odoo/odoo#155094 X-original-commit: 8ef34c15336c6938f40c15dbcc64c025b24d5808 Signed-off-by: Robin Lejeune (role) <role@odoo.com>
This commit is contained in:
@@ -12,6 +12,7 @@ import {
|
||||
markup,
|
||||
} from "@odoo/owl";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import dom from "@web/legacy/js/core/dom";
|
||||
|
||||
export class ImageCrop extends Component {
|
||||
static template = 'web_editor.ImageCrop';
|
||||
@@ -147,6 +148,7 @@ export class ImageCrop extends Component {
|
||||
}
|
||||
const $cropperWrapper = this.$('.o_we_cropper_wrapper');
|
||||
|
||||
await this._scrollToInvisibleImage();
|
||||
// Replacing the src with the original's so that the layout is correct.
|
||||
await loadImage(this.originalSrc, this.media);
|
||||
this.$cropperImage = this.$('.o_we_cropper_img');
|
||||
@@ -221,6 +223,41 @@ export class ImageCrop extends Component {
|
||||
this.$cropperImage.cropper('clear');
|
||||
this.$cropperImage.cropper('crop');
|
||||
}
|
||||
/**
|
||||
* Make sure the targeted image is in the visible viewport before crop.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
async _scrollToInvisibleImage() {
|
||||
const rect = this.media.getBoundingClientRect();
|
||||
const viewportTop = this.document.documentElement.scrollTop || 0;
|
||||
const viewportBottom = viewportTop + window.innerHeight;
|
||||
const closestScrollable = el => {
|
||||
if (!el) {
|
||||
return null;
|
||||
}
|
||||
if (el.scrollHeight > el.clientHeight) {
|
||||
return $(el);
|
||||
} else {
|
||||
return closestScrollable(el.parentElement);
|
||||
}
|
||||
};
|
||||
// Give priority to the closest scrollable element (e.g. for images in
|
||||
// HTML fields, the element to scroll is different from the document's
|
||||
// scrolling element).
|
||||
const $scrollable = closestScrollable(this.media);
|
||||
|
||||
// The image must be in a position that allows access to it and its crop
|
||||
// options buttons. Otherwise, the crop widget container can be scrolled
|
||||
// to allow editing.
|
||||
if (rect.top < viewportTop || viewportBottom - rect.bottom < 100) {
|
||||
await dom.scrollTo(this.media, {
|
||||
easing: "linear",
|
||||
duration: 500,
|
||||
...($scrollable && { $scrollable }),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
|
||||
@@ -605,6 +605,7 @@ img.o_we_selected_image {
|
||||
@include o-position-absolute(0, 0, 0, 0);
|
||||
/* This value must be higher than dialog z-index in bootstrap */
|
||||
z-index: 1056;
|
||||
overflow: auto;
|
||||
|
||||
.o_we_cropper_wrapper {
|
||||
position: absolute;
|
||||
|
||||
Reference in New Issue
Block a user