summaryrefslogtreecommitdiff
path: root/addons/web_editor/static/src/js
diff options
context:
space:
mode:
authorSébastien Theys <seb@odoo.com>2019-06-04 15:10:53 +0200
committerSébastien Theys <seb@odoo.com>2019-06-04 22:14:13 +0200
commit191c556d6b50b35178ea5bb91fb998bcffb86367 (patch)
tree39a4a2565f405de2c36e274f3d062e3a9031517c /addons/web_editor/static/src/js
parent86d304fdb0c93fa3af0f2649882304c0ddabe896 (diff)
[IMP] web_editor, *: improve file media widget views & selection
* = web_unsplash, website_blog Rename "image" to "attachment" when appropriate in FileWidget Improve image selection / highlight code (now based on attachment id) Improve image grid view: - Remove the row mechanism and replace it by a single loop over the images. - Take advantage of row wrap for a responsive display. - Uniformize the height (prevent tall images from moving down everything). - Load a miniature of the images when possible, remove the loading placeholder. This should significantly reduce the download size when opening the dialog, at the cost of CPU usage on the server. - Split the existing image view into one view for the loop and one view for the image itself. This way in a following commit we can reuse the image view when adding a new one, instead of having to render everything again. task-1930726 PR: #31208
Diffstat (limited to 'addons/web_editor/static/src/js')
-rw-r--r--addons/web_editor/static/src/js/wysiwyg/widgets/media.js181
1 files changed, 71 insertions, 110 deletions
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 f901e9eb3f1..8e923acc6db 100644
--- a/addons/web_editor/static/src/js/wysiwyg/widgets/media.js
+++ b/addons/web_editor/static/src/js/wysiwyg/widgets/media.js
@@ -103,19 +103,18 @@ var FileWidget = SearchableMediaWidget.extend({
events: _.extend({}, SearchableMediaWidget.prototype.events || {}, {
'click .o_upload_media_button': '_onUploadButtonClick',
'click .o_upload_media_button_no_optimization': '_onUploadButtonNoOptimizationClick',
- 'change .o_file_input': '_onImageSelection',
+ 'change .o_file_input': '_onFileInputChange',
'click .o_upload_media_url_button': '_onUploadURLButtonClick',
'input .o_we_url_input': '_onURLInputChange',
- 'click .o_existing_attachment_cell [data-src]': '_onImageClick',
- 'dblclick .o_existing_attachment_cell [data-src]': '_onImageDblClick',
+ 'click .o_existing_attachment_cell': '_onAttachmentClick',
+ 'dblclick .o_existing_attachment_cell': '_onAttachmentDblClick',
'click .o_existing_attachment_remove': '_onRemoveClick',
'click .o_load_more': '_onLoadMoreClick',
}),
existingAttachmentsTemplate: undefined,
IMAGE_MIMETYPES: ['image/gif', 'image/jpe', 'image/jpeg', 'image/jpg', 'image/gif', 'image/png'],
- IMAGES_PER_ROW: 6,
- IMAGES_ROWS: 5,
+ NUMBER_OF_ATTACHMENTS_TO_DISPLAY: 30,
/**
* @constructor
@@ -124,15 +123,15 @@ var FileWidget = SearchableMediaWidget.extend({
this._super.apply(this, arguments);
this._mutex = new concurrency.Mutex();
- this.imagesRows = this.IMAGES_ROWS;
- this.IMAGES_DISPLAYED_TOTAL = this.IMAGES_PER_ROW * this.imagesRows;
+ this.numberOfAttachmentsToDisplay = this.NUMBER_OF_ATTACHMENTS_TO_DISPLAY;
this.options = _.extend({
firstFilters: [],
lastFilters: [],
}, options || {});
- this.images = [];
+ this.attachments = [];
+ this.selectedAttachments = [];
},
/**
* @override
@@ -159,8 +158,10 @@ var FileWidget = SearchableMediaWidget.extend({
this.$urlError = this.$('.o_we_url_error');
this.$errorText = this.$('.o_we_error_text');
- this._renderImages(true);
+ this._renderImages();
+ // If there is already an attachment on the target, select by default
+ // that attachment if it is among the loaded images.
var o = {
url: null,
alt: null,
@@ -172,7 +173,9 @@ var FileWidget = SearchableMediaWidget.extend({
o.id = +o.url.match(/\/web\/content\/(\d+)/, '')[1];
}
if (o.url) {
- self._toggleImage(_.find(self.records, function (record) { return record.url === o.url;}) || o, true);
+ self._toggleImage(_.find(self.attachments, function (attachment) {
+ return attachment.url === o.url;
+ }) || o, true);
}
return def;
@@ -193,12 +196,11 @@ var FileWidget = SearchableMediaWidget.extend({
},
/**
* @override
+ * @param {boolean} noRender: if true, do not render the found attachments
*/
search: function (needle, noRender) {
var self = this;
- if (!noRender) {
- this.$urlInput.val('').trigger('input').trigger('change');
- }
+
return this._rpc({
model: 'ir.attachment',
method: 'search_read',
@@ -209,8 +211,8 @@ var FileWidget = SearchableMediaWidget.extend({
order: [{name: 'id', asc: false}],
context: this.options.context,
},
- }).then(function (records) {
- self.records = _.chain(records)
+ }).then(function (attachments) {
+ self.attachments = _.chain(attachments)
.filter(function (r) {
return (r.type === "binary" || r.url && r.url.length > 0);
})
@@ -234,13 +236,13 @@ var FileWidget = SearchableMediaWidget.extend({
})
.value();
- _.each(self.records, function (record) {
- record.src = record.url || _.str.sprintf('/web/image/%s/%s', record.id, encodeURI(record.name)); // Name is added for SEO purposes
- record.isDocument = !(/gif|jpe|jpg|png/.test(record.mimetype));
+ _.each(self.attachments, function (attachment) {
+ // Name is added for SEO purposes
+ attachment.src = attachment.url || _.str.sprintf('/web/image/%s/%s', attachment.id, encodeURI(attachment.name));
+ attachment.isDocument = !(/gif|jpe|jpg|png/.test(attachment.mimetype));
});
if (!noRender) {
self._renderImages();
- self._adaptLoadMore();
}
});
},
@@ -250,14 +252,6 @@ var FileWidget = SearchableMediaWidget.extend({
//--------------------------------------------------------------------------
/**
- * @private
- */
- _adaptLoadMore: function () {
- var noMoreImgToLoad = this.IMAGES_DISPLAYED_TOTAL >= this.records.length;
- this.$('.o_load_more').toggleClass('d-none', noMoreImgToLoad);
- this.$('.o_load_done_msg').toggleClass('d-none', !noMoreImgToLoad);
- },
- /**
* @override
*/
_clear: function () {
@@ -318,27 +312,20 @@ var FileWidget = SearchableMediaWidget.extend({
/**
* @private
*/
- _highlightSelectedImages: function () {
+ _highlightSelected: function () {
var self = this;
- this.$('.o_existing_attachment_cell.o_selected').removeClass("o_selected");
- var $select = this.$('.o_existing_attachment_cell [data-src]').filter(function () {
- var $img = $(this);
- return !!_.find(self.images, function (v) {
- return (v.url === $img.data("src") || ($img.data("url") && v.url === $img.data("url")) || v.id === $img.data("id"));
- });
+ this.$('.o_existing_attachment_cell.o_we_attachment_selected').removeClass("o_we_attachment_selected");
+ _.each(this.selectedAttachments, function (attachment) {
+ self.$('.o_existing_attachment_cell[data-id=' + attachment.id + ']').addClass("o_we_attachment_selected");
});
- $select.closest('.o_existing_attachment_cell').addClass("o_selected");
- return $select;
},
/**
* @private
*/
_loadMoreImages: function (forceSearch) {
- this.imagesRows += 2;
- this.IMAGES_DISPLAYED_TOTAL = this.imagesRows * this.IMAGES_PER_ROW;
+ this.numberOfAttachmentsToDisplay += 10;
if (!forceSearch) {
this._renderImages();
- this._adaptLoadMore();
} else {
this.search(this.$('.o_we_search').val() || '');
}
@@ -346,58 +333,34 @@ var FileWidget = SearchableMediaWidget.extend({
/**
* Renders the existing attachments and returns the result as a string.
*
- * @param {Object[]} rows
- * @param {boolean} withEffect
+ * @param {Object[]} attachments
* @returns {string}
*/
- _renderExisting: function (rows, withEffect) {
+ _renderExisting: function (attachments) {
return QWeb.render(this.existingAttachmentsTemplate, {
- rows: rows,
+ attachments: attachments,
widget: this,
- withEffect: withEffect,
});
},
/**
* @private
*/
- _renderImages: function (withEffect) {
- var self = this;
- var rows = _(this.records).chain()
- .slice(0, this.IMAGES_DISPLAYED_TOTAL)
- .groupBy(function (a, index) { return Math.floor(index / self.IMAGES_PER_ROW); })
- .values()
- .value();
+ _renderImages: function () {
+ var attachments = this.attachments.slice(0, this.numberOfAttachmentsToDisplay);
this.$errorText.empty();
- // Render menu & content
+ // Render menu & content
this.$('.existing-attachments').replaceWith(
- this._renderExisting(rows, withEffect)
+ this._renderExisting(attachments)
);
- var $divs = this.$('.o_image');
- var imageDefs = _.map($divs, function (el) {
- var $div = $(el);
- if (/gif|jpe|jpg|png/.test($div.data('mimetype'))) {
- var $img = $('<img/>', {
- class: 'img-fluid',
- src: $div.data('url') || $div.data('src'),
- });
- var prom = new Promise(function (resolve, reject) {
- $img[0].onload = resolve();
- $div.addClass('o_webimage').append($img);
- });
- return prom;
- }
- });
- if (withEffect) {
- Promise.all(imageDefs).then(function () {
- _.delay(function () {
- $divs.removeClass('o_image_loading');
- }, 400);
- });
- }
- this._highlightSelectedImages();
+ this._highlightSelected();
+
+ // adapt load more
+ var noMoreImgToLoad = this.numberOfAttachmentsToDisplay >= this.attachments.length;
+ this.$('.o_load_more').toggleClass('d-none', noMoreImgToLoad);
+ this.$('.o_load_done_msg').toggleClass('d-none', !noMoreImgToLoad);
},
/**
* @private
@@ -407,10 +370,10 @@ var FileWidget = SearchableMediaWidget.extend({
var self = this;
if (this.options.multiImages) {
- return Promise.resolve(this.images);
+ return Promise.resolve(this.selectedAttachments);
}
- var img = this.images[0];
+ var img = this.selectedAttachments[0];
if (!img) {
return Promise.resolve(this.media);
}
@@ -475,24 +438,24 @@ var FileWidget = SearchableMediaWidget.extend({
/**
* @private
*/
- _toggleImage: function (attachment, clearSearch, forceSelect) {
+ _toggleImage: function (attachment, doubleClick) {
if (this.options.multiImages) {
- var img = _.select(this.images, function (v) { return v.id === attachment.id; });
- if (img.length) {
- if (!forceSelect) {
- this.images.splice(this.images.indexOf(img[0]),1);
+ // if the clicked image is already selected, then unselect it
+ // unless it was a double click
+ var index = this.selectedAttachments.indexOf(attachment);
+ if (index !== -1) {
+ if (!doubleClick) {
+ this.selectedAttachments.splice(index, 1);
}
} else {
- this.images.push(attachment);
+ // if the clicked image is not selected, then select it
+ this.selectedAttachments.push(attachment);
}
} else {
- this.images = [attachment];
- }
- this._highlightSelectedImages();
-
- if (clearSearch) {
- this.search('');
+ // select the clicked image
+ this.selectedAttachments = [attachment];
}
+ this._highlightSelected();
},
/**
* Updates the add by URL UI.
@@ -536,14 +499,15 @@ var FileWidget = SearchableMediaWidget.extend({
self.$('.well > span').remove();
self.$('.well > div').show();
- _.each(attachments, function (record) {
- record.src = record.url || _.str.sprintf('/web/image/%s/%s', record.id, encodeURI(record.name)); // Name is added for SEO purposes
- record.isDocument = !(/gif|jpe|jpg|png/.test(record.mimetype));
+ _.each(attachments, function (attachment) {
+ // Name is added for SEO purposes
+ attachment.src = attachment.url || _.str.sprintf('/web/image/%s/%s', attachment.id, encodeURI(attachment.name));
+ attachment.isDocument = !(/gif|jpe|jpg|png/.test(attachment.mimetype));
});
if (error || !attachments.length) {
_processFile(null, error || !attachments.length);
}
- self.images = attachments;
+ self.attachments = attachments;
for (var i = 0 ; i < attachments.length ; i++) {
_processFile(attachments[i], error);
}
@@ -584,24 +548,22 @@ var FileWidget = SearchableMediaWidget.extend({
/**
* @private
*/
- _onImageClick: function (ev, force_select) {
- var $img = $(ev.currentTarget);
- var attachment = _.find(this.records, function (record) {
- return record.id === $img.data('id');
- });
- this._toggleImage(attachment, false, force_select);
+ _onAttachmentClick: function (ev, doubleClick) {
+ var $attachment = $(ev.currentTarget);
+ var attachment = _.find(this.attachments, {id: $attachment.data('id')});
+ this._toggleImage(attachment, doubleClick);
},
/**
* @private
*/
- _onImageDblClick: function (ev) {
- this._onImageClick(ev, true);
+ _onAttachmentDblClick: function (ev) {
+ this._onAttachmentClick(ev, true);
this.trigger_up('save_request');
},
/**
* @private
*/
- _onImageSelection: function () {
+ _onFileInputChange: function () {
this.$el.addClass('nosave');
this.$form.removeClass('o_has_error').find('.form-control, .custom-select').removeClass('is-invalid');
this.$errorText.empty();
@@ -616,9 +578,9 @@ var FileWidget = SearchableMediaWidget.extend({
Dialog.confirm(this, _t("Are you sure you want to delete this file ?"), {
confirm_callback: function () {
var $helpBlock = self.$errorText.empty();
- var $a = $(ev.currentTarget);
+ var $a = $(ev.currentTarget).closest('.o_existing_attachment_cell');
var id = parseInt($a.data('id'), 10);
- var attachment = _.findWhere(self.records, {id: id});
+ var attachment = _.findWhere(self.attachments, {id: id});
return self._rpc({
route: '/web_editor/attachment/remove',
params: {
@@ -626,7 +588,7 @@ var FileWidget = SearchableMediaWidget.extend({
},
}).then(function (prevented) {
if (_.isEmpty(prevented)) {
- self.records = _.without(self.records, attachment);
+ self.attachments = _.without(self.attachments, attachment);
self._renderImages();
return;
}
@@ -683,8 +645,7 @@ var FileWidget = SearchableMediaWidget.extend({
* @override
*/
_onSearchInput: function () {
- this.imagesRows = this.IMAGES_ROWS;
- this.IMAGES_DISPLAYED_TOTAL = this.IMAGES_PER_ROW * this.imagesRows;
+ this.numberOfAttachmentsToDisplay = this.NUMBER_OF_ATTACHMENTS_TO_DISPLAY;
this._super.apply(this, arguments);
},
});
@@ -885,10 +846,10 @@ var IconWidget = SearchableMediaWidget.extend({
*/
_highlightSelectedIcon: function () {
var self = this;
- this.$icons.removeClass('o_selected');
+ this.$icons.removeClass('o_we_attachment_selected');
this.$icons.filter(function (i, el) {
return _.contains($(el).data('alias').split(','), self.selectedIcon);
- }).addClass('o_selected');
+ }).addClass('o_we_attachment_selected');
},
//--------------------------------------------------------------------------