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 b5cbaf120e2..fd425d502c1 100644
--- a/addons/web_editor/static/src/js/editor/snippets.options.js
+++ b/addons/web_editor/static/src/js/editor/snippets.options.js
@@ -5677,8 +5677,11 @@ const ImageHandlerOption = SnippetOptionWidget.extend({
/**
* @see this.selectClass for parameters
*/
- selectWidth(previewMode, widgetValue, params) {
- this._getImg().dataset.resizeWidth = widgetValue;
+ selectFormat(previewMode, widgetValue, params) {
+ const values = widgetValue.split(' ');
+ const image = this._getImg();
+ image.dataset.resizeWidth = values[0];
+ image.dataset.mimetype = values[1];
return this._applyOptions();
},
/**
@@ -5747,8 +5750,8 @@ const ImageHandlerOption = SnippetOptionWidget.extend({
});
switch (methodName) {
- case 'selectWidth':
- return img.naturalWidth;
+ case 'selectFormat':
+ return img.naturalWidth + ' ' + this._getImageMimetype(img);
case 'setFilter':
return img.dataset.filter;
case 'glFilter':
@@ -5776,9 +5779,9 @@ const ImageHandlerOption = SnippetOptionWidget.extend({
if (!this.originalSrc || !this._isImageSupportedForProcessing(img)) {
return;
}
- const $select = $(uiFragment).find('we-select[data-name=width_select_opt]');
- (await this._computeAvailableWidths()).forEach(([value, label]) => {
- $select.append(`${label}`);
+ const $select = $(uiFragment).find('we-select[data-name=format_select_opt]');
+ (await this._computeAvailableFormats()).forEach(([value, [label, targetFormat]]) => {
+ $select.append(`${label} ${targetFormat.split('/')[1]}`);
});
if (!['image/jpeg', 'image/webp'].includes(this._getImageMimetype(img))) {
@@ -5789,26 +5792,31 @@ const ImageHandlerOption = SnippetOptionWidget.extend({
}
},
/**
- * Returns a list of valid widths for a given image.
+ * Returns a list of valid formats for a given image.
*
* @private
*/
- async _computeAvailableWidths() {
+ async _computeAvailableFormats() {
const img = this._getImg();
const original = await loadImage(this.originalSrc);
const maxWidth = img.dataset.width ? img.naturalWidth : original.naturalWidth;
const optimizedWidth = Math.min(maxWidth, this._computeMaxDisplayWidth());
this.optimizedWidth = optimizedWidth;
const widths = {
- 128: '128px',
- 256: '256px',
- 512: '512px',
- 1024: '1024px',
- 1920: '1920px',
+ 128: ['128px', 'image/webp'],
+ 256: ['256px', 'image/webp'],
+ 512: ['512px', 'image/webp'],
+ 1024: ['1024px', 'image/webp'],
+ 1920: ['1920px', 'image/webp'],
};
- widths[img.naturalWidth] = sprintf(_t("%spx"), img.naturalWidth);
- widths[optimizedWidth] = sprintf(_t("%spx (Suggested)"), optimizedWidth);
- widths[maxWidth] = sprintf(_t("%spx (Original)"), maxWidth);
+ widths[img.naturalWidth] = [sprintf(_t("%spx"), img.naturalWidth), 'image/webp'];
+ widths[optimizedWidth] = [sprintf(_t("%spx (Suggested)"), optimizedWidth), 'image/webp'];
+ widths[maxWidth] = [sprintf(_t("%spx (Original)"), maxWidth), img.dataset.originalMimetype];
+ if (img.dataset.originalMimetype !== 'image/webp') {
+ // Avoid a key collision by subtracting 0.1 - putting the webp
+ // above the original format one of the same size.
+ widths[maxWidth - 0.1] = [sprintf(_t("%spx"), maxWidth), 'image/webp'];
+ }
return Object.entries(widths)
.filter(([width]) => width <= maxWidth)
.sort(([v1], [v2]) => v1 - v2);
@@ -5863,6 +5871,9 @@ const ImageHandlerOption = SnippetOptionWidget.extend({
}
this.originalId = img.dataset.originalId;
this.originalSrc = img.dataset.originalSrc;
+ if (!img.dataset.originalMimetype) {
+ img.dataset.originalMimetype = img.dataset.mimetype;
+ }
},
/**
* Sets the image's width to its suggested size.
@@ -5872,7 +5883,12 @@ const ImageHandlerOption = SnippetOptionWidget.extend({
async _autoOptimizeImage() {
await this._loadImageInfo();
await this._rerenderXML();
- this._getImg().dataset.resizeWidth = this.optimizedWidth;
+ const img = this._getImg();
+ if (!['image/gif', 'image/svg+xml'].includes(img.dataset.mimetype)) {
+ // Convert to recommended format and width.
+ img.dataset.mimetype = 'image/webp';
+ img.dataset.resizeWidth = this.optimizedWidth;
+ }
await this._applyOptions();
await this.updateUI();
},
@@ -5944,7 +5960,7 @@ const ImageHandlerOption = SnippetOptionWidget.extend({
return params.optionsPossibleValues.glFilter
|| 'customFilter' in params.optionsPossibleValues
|| params.optionsPossibleValues.setQuality
- || widgetName === 'width_select_opt';
+ || widgetName === 'format_select_opt';
},
});
diff --git a/addons/web_editor/static/src/scss/wysiwyg_snippets.scss b/addons/web_editor/static/src/scss/wysiwyg_snippets.scss
index 43766b754bb..ede0b3ad368 100644
--- a/addons/web_editor/static/src/scss/wysiwyg_snippets.scss
+++ b/addons/web_editor/static/src/scss/wysiwyg_snippets.scss
@@ -1132,6 +1132,12 @@
}
}
+ &.o_we_badge_at_end > div {
+ display: flex;
+ width: 100%;
+ justify-content: space-between;
+ }
+
&:not(.d-none) ~ we-button {
// Use a border-top instead of a margin-top as when the
// mouse goes from one select button to another, the
diff --git a/addons/web_editor/views/snippets.xml b/addons/web_editor/views/snippets.xml
index bad5cede7f0..86ebed5b4c1 100644
--- a/addons/web_editor/views/snippets.xml
+++ b/addons/web_editor/views/snippets.xml
@@ -118,10 +118,10 @@
data-max="2000"
data-step="100"/>
- Width
- Format
+
+ data-name="format_select_opt"/>
Quality