summaryrefslogtreecommitdiff
path: root/addons/web_editor/static/src/js/wysiwyg
diff options
context:
space:
mode:
authorSamuel Degueldre <sad@odoo.com>2020-05-19 09:21:49 +0000
committerqsm-odoo <qsm@odoo.com>2020-06-05 18:11:53 +0000
commitaa8d2a8be2c8f713b4b39b2aa1ea2aaf1839396c (patch)
treef1531840d7b262d1e282d14db23a3d0ce6d41571 /addons/web_editor/static/src/js/wysiwyg
parentc2de755bc690987f59cda27bd83a7429278955fc (diff)
[IMP] web_editor, *: move image optimization feature to left-panel
*: website, mass_mailing In continuity with the nline crop, in an effort to make the image workflow as seamless as possible in the website editor, the image optimization feature has been moved out of the modal which could be opened through the media-dialog and into the left panel. This commit adds a quality slider and a width selector, as well as a preview of the image's weight to the left panel, and removes the image_optimize dialog. This commit also introduces the possibility to add a color filter on images. Part of https://github.com/odoo/odoo/pull/51517 task-2192755 closes odoo/odoo#51517 Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
Diffstat (limited to 'addons/web_editor/static/src/js/wysiwyg')
-rw-r--r--addons/web_editor/static/src/js/wysiwyg/root.js2
-rw-r--r--addons/web_editor/static/src/js/wysiwyg/widgets/image_crop_widget.js120
-rw-r--r--addons/web_editor/static/src/js/wysiwyg/widgets/image_optimize_dialog.js330
-rw-r--r--addons/web_editor/static/src/js/wysiwyg/widgets/media.js113
-rw-r--r--addons/web_editor/static/src/js/wysiwyg/wysiwyg.js4
5 files changed, 26 insertions, 543 deletions
diff --git a/addons/web_editor/static/src/js/wysiwyg/root.js b/addons/web_editor/static/src/js/wysiwyg/root.js
index 8b644b6faae..dc87ff9e0be 100644
--- a/addons/web_editor/static/src/js/wysiwyg/root.js
+++ b/addons/web_editor/static/src/js/wysiwyg/root.js
@@ -9,7 +9,7 @@ var WysiwygRoot = Widget.extend({
assetLibs: ['web_editor.compiled_assets_wysiwyg'],
_loadLibsTplRoute: '/web_editor/public_render_template',
- publicMethods: ['isDirty', 'save', 'getValue', 'setValue', 'getEditable', 'on', 'trigger', 'focus', 'saveCroppedImages'],
+ publicMethods: ['isDirty', 'save', 'getValue', 'setValue', 'getEditable', 'on', 'trigger', 'focus', 'saveModifiedImages'],
/**
* @see 'web_editor.wysiwyg' module
diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/image_crop_widget.js b/addons/web_editor/static/src/js/wysiwyg/widgets/image_crop_widget.js
index 91f76bba5d4..27444e061af 100644
--- a/addons/web_editor/static/src/js/wysiwyg/widgets/image_crop_widget.js
+++ b/addons/web_editor/static/src/js/wysiwyg/widgets/image_crop_widget.js
@@ -2,13 +2,11 @@ odoo.define('wysiwyg.widgets.ImageCropWidget', function (require) {
'use strict';
const core = require('web.core');
-const qweb = core.qweb;
const Widget = require('web.Widget');
+const {applyModifications, cropperDataFields, activateCropper, loadImage, loadImageInfo} = require('web_editor.image_processing');
const _t = core._t;
-// Fields returned by cropper lib 'getData' method
-const cropperDataFields = ['x', 'y', 'width', 'height', 'rotate', 'scaleX', 'scaleY'];
const ImageCropWidget = Widget.extend({
template: ['wysiwyg.widgets.crop'],
xmlDependencies: ['/web_editor/static/src/xml/wysiwyg.xml'],
@@ -17,41 +15,16 @@ const ImageCropWidget = Widget.extend({
// zoom event is triggered by the cropperjs library when the user zooms.
'zoom': '_onCropZoom',
},
- // Crop attributes that are saved with the DOM. Should only be removed when the image is changed.
- persistentAttributes: [
- ...cropperDataFields,
- 'aspectRatio',
- ],
- // Attributes that are used to keep data from one crop to the next in the same session
- // If present, should be used by the cropper instead of querying db
- sessionAttributes: [
- 'attachmentId',
- 'originalSrc',
- 'originalId',
- 'originalName',
- 'mimetype',
- ],
- // Attributes that are used by saveCroppedImages to create or update attachments
- saveAttributes: [
- 'resModel',
- 'resId',
- 'attachmentId',
- 'originalId',
- 'originalName',
- 'mimetype',
- ],
/**
* @constructor
*/
- init(parent, options, media) {
+ init(parent, media) {
this._super(...arguments);
this.media = media;
this.$media = $(media);
// Needed for editors in iframes.
this.document = media.ownerDocument;
- // Used for res_model and res_id
- this.options = options;
// key: ratio identifier, label: displayed to user, value: used by cropper lib
this.aspectRatios = {
"0/0": {label: _t("Free"), value: 0},
@@ -65,48 +38,26 @@ const ImageCropWidget = Widget.extend({
this.initialSrc = src;
this.aspectRatio = data.aspectRatio || "0/0";
this.mimetype = data.mimetype || src.endsWith('.png') ? 'image/png' : 'image/jpeg';
- this.isCroppable = src.startsWith('data:') || new URL(src, window.location.origin).origin === window.location.origin;
},
/**
* @override
*/
async willStart() {
await this._super.apply(this, arguments);
- if (!this.isCroppable) {
- return;
- }
- // If there is a marked originalSrc, a previous crop has already happened,
- // we won't find the original from the data-url. Reuse the data from the previous crop.
+ await loadImageInfo(this.media, this._rpc.bind(this));
if (this.media.dataset.originalSrc) {
- this.sessionAttributes.forEach(attr => {
- this[attr] = this.media.dataset[attr];
- });
- return;
- }
-
- // Get id, mimetype and originalSrc.
- const {attachment, original} = await this._rpc({
- route: '/web_editor/get_image_info',
- params: {src: this.initialSrc.split(/[?#]/)[0]},
- });
- if (!attachment) {
- // Local image that doesn't have an attachment, don't allow crop?
- // In practice, this can happen if an image is directly linked with its
- // static url and there is no corresponding attachment, (eg, logo in mass_mailing)
- this.isCroppable = false;
+ this.originalSrc = this.media.dataset.originalSrc;
+ this.originalId = this.media.dataset.originalId;
return;
}
- this.originalId = original.id;
- this.originalSrc = original.image_src;
- this.originalName = original.name;
- this.mimetype = original.mimetype;
- this.attachmentId = attachment.id;
+ // Couldn't find an attachment: not croppable.
+ this.uncroppable = true;
},
/**
* @override
*/
async start() {
- if (!this.isCroppable) {
+ if (this.uncroppable) {
this.displayNotification({
type: 'warning',
title: _t("This image is an external image"),
@@ -118,8 +69,7 @@ const ImageCropWidget = Widget.extend({
const $cropperWrapper = this.$('.o_we_cropper_wrapper');
// Replacing the src with the original's so that the layout is correct.
- this.media.setAttribute('src', this.originalSrc);
- await new Promise(resolve => this.media.addEventListener('load', resolve, {once: true}));
+ await loadImage(this.originalSrc, this.media);
this.$cropperImage = this.$('.o_we_cropper_img');
const cropperImage = this.$cropperImage[0];
[cropperImage.style.width, cropperImage.style.height] = [this.$media.width() + 'px', this.$media.height() + 'px'];
@@ -130,18 +80,8 @@ const ImageCropWidget = Widget.extend({
offset.top += parseInt(this.$media.css('padding-right'));
$cropperWrapper.offset(offset);
- cropperImage.setAttribute('src', this.originalSrc);
- await new Promise(resolve => cropperImage.addEventListener('load', resolve, {once: true}));
- this.$cropperImage.cropper({
- viewMode: 2,
- dragMode: 'move',
- autoCropArea: 1.0,
- aspectRatio: this.aspectRatios[this.aspectRatio].value,
- data: _.mapObject(_.pick(this.media.dataset, ...cropperDataFields), value => parseFloat(value)),
- // Can't use 0 because it's falsy and the lib will then use its defaults (200x100)
- minContainerWidth: 1,
- minContainerHeight: 1,
- });
+ await loadImage(this.originalSrc, cropperImage);
+ await activateCropper(cropperImage, this.aspectRatios[this.aspectRatio].value, this.media.dataset);
core.bus.trigger('deactivate_snippet');
this._onDocumentMousedown = this._onDocumentMousedown.bind(this);
@@ -173,27 +113,20 @@ const ImageCropWidget = Widget.extend({
*
* @private
*/
- _save() {
- // Mark the media for later creation/update of cropped attachment
- this.media.classList.add('o_cropped_img_to_save');
+ async _save() {
+ // Mark the media for later creation of cropped attachment
+ this.media.classList.add('o_modified_image_to_save');
- this.allAttributes.forEach(attr => {
+ [...cropperDataFields, 'aspectRatio'].forEach(attr => {
delete this.media.dataset[attr];
const value = this._getAttributeValue(attr);
if (value) {
this.media.dataset[attr] = value;
}
});
-
- // Update the media with base64 source for preview before saving
- const cropperData = this.$cropperImage.cropper('getData');
- const canvas = this.$cropperImage.cropper('getCroppedCanvas', {
- width: cropperData.width,
- height: cropperData.height,
- });
- // 1 is the quality if the image is jpeg (in the range O-1), defaults to .92
- this.initialSrc = canvas.toDataURL(this.mimetype, 1);
- // src will be set to this.initialSrc in the destroy method
+ delete this.media.dataset.resizeWidth;
+ this.initialSrc = await applyModifications(this.media);
+ this.$media.trigger('image_cropped');
this.destroy();
},
/**
@@ -202,12 +135,6 @@ const ImageCropWidget = Widget.extend({
* @private
*/
_getAttributeValue(attr) {
- switch (attr) {
- case 'resModel':
- return this.options.res_model;
- case 'resId':
- return this.options.res_id;
- }
if (cropperDataFields.includes(attr)) {
return this.$cropperImage.cropper('getData')[attr];
}
@@ -282,16 +209,5 @@ const ImageCropWidget = Widget.extend({
},
});
-const proto = ImageCropWidget.prototype;
-proto.allAttributes = [...new Set([
- ...proto.persistentAttributes,
- ...proto.sessionAttributes,
- ...proto.saveAttributes,
-])];
-proto.removeOnSaveAttributes = [...new Set([
- ...proto.sessionAttributes,
- ...proto.saveAttributes,
-])];
-
return ImageCropWidget;
});
diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/image_optimize_dialog.js b/addons/web_editor/static/src/js/wysiwyg/widgets/image_optimize_dialog.js
deleted file mode 100644
index 1c655026f32..00000000000
--- a/addons/web_editor/static/src/js/wysiwyg/widgets/image_optimize_dialog.js
+++ /dev/null
@@ -1,330 +0,0 @@
-odoo.define('wysiwyg.widgets.image_optimize_dialog', function (require) {
-'use strict';
-
-var core = require('web.core');
-var Dialog = require('web.Dialog');
-
-var _t = core._t;
-
-var ImageOptimizeDialog = Dialog.extend({
- template: 'wysiwyg.widgets.image.optimize',
- xmlDependencies: (Dialog.prototype.xmlDependencies || []).concat([
- '/web_editor/static/src/xml/wysiwyg.xml',
- ]),
- events: _.extend({}, Dialog.prototype.events, {
- 'click .o_we_width_preset': '_onWidthPresetClick',
- 'input #o_we_height': '_onHeightInput',
- 'input #o_we_name_input': '_onNameInput',
- 'input #o_we_optimize_quality': '_onOptimizeQualityInput',
- 'input #o_we_quality_input': '_onQualityInput',
- 'input #o_we_width': '_onWidthInput',
- 'input .o_we_quality_range': '_onQualityRangeInput',
- }),
-
- /**
- * @constructor
- */
- init: function (parent, params, options) {
- this._super(parent, _.extend({}, {
- title: _t("Improve your Image"),
- size: 'large',
- buttons: [
- {text: _t("Optimize"), classes: 'btn-primary o_we_save', close: false, click: this._onOptimizeClick.bind(this)},
- {text: _t("Keep Original"), close: false, click: this._onKeepOriginalClick.bind(this)}
- ],
- }, options));
- this.params = params;
- },
- /**
- * @override
- */
- willStart: async function () {
- const _super = this._super.bind(this);
- const {isExisting, attachment, optimizedWidth} = this.params;
- this.isExisting = isExisting;
- this.attachment = attachment;
- let original = attachment;
- if (attachment.original_id) {
- [original] = await this._rpc({
- model: 'ir.attachment',
- method: 'read',
- args: [[attachment.original_id[0]], ['image_width', 'image_height']],
- });
- }
- this.image_width = original.image_width;
- this.image_height = original.image_height;
- // We do not support resizing and quality for:
- // - SVG because it doesn't make sense
- // - GIF because our current code is not made to handle all the frames
- this.disableResize = ['image/jpeg', 'image/jpe', 'image/jpg', 'image/png'].indexOf(this.attachment.mimetype) === -1;
- this.disableQuality = this.disableResize;
- this.toggleQuality = this.attachment.mimetype === 'image/png';
- this.optimizedWidth = Math.min(optimizedWidth || this.image_width, this.image_width);
- this.defaultQuality = this.isExisting ? 100 : 80;
- this.defaultWidth = parseInt(this.isExisting ? this.image_width : this.optimizedWidth);
- this.defaultHeight = parseInt(this.isExisting || !this.image_width ? this.image_height :
- this.optimizedWidth / this.image_width * this.image_height);
-
- this.suggestedWidths = [];
- this._addSuggestedWidth(128, '128');
- this._addSuggestedWidth(256, '256');
- this._addSuggestedWidth(512, '512');
- this._addSuggestedWidth(1024, '1024');
- this._addSuggestedWidth(this.optimizedWidth,
- _.str.sprintf(_t("%d (Suggested)"), this.optimizedWidth));
- this.suggestedWidths.push({
- 'width': this.image_width,
- 'text': _.str.sprintf(_t("%d (Original)"), this.image_width),
- });
- this.suggestedWidths = _.sortBy(this.suggestedWidths, 'width');
- this._updatePreview = _.debounce(this._updatePreview.bind(this), 300);
- return _super(...arguments);
- },
- /**
- * @override
- */
- start: function () {
- var self = this;
- var promise = this._super.apply(this, arguments);
- this.$nameInput = this.$('#o_we_name_input');
- this.$previewImage = this.$('.o_we_preview_image');
- this.$saveButton = this.$footer.find('.o_we_save');
-
- // The following selectors might not contain anything:
- // - depending on disableResize
- this.$widthPresets = this.$('.o_we_width_preset');
- this.$widthInput = this.$('#o_we_width');
- this.$heightInput = this.$('#o_we_height');
- // - depending on disableQuality
- this.$qualityRange = this.$('.o_we_quality_range');
- this.$qualityInput = this.$('#o_we_quality_input');
- // - depending on toggleQuality
- this.$qualityCheckBox = this.$('#o_we_optimize_quality');
-
- this._updatePreview();
- this._validateForm();
- this.opened().then(function () {
- self.$nameInput.focus();
- });
- return promise;
- },
-
- //--------------------------------------------------------------------------
- // Private
- //--------------------------------------------------------------------------
-
- /**
- * Adds a size to the list of suggested width, only if it is smaller than
- * the image width (we don't scale up images).
- *
- * @private
- * @param {number} size: integer
- * @param {string} text
- */
- _addSuggestedWidth: function (size, text) {
- if (size < this.image_width) {
- this.suggestedWidths.push({
- width: size,
- text: text,
- });
- }
- },
- /**
- * Gets the current quality from the input, adapts it to match what is
- * expected by image tools, and returns it.
- *
- * The adaptation consists of transforming the quality 100 to 0 to disable
- * optimizations, and to convert values between 95 and 99 to 95 because
- * values above 95 results in large files with hardly any gain in image
- * quality.
- *
- * See `quality` parameter at:
- * https://pillow.readthedocs.io/en/4.0.x/handbook/image-file-formats.html#jpeg
- *
- * @private
- * @returns {number} the quality as integer
- */
- _getAdaptedQuality: function () {
- var quality = 0;
- if (this.$qualityCheckBox.length) {
- if (this.$qualityCheckBox.is(":checked")) {
- // any value will do, as long as it is not 100 or falsy
- quality = 50;
- }
- } else if (this.$qualityRange.length) {
- quality = parseInt(this.$qualityRange.val() || 0);
- }
- if (quality === 100) {
- quality = 0;
- }
- return Math.min(95, quality);
- },
- /**
- * Updates the preview to match the current settings, and also highlights
- * the width preset buttons if applicable.
- *
- * @private
- */
- _updatePreview: function () {
- if (!this._validatePreview()) {
- return;
- }
- var width = parseInt(this.$widthInput.val() || 0);
- var height = parseInt(this.$heightInput.val() || 0);
- this.$previewImage.attr('src', _.str.sprintf('/web/image/%d/%dx%d?quality=%d',
- (this.attachment.original_id || [this.attachment.id])[0], width, height, this._getAdaptedQuality()));
- this.$widthPresets.removeClass('active');
- _.each(this.$widthPresets, function (button) {
- var $button = $(button);
- if (parseInt($button.data('width')) === width) {
- $button.addClass('active');
- }
- });
- },
- /**
- * Validates the form and toggles the save button accordingly.
- *
- * @private
- * @returns {boolean} whether the form is valid
- */
- _validateForm: function () {
- var name = this.$nameInput.val();
- var isValid = name && this._validatePreview();
- this.$saveButton.prop('disabled', !isValid);
- return isValid;
- },
- /**
- * Validates the preview values.
- *
- * @private
- * @returns {boolean} whether the preview values are valid
- */
- _validatePreview: function () {
- var isValid = true;
- var quality = this._getAdaptedQuality();
- var width = parseInt(this.$widthInput.val() || 0);
- var height = parseInt(this.$heightInput.val() || 0);
- if (quality < 0 || quality > 100) {
- isValid = false;
- }
- if (width < 0 || width > this.image_width) {
- isValid = false;
- }
- if (height < 0 || height > this.image_height) {
- isValid = false;
- }
- return isValid;
- },
-
- //--------------------------------------------------------------------------
- // Handlers
- //--------------------------------------------------------------------------
-
- /**
- * @private
- */
- _onHeightInput: function () {
- var height = parseInt(this.$heightInput.val()) || 0;
- this.$widthInput
- .val(parseInt(height / this.image_height * this.image_width));
- this._updatePreview();
- this._validateForm();
- },
- /**
- * @private
- */
- _onKeepOriginalClick: function () {
- if (!this.isExisting) {
- this.trigger_up('attachment_updated', this.attachment);
- }
- this.close();
- },
- /**
- * @private
- */
- _onNameInput: function () {
- this._validateForm();
- },
- /**
- * Handles clicking on the save button: updates the given attachment with
- * the selected settings and triggers up the `attachment_updated`` event,
- * then closes the dialog.
- *
- * @private
- * @returns {Promise}
- */
- _onOptimizeClick: function () {
- var self = this;
- var name = this.$nameInput.val();
- var params = {
- 'name': name,
- 'quality': this._getAdaptedQuality(),
- 'width': parseInt(this.$widthInput.val() || 0),
- 'height': parseInt(this.$heightInput.val() || 0),
- };
- if (this.isExisting && !this.attachment.original_id) {
- params['copy'] = true;
- }
- return this._rpc({
- route: _.str.sprintf('/web_editor/attachment/%d/update', this.attachment.id),
- params: params,
- }).then(function (attachment) {
- self.trigger_up('attachment_updated', attachment);
- self.close();
- });
- },
- /**
- * @private
- */
- _onQualityInput: function () {
- var quality = parseInt(this.$qualityInput.val() || 0);
- // adapt the quality to what will actually happen
- if (quality === 0) {
- quality = 100;
- }
- // prevent flickering when clearing the input to type something else
- if (!quality) {
- return;
- }
- this.$qualityRange.val(quality);
- this._onQualityRangeInput();
- },
- /**
- * @private
- */
- _onQualityRangeInput: function () {
- var quality = parseInt(this.$qualityRange.val() || 0);
- this.$qualityInput.val(quality);
- this._updatePreview();
- this._validateForm();
- },
- /**
- * @private
- */
- _onOptimizeQualityInput: function () {
- this._updatePreview();
- },
- /**
- * @private
- */
- _onWidthInput: function () {
- var width = parseInt(this.$widthInput.val() || 0);
- this.$heightInput
- .val(parseInt(width / this.image_width * this.image_height));
- this._updatePreview();
- this._validateForm();
- },
- /**
- * @private
- */
- _onWidthPresetClick: function (ev) {
- ev.preventDefault();
- this.$widthInput.val(parseInt($(ev.target).data('width')));
- this._onWidthInput();
- },
-});
-
-return {
- ImageOptimizeDialog: ImageOptimizeDialog,
-};
-});
diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/media.js b/addons/web_editor/static/src/js/wysiwyg/widgets/media.js
index 645b49c7ead..09fddb2869b 100644
--- a/addons/web_editor/static/src/js/wysiwyg/widgets/media.js
+++ b/addons/web_editor/static/src/js/wysiwyg/widgets/media.js
@@ -6,11 +6,10 @@ var core = require('web.core');
var Dialog = require('web.Dialog');
var dom = require('web.dom');
var fonts = require('wysiwyg.fonts');
-var ImageOptimizeDialog = require('wysiwyg.widgets.image_optimize_dialog').ImageOptimizeDialog;
var utils = require('web.utils');
var Widget = require('web.Widget');
var session = require('web.session');
-const ImageCropWidget = require('wysiwyg.widgets.ImageCropWidget');
+const {removeOnImageChangeAttrs} = require('web_editor.image_processing');
var QWeb = core.qweb;
var _t = core._t;
@@ -123,7 +122,6 @@ var FileWidget = SearchableMediaWidget.extend({
'input .o_we_url_input': '_onURLInputChange',
'click .o_existing_attachment_cell': '_onAttachmentClick',
'click .o_existing_attachment_remove': '_onRemoveClick',
- 'click .o_existing_attachment_optimize': '_onExistingOptimizeClick',
'click .o_load_more': '_onLoadMoreClick',
}),
existingAttachmentsTemplate: undefined,
@@ -131,14 +129,6 @@ var FileWidget = SearchableMediaWidget.extend({
IMAGE_MIMETYPES: ['image/gif', 'image/jpe', 'image/jpeg', 'image/jpg', 'image/gif', 'image/png', 'image/svg+xml'],
NUMBER_OF_ATTACHMENTS_TO_DISPLAY: 30,
- // This factor is used to take into account that an image displayed in a BS
- // column might get bigger when displayed on a smaller breakpoint if that
- // breakpoint leads to have less columns.
- // Eg. col-lg-6 -> 480px per column -> col-md-12 -> 720px per column -> 1.5
- // However this will not be enough if going from 3 or more columns to 1, but
- // in that case, we consider it a snippet issue.
- OPTIMIZE_SIZE_FACTOR: 1.5,
-
/**
* @constructor
*/
@@ -261,20 +251,6 @@ var FileWidget = SearchableMediaWidget.extend({
.replace(allImgClassModifiers, ' ');
},
/**
- * Computes and returns the width that a new attachment should have to
- * ideally occupy the space where it will be inserted.
- * Only relevant for images.
- *
- * @see options.mediaWidth
- * @see OPTIMIZE_SIZE_FACTOR
- *
- * @private
- * @returns {integer}
- */
- _computeOptimizedWidth: function () {
- return Math.min(1920, parseInt(this.options.mediaWidth * this.OPTIMIZE_SIZE_FACTOR));
- },
- /**
* Returns the domain for attachments used in media dialog.
* We look for attachments related to the current document. If there is a value for the model
* field, it is used to search attachments, and the attachments from the current document are
@@ -356,52 +332,6 @@ var FileWidget = SearchableMediaWidget.extend({
});
},
/**
- * Opens the image optimize dialog for the given attachment.
- *
- * Hides the media dialog while the optimize dialog is open to avoid an
- * overlap of modals.
- *
- * @private
- * @param {object} attachment
- * @param {boolean} isExisting: whether this is a new attachment that was
- * just uploaded, or an existing attachment
- * @returns {Promise} resolved with the updated attachment object when the
- * optimize dialog is saved. Rejected if the dialog is otherwise closed.
- */
- _openImageOptimizeDialog: function (attachment, isExisting, $attachmentCell) {
- var self = this;
- var promise = new Promise(function (resolve, reject) {
- self.trigger_up('hide_parent_dialog_request');
- var optimizeDialog = new ImageOptimizeDialog(self, {
- attachment: attachment,
- isExisting: isExisting,
- optimizedWidth: self._computeOptimizedWidth(),
- }).open();
- optimizeDialog.on('attachment_updated', self, function (ev) {
- optimizeDialog.off('closed');
- if (self.$media[0].getAttribute('src') === attachment.image_src) {
- self.$media[0].src = ev.data.image_src;
- }
- Object.assign(attachment, ev.data);
- $attachmentCell.find('img')[0].src = attachment.image_src;
- resolve(attachment);
- });
- optimizeDialog.on('closed', self, function () {
- self.noSave = true;
- if (isExisting) {
- reject();
- } else {
- resolve(attachment);
- }
- });
- });
- var always = () => {
- self.trigger_up('show_parent_dialog_request');
- };
- promise.then(always).guardedCatch(always);
- return promise;
- },
- /**
* Renders the existing attachments and returns the result as a string.
*
* @param {Object[]} attachments
@@ -446,11 +376,6 @@ var FileWidget = SearchableMediaWidget.extend({
return this.media;
}
- // Auto optimize unoptimized images.
- if (['image/jpeg', 'image/jpe', 'image/jpg', 'image/png'].includes(img.mimetype) && img.type === 'binary' && !img.original_id) {
- img = await this._optimizeAttachment(img);
- }
-
if (!img.public && !img.access_token) {
await this._rpc({
model: 'ir.attachment',
@@ -496,31 +421,15 @@ var FileWidget = SearchableMediaWidget.extend({
this.$media.css(style);
}
- // Remove crop related attributes
- ImageCropWidget.prototype.allAttributes.forEach(attr => {
+ // Remove image modification attributes
+ removeOnImageChangeAttrs.forEach(attr => {
delete this.media.dataset[attr];
});
- this.media.classList.remove('o_cropped_img_to_save');
+ this.media.classList.remove('o_modified_image_to_save');
+ this.$media.trigger('image_changed');
return this.media;
},
/**
- * Creates and returns an optimized copy of an attachment.
- *
- * @private
- * @param {object} attachment
- */
- _optimizeAttachment: function (attachment) {
- return this._rpc({
- route: `/web_editor/attachment/${attachment.id}/update`,
- params: {
- copy: true,
- name: attachment.name,
- quality: attachment.mimetype === 'image/png' ? 0 : 80,
- width: this._computeOptimizedWidth(),
- },
- });
- },
- /**
* @param {object} attachment
* @param {boolean} [save=true] to save the given attachment in the DOM and
* and to close the media dialog
@@ -577,18 +486,6 @@ var FileWidget = SearchableMediaWidget.extend({
this._selectAttachement(attachment, !this.options.multiImages);
},
/**
- * @private
- */
- _onExistingOptimizeClick: function (ev) {
- var $a = $(ev.currentTarget).closest('.o_existing_attachment_cell');
- var id = parseInt($a.data('id'), 10);
- var attachment = _.findWhere(this.attachments, {id: id});
- ev.stopPropagation();
- return this._openImageOptimizeDialog(attachment, true, $a).then(newAttachment => {
- this._handleNewAttachment(newAttachment);
- });
- },
- /**
* Handles change of the file input: create attachments with the new files
* and open the Preview dialog for each of them. Locks the save button until
* all new files have been processed.
diff --git a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js
index fe7399fdebe..0ba27dcf172 100644
--- a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js
+++ b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js
@@ -158,8 +158,8 @@ var Wysiwyg = Widget.extend({
* @param {jQuery} $editable
* @returns {Promise}
*/
- saveCroppedImages: function ($editable) {
- return this._summernoteManager.saveCroppedImages($editable);
+ saveModifiedImages: function ($editable) {
+ return this._summernoteManager.saveModifiedImages($editable);
},
/**
* @param {String} value