[FIX] web_editor: fix icons losing classes when modifying them

Previously, when double clicking and image, video, icon, or document in
the web-editor and replacing it with a different media type, it would
lose its custom classes. This means among other things, that it would
lose margins and paddings from bootstrap classes, or in the case of the
three columns snippet, that the new media would not be properly rounded
in its top corner, or not show up at all in the case of the video. The
only exception was when changing any media type to an icon, but in that
case it would also keep some of the media-specific classes that are
supposed to be removed (eg img-fluid or media_iframe_video).

This commit fixes that as well as some _clear behaviour that didn't
remove all classes that had to be removed, eg some fa-classes would
linger depending on their order, and the o_image class from documents
would always remain

Part of https://github.com/odoo/odoo/pull/64234
task-2282542

closes odoo/odoo#64234

X-original-commit: 99531f5dd8966fc4ad89d1e9c2886ad701527f3a
Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
This commit is contained in:
Samuel Degueldre
2021-01-12 06:52:14 +00:00
parent 398259c93f
commit 3bb892cfab
3 changed files with 27 additions and 17 deletions
@@ -4,6 +4,8 @@
height: 38px;
background-image: url('/web/static/src/img/mimetypes/unknown.svg');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
&[data-mimetype^='image'] {
background-image: url('/web/static/src/img/mimetypes/image.svg');
@@ -251,15 +251,7 @@ var FileWidget = SearchableMediaWidget.extend({
* @override
*/
_clear: function () {
if (this.$media.is('img')) {
return;
}
var allImgClasses = /(^|\s+)((img(\s|$)|img-(?!circle|rounded|thumbnail))[^\s]*)/g;
var allImgClassModifiers = /(^|\s+)(rounded-circle|shadow|rounded|img-thumbnail|mx-auto)([^\s]*)/g;
this.media.className = this.media.className && this.media.className
.replace('o_we_custom_image', '')
.replace(allImgClasses, ' ')
.replace(allImgClassModifiers, ' ');
this.media.className = this.media.className && this.media.className.replace(/(^|\s+)(o_image)(?=\s|$)/g, ' ');
},
/**
* Returns the domain for attachments used in media dialog.
@@ -977,6 +969,14 @@ var ImageWidget = FileWidget.extend({
this.libraryMedia = [];
this._super(...arguments);
},
/**
* @override
*/
_clear: function (type) {
// Not calling _super: we don't want to call the document widget's _clear method on images
var allImgClasses = /(^|\s+)(img|img-\S*|o_we_custom_image|rounded-circle|rounded|thumbnail|shadow)(?=\s|$)/g;
this.media.className = this.media.className && this.media.className.replace(allImgClasses, ' ');
},
});
@@ -1056,10 +1056,10 @@ var IconWidget = SearchableMediaWidget.extend({
var cls = classes[i];
if (_.contains(this.alias, cls)) {
this.selectedIcon = cls;
this.initialIcon = cls;
this._highlightSelectedIcon();
}
}
this.nonIconClasses = _.without(classes, 'media_iframe_video', this.selectedIcon);
return this._super.apply(this, arguments);
},
@@ -1074,7 +1074,6 @@ var IconWidget = SearchableMediaWidget.extend({
save: function () {
var style = this.$media.attr('style') || '';
var iconFont = this._getFont(this.selectedIcon) || {base: 'fa', font: ''};
var finalClasses = _.uniq(this.nonIconClasses.concat([iconFont.base, iconFont.font]));
if (!this.$media.is('span, i')) {
var $span = $('<span/>');
$span.data(this.$media.data());
@@ -1082,10 +1081,8 @@ var IconWidget = SearchableMediaWidget.extend({
this.media = this.$media[0];
style = style.replace(/\s*width:[^;]+/, '');
}
this.$media.attr({
class: _.compact(finalClasses).join(' '),
style: style || null,
});
this.$media.removeClass(this.initialIcon).addClass([iconFont.base, iconFont.font]);
this.$media.attr('style', style || null);
return Promise.resolve(this.media);
},
/**
@@ -1123,7 +1120,7 @@ var IconWidget = SearchableMediaWidget.extend({
* @override
*/
_clear: function () {
var allFaClasses = /(^|\s)(fa(\s|$)|fa-[^\s]*)/g;
var allFaClasses = /(^|\s)(fa|(text-|bg-|fa-)\S*|rounded-circle|rounded|thumbnail|shadow)(?=\s|$)/g;
this.media.className = this.media.className && this.media.className.replace(allFaClasses, ' ');
},
/**
@@ -39,6 +39,7 @@ var MediaDialog = Dialog.extend({
init: function (parent, options, media) {
var $media = $(media);
media = $media[0];
this.media = media;
options = _.extend({}, options);
var onlyImages = options.onlyImages || this.multiImages || (media && ($media.parent().data('oeField') === 'image' || $media.parent().data('oeType') === 'image'));
@@ -75,6 +76,7 @@ var MediaDialog = Dialog.extend({
} else {
this.activeWidget = [this.imageWidget, this.documentWidget, this.videoWidget, this.iconWidget].find(w => !!w);
}
this.initiallyActiveWidget = this.activeWidget;
},
/**
* Adds the appropriate class to the current modal and appends the media
@@ -153,7 +155,16 @@ var MediaDialog = Dialog.extend({
var _super = this._super;
var args = arguments;
return this.activeWidget.save().then(function (data) {
self._clearWidgets();
if (self.activeWidget !== self.initiallyActiveWidget) {
self._clearWidgets();
}
// Restore classes if the media was replaced (when changing type)
if (self.media !== data) {
var oldClasses = self.media && _.toArray(self.media.classList);
if (oldClasses) {
data.className = _.union(_.toArray(data.classList), oldClasses).join(' ');
}
}
self.final_data = data;
_super.apply(self, args);
$(data).trigger('content_changed');