From e378aebc247942ee5152127b9d8328f66d3b7a1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Theys?= Date: Thu, 23 May 2019 14:47:36 +0000 Subject: [PATCH 1/8] [IMP] web_editor, website_blog: clean up save/saved events The web_editor had two different events `save` and `saved` doing more or less the same thing but with a different signature. In this commit we keep only the `save` event and adapt the code accordingly. PR: #33509 --- .../static/src/js/wysiwyg/plugin/media.js | 29 +++++++++---------- .../src/js/wysiwyg/widgets/alt_dialog.js | 4 +-- .../src/js/wysiwyg/widgets/crop_dialog.js | 4 +-- .../static/src/js/wysiwyg/widgets/media.js | 2 ++ .../src/js/wysiwyg/widgets/media_dialog.js | 10 ------- .../js/wysiwyg_snippets/snippets.options.js | 4 +-- .../static/src/js/website_blog.editor.js | 4 +-- 7 files changed, 22 insertions(+), 35 deletions(-) diff --git a/addons/web_editor/static/src/js/wysiwyg/plugin/media.js b/addons/web_editor/static/src/js/wysiwyg/plugin/media.js index e6a598a2813..9ba83486e25 100644 --- a/addons/web_editor/static/src/js/wysiwyg/plugin/media.js +++ b/addons/web_editor/static/src/js/wysiwyg/plugin/media.js @@ -67,8 +67,8 @@ var MediaPlugin = AbstractPlugin.extend({ $(media).clone()[0] ); - mediaDialog.on('saved', this, function (data) { - this.insertMedia(media, data); + mediaDialog.on('save', this, function (element) { + this.insertMedia(media, element); }); mediaDialog.on('closed', this, function () { this.context.invoke('editor.restoreRange'); @@ -157,13 +157,12 @@ var MediaPlugin = AbstractPlugin.extend({ * Insert or replace a media. * * @param {Node} previous the media to replace, if any - * @param {Object} data contains the media to insert + * @param {Node} newMedia contains the media to insert */ - insertMedia: function (previous, data) { - if (!data.media) { + insertMedia: function (previous, newMedia) { + if (!newMedia) { return; } - var newMedia = data.media; this._wrapCommand(function () { this.$editable.focus(); var rng = this.context.invoke('editor.createRange'); @@ -689,17 +688,17 @@ var ImagePlugin = AbstractMediaPlugin.extend({ //-------------------------------------------------------------------------- /** - * Open the crop image dialog and listen to its saved/closed events. + * Open the crop image dialog and listen to its save/closed events. */ cropImageDialog: function () { this.context.invoke('editor.saveRange'); var media = this.context.invoke('editor.restoreTarget'); var cropImageDialog = new weWidgets.CropImageDialog(this.options.parent, {}, - $(media).clone() + $(media).clone()[0] ); - cropImageDialog.on('saved', this, function (data) { - this.context.invoke('MediaPlugin.insertMedia', media, data); + cropImageDialog.on('save', this, function (img) { + this.context.invoke('MediaPlugin.insertMedia', media, img); }); cropImageDialog.on('closed', this, function () { this.context.invoke('editor.restoreRange'); @@ -708,18 +707,18 @@ var ImagePlugin = AbstractMediaPlugin.extend({ cropImageDialog.open(); }, /** - * Open the alt dialog (change image title and alt) and listen to its saved/closed events. + * Open the alt dialog (change image title and alt) and listen to its save/closed events. */ altDialg: function () { this.context.invoke('editor.saveRange'); var media = this.context.invoke('editor.restoreTarget'); var altDialog = new weWidgets.AltDialog(this.options.parent, {}, - $(media).clone() + $(media).clone()[0] ); - altDialog.on('saved', this, this._wrapCommand(function (data) { - $(media).attr('alt', $(data.media).attr('alt')) - .attr('title', $(data.media).attr('title')) + altDialog.on('save', this, this._wrapCommand(function (img) { + $(media).attr('alt', img.alt) + .attr('title', img.title) .trigger('content_changed'); })); altDialog.on('closed', this, function () { diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/alt_dialog.js b/addons/web_editor/static/src/js/wysiwyg/widgets/alt_dialog.js index dd6baff130f..98abc75f6c1 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/alt_dialog.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/alt_dialog.js @@ -52,9 +52,7 @@ var AltDialog = Dialog.extend({ $(this.media).attr('alt', alt ? alt.replace(allNonEscQuots, """) : null) .attr('title', title ? title.replace(allNonEscQuots, """) : null); - this.trigger('saved', { - media: this.media, - }); + this.final_data = this.media; return this._super.apply(this, arguments); }, }); diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/crop_dialog.js b/addons/web_editor/static/src/js/wysiwyg/widgets/crop_dialog.js index cb1feaf3f4d..19623d05f5e 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/crop_dialog.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/crop_dialog.js @@ -172,9 +172,7 @@ var CropImageDialog = Dialog.extend({ }); this.$media.attr('src', canvas.toDataURL(this.imageData.mimetype)); - this.trigger('saved', { - media: this.$media[0], - }); + this.final_data = this.media; return this._super.apply(this, arguments); }, 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 ddd987f4ed2..a30b4a223b4 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/media.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/media.js @@ -47,6 +47,8 @@ var MediaWidget = Widget.extend({ */ search: function (needle) {}, /** + * Saves the currently configured media on the target media. + * * @abstract * @returns {*} */ diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/media_dialog.js b/addons/web_editor/static/src/js/wysiwyg/widgets/media_dialog.js index cdfde911597..4297d5f4dd3 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/media_dialog.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/media_dialog.js @@ -141,16 +141,6 @@ var MediaDialog = Dialog.extend({ var args = arguments; return Promise.resolve(this.active.save()).then(function (data) { self.final_data = data; - // In the case of multi images selection we suppose this was not to - // replace an old media, so we only retrieve the images and save. - if (!self.multiImages) { - // TODO this dialog triggers 'save' and 'saved' with different - // data on close... should refactor to avoid confusion... - self.trigger('saved', { - attachments: self.active.images, - media: data, - }); - } return _super.apply(self, args); }); }, diff --git a/addons/web_editor/static/src/js/wysiwyg_snippets/snippets.options.js b/addons/web_editor/static/src/js/wysiwyg_snippets/snippets.options.js index 5c7a41ae8f3..020a91b0a2b 100644 --- a/addons/web_editor/static/src/js/wysiwyg_snippets/snippets.options.js +++ b/addons/web_editor/static/src/js/wysiwyg_snippets/snippets.options.js @@ -858,8 +858,8 @@ registry.background = SnippetOption.extend({ res_id: $editable.data('oe-id'), }, $image[0]).open(); - _editor.on('save', this, function () { - this._setCustomBackground($image.attr('src')); + _editor.on('save', this, function (image) { + this._setCustomBackground(image.src); this.$target.trigger('content_changed'); }); _editor.on('closed', this, function () { diff --git a/addons/website_blog/static/src/js/website_blog.editor.js b/addons/website_blog/static/src/js/website_blog.editor.js index d4cdeb3e679..b2187ca28ae 100644 --- a/addons/website_blog/static/src/js/website_blog.editor.js +++ b/addons/website_blog/static/src/js/website_blog.editor.js @@ -182,8 +182,8 @@ options.registry.blog_cover = options.Class.extend({ onlyImages: true, firstFilters: ['background'] }, $image[0]).open(); - editor.on('save', this, function (event, img) { - var src = $image.attr('src'); + editor.on('save', this, function (image) { + var src = image.src; this.$image.css('background-image', src ? ('url(' + src + ')') : ''); if (!this.$target.hasClass('cover')) { var $opt = this.$el.find('[data-select-class]').first(); From d25d3324e2ae105429a965c8f9cfb08c861e95d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Theys?= Date: Thu, 23 May 2019 14:47:38 +0000 Subject: [PATCH 2/8] [IMP] web_editor: split search out of MediaWidget The search is not used on VideoWidget for example, so it makes more sense to split it out of the basic MediaWidget. PR: #33509 --- .../static/src/js/wysiwyg/widgets/media.js | 49 +++++++++++++------ .../static/src/js/wysiwyg/widgets/widgets.js | 1 + 2 files changed, 36 insertions(+), 14 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 a30b4a223b4..acff4183aab 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/media.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/media.js @@ -13,18 +13,17 @@ var _t = core._t; var MediaWidget = Widget.extend({ xmlDependencies: ['/web_editor/static/src/xml/wysiwyg.xml'], - events: { - 'input input.o_we_search': '_onSearchInput', - }, /** * @constructor + * @param {Element} media: the target Element for which we select a media + * @param {Object} options: useful parameters such as res_id, res_model, + * context, user_id, ... */ init: function (parent, media, options) { this._super.apply(this, arguments); this.media = media; this.$media = $(media); - this._onSearchInput = _.debounce(this._onSearchInput, 500); }, //-------------------------------------------------------------------------- @@ -40,12 +39,6 @@ var MediaWidget = Widget.extend({ } this._clear(); }, - /** - * @abstract - * @param {string} needle - * @returns {Deferred} - */ - search: function (needle) {}, /** * Saves the currently configured media on the target media. * @@ -62,6 +55,33 @@ var MediaWidget = Widget.extend({ * @abstract */ _clear: function () {}, +}); + +var SearchableMediaWidget = MediaWidget.extend({ + events: _.extend({}, MediaWidget.prototype.events || {}, { + 'input .o_we_search': '_onSearchInput', + }), + + /** + * @constructor + */ + init: function () { + this._super.apply(this, arguments); + this._onSearchInput = _.debounce(this._onSearchInput, 500); + }, + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + /** + * Finds and displays existing attachments related to the target media. + * + * @abstract + * @param {string} needle: only return attachments matching this parameter + * @returns {Promise} + */ + search: function (needle) {}, //-------------------------------------------------------------------------- // Handlers @@ -79,9 +99,9 @@ var MediaWidget = Widget.extend({ /** * Let users choose an image, including uploading a new image in odoo. */ -var ImageWidget = MediaWidget.extend({ +var ImageWidget = SearchableMediaWidget.extend({ template: 'wysiwyg.widgets.image', - events: _.extend({}, MediaWidget.prototype.events || {}, { + events: _.extend({}, SearchableMediaWidget.prototype.events || {}, { 'click .o_upload_media_button': '_onUploadButtonClick', 'click .o_upload_media_button_no_optimization': '_onUploadButtonNoOptimizationClick', 'change input[type=file]': '_onImageSelection', @@ -655,9 +675,9 @@ var ImageWidget = MediaWidget.extend({ * Let users choose a font awesome icon, support all font awesome loaded in the * css files. */ -var IconWidget = MediaWidget.extend({ +var IconWidget = SearchableMediaWidget.extend({ template: 'wysiwyg.widgets.font-icons', - events: _.extend({}, MediaWidget.prototype.events || {}, { + events: _.extend({}, SearchableMediaWidget.prototype.events || {}, { 'click .font-icons-icon': '_onIconClick', 'dblclick .font-icons-icon': '_onIconDblClick', }), @@ -1097,6 +1117,7 @@ var VideoWidget = MediaWidget.extend({ return { MediaWidget: MediaWidget, + SearchableMediaWidget: SearchableMediaWidget, ImageWidget: ImageWidget, IconWidget: IconWidget, VideoWidget: VideoWidget, diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/widgets.js b/addons/web_editor/static/src/js/wysiwyg/widgets/widgets.js index 18b88951c70..2f52fe6c5fa 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/widgets.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/widgets.js @@ -19,6 +19,7 @@ return { ColorpickerDialog: ColorpickerDialog, MediaWidget: media.MediaWidget, + SearchableMediaWidget: media.SearchableMediaWidget, ImageWidget: media.ImageWidget, IconWidget: media.IconWidget, VideoWidget: media.VideoWidget, From 8ab696dc824bdcb832d81f2540dd7030dd291d0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Theys?= Date: Thu, 23 May 2019 14:47:40 +0000 Subject: [PATCH 3/8] [IMP] web_editor, web_unsplash: split media widget (image & document) The common code is kept in a generic File widget, while the split allows for easier customization. PR: #33509 --- .../static/src/js/wysiwyg/widgets/media.js | 145 ++++++++++++++---- .../src/js/wysiwyg/widgets/media_dialog.js | 4 +- .../static/src/js/wysiwyg/widgets/widgets.js | 2 + addons/web_editor/static/src/xml/wysiwyg.xml | 79 ++++++---- .../static/tests/field_html_tests.js | 15 -- .../web_editor/static/tests/wysiwyg_tests.js | 8 +- .../static/src/js/unsplash_image_widget.js | 24 ++- .../static/src/xml/unsplash_image_widget.xml | 2 +- 8 files changed, 181 insertions(+), 98 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 acff4183aab..2170fda3259 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/media.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/media.js @@ -97,10 +97,9 @@ var SearchableMediaWidget = MediaWidget.extend({ }); /** - * Let users choose an image, including uploading a new image in odoo. + * Let users choose a file, including uploading a new file in odoo. */ -var ImageWidget = SearchableMediaWidget.extend({ - template: 'wysiwyg.widgets.image', +var FileWidget = SearchableMediaWidget.extend({ events: _.extend({}, SearchableMediaWidget.prototype.events || {}, { 'click .o_upload_media_button': '_onUploadButtonClick', 'click .o_upload_media_button_no_optimization': '_onUploadButtonNoOptimizationClick', @@ -112,7 +111,9 @@ var ImageWidget = SearchableMediaWidget.extend({ '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, @@ -128,7 +129,7 @@ var ImageWidget = SearchableMediaWidget.extend({ this.options = options; this.context = options.context; - this.accept = options.accept || (options.document ? '*/*' : 'image/*'); + this.accept = options.accept; this.multiImages = options.multiImages; @@ -299,10 +300,7 @@ var ImageWidget = SearchableMediaWidget.extend({ domain = domain.concat(attachedDocumentDomain); } domain = ['|', ['public', '=', true]].concat(domain); - - domain.push('|', - ['mimetype', '=', false], - ['mimetype', this.options.document ? 'not in' : 'in', ['image/gif', 'image/jpe', 'image/jpeg', 'image/jpg', 'image/gif', 'image/png']]); + domain = domain.concat(this.options.mimetypeDomain); if (needle && needle.length) { domain.push('|', ['datas_fname', 'ilike', needle], ['name', 'ilike', needle]); } @@ -337,6 +335,20 @@ var ImageWidget = SearchableMediaWidget.extend({ this.search(this.$('.o_we_search').val() || ''); } }, + /** + * Renders the existing attachments and returns the result as a string. + * + * @param {Object[]} rows + * @param {boolean} withEffect + * @returns {string} + */ + _renderExisting: function (rows, withEffect) { + return QWeb.render(this.existingAttachmentsTemplate, { + rows: rows, + widget: this, + withEffect: withEffect, + }); + }, /** * @private */ @@ -352,11 +364,7 @@ var ImageWidget = SearchableMediaWidget.extend({ // Render menu & content this.$('.existing-attachments').replaceWith( - QWeb.render('wysiwyg.widgets.files.existing.content', { - rows: rows, - isDocument: this.options.document, - withEffect: withEffect, - }) + this._renderExisting(rows, withEffect) ); var $divs = this.$('.o_image'); @@ -481,6 +489,26 @@ var ImageWidget = SearchableMediaWidget.extend({ this.search(''); } }, + /** + * Updates the add by URL UI. + * + * @private + * @param {boolean} emptyValue + * @param {boolean} isURL + * @param {boolean} isImage + */ + _updateAddUrlUi(emptyValue, isURL, isImage) { + var $button = this.$('.o_upload_media_url_button'); + var $success = this.$('.o_we_url_success'); + var $error = this.$('.o_we_url_error'); + + $button.toggleClass('btn-secondary', emptyValue) + .toggleClass('btn-primary', !emptyValue) + .prop('disabled', !isURL); + + $success.toggleClass('d-none', !isURL); + $error.toggleClass('d-none', emptyValue || isURL); + }, /** * @private */ @@ -604,6 +632,7 @@ var ImageWidget = SearchableMediaWidget.extend({ } $helpBlock.replaceWith(QWeb.render('wysiwyg.widgets.image.existing.error', { views: prevented[id], + widget: self, })); }); } @@ -614,10 +643,6 @@ var ImageWidget = SearchableMediaWidget.extend({ */ _onURLInputChange: function (ev) { var $input = $(ev.currentTarget); - var $button = this.$('.o_upload_media_url_button'); - var $success = this.$('.o_we_url_success'); - var $warning = this.$('.o_we_url_warning'); - var $error = this.$('.o_we_url_error'); var inputValue = $input.val(); var emptyValue = (inputValue === ''); @@ -627,14 +652,7 @@ var ImageWidget = SearchableMediaWidget.extend({ return inputValue.endsWith(format); }); - $button.toggleClass('btn-secondary', emptyValue).toggleClass('btn-primary', !emptyValue) - .prop('disabled', !isURL); - if (!this.options.document) { - $button.text((isURL && !isImage) ? _t("Add as document") : _t("Add image")); - } - $success.toggleClass('d-none', !isURL); - $warning.toggleClass('d-none', !isURL || this.options.document || isImage); - $error.toggleClass('d-none', emptyValue || isURL); + this._updateAddUrlUi(emptyValue, isURL, isImage); }, /** * @private @@ -671,6 +689,79 @@ var ImageWidget = SearchableMediaWidget.extend({ }, }); +/** + * Let users choose an image, including uploading a new image in odoo. + */ +var ImageWidget = FileWidget.extend({ + template: 'wysiwyg.widgets.image', + existingAttachmentsTemplate: 'wysiwyg.widgets.image.existing.attachments', + + /** + * @constructor + */ + init: function (parent, media, options) { + options = _.extend({ + accept: 'image/*', + mimetypeDomain: [['mimetype', 'in', this.IMAGE_MIMETYPES]], + }, options || {}); + this._super(parent, media, options); + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @override + */ + _updateAddUrlUi: function (emptyValue, isURL, isImage) { + this._super.apply(this, arguments); + + var $button = this.$('.o_upload_media_url_button'); + var $warning = this.$('.o_we_url_warning'); + + $button.text((isURL && !isImage) ? _t("Add as document") : _t("Add image")); + $warning.toggleClass('d-none', !isURL || isImage); + }, +}); + + +/** + * Let users choose a document, including uploading a new document in odoo. + */ +var DocumentWidget = FileWidget.extend({ + template: 'wysiwyg.widgets.document', + existingAttachmentsTemplate: 'wysiwyg.widgets.document.existing.attachments', + + /** + * @constructor + */ + init: function (parent, media, options) { + options = _.extend({ + accept: '*/*', + mimetypeDomain: [['mimetype', 'not in', this.IMAGE_MIMETYPES]], + }, options || {}); + this._super(parent, media, options); + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @override + */ + _updateAddUrlUi: function (emptyValue, isURL, isImage) { + this._super.apply(this, arguments); + + var $button = this.$('.o_upload_media_url_button'); + var $warning = this.$('.o_we_url_warning'); + + $button.text((isURL && isImage) ? _t("Add as image") : _t("Add document")); + $warning.toggleClass('d-none', !isURL || !isImage); + }, +}); + /** * Let users choose a font awesome icon, support all font awesome loaded in the * css files. @@ -758,7 +849,7 @@ var IconWidget = SearchableMediaWidget.extend({ }); } this.$('div.font-icons-icons').html( - QWeb.render('wysiwyg.widgets.font-icons.icons', {iconsParser: iconsParser}) + QWeb.render('wysiwyg.widgets.font-icons.icons', {iconsParser: iconsParser, widget: this}) ); return Promise.resolve(); }, @@ -1118,7 +1209,9 @@ var VideoWidget = MediaWidget.extend({ return { MediaWidget: MediaWidget, SearchableMediaWidget: SearchableMediaWidget, + FileWidget: FileWidget, ImageWidget: ImageWidget, + DocumentWidget: DocumentWidget, IconWidget: IconWidget, VideoWidget: VideoWidget, }; diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/media_dialog.js b/addons/web_editor/static/src/js/wysiwyg/widgets/media_dialog.js index 4297d5f4dd3..3e68294cf8b 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/media_dialog.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/media_dialog.js @@ -55,9 +55,7 @@ var MediaDialog = Dialog.extend({ this.noVideos = onlyImages || options.noVideos; if (!this.noDocuments) { - this.documentDialog = new MediaModules.ImageWidget(this, this.media, _.extend({}, options, { - document: true, - })); + this.documentDialog = new MediaModules.DocumentWidget(this, this.media, options); this.documentDialog.tabToShow = 'document'; } if (!this.noIcons) { diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/widgets.js b/addons/web_editor/static/src/js/wysiwyg/widgets/widgets.js index 2f52fe6c5fa..cb17523ac19 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/widgets.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/widgets.js @@ -20,7 +20,9 @@ return { MediaWidget: media.MediaWidget, SearchableMediaWidget: media.SearchableMediaWidget, + FileWidget: media.FileWidget, ImageWidget: media.ImageWidget, + DocumentWidget: media.DocumentWidget, IconWidget: media.IconWidget, VideoWidget: media.VideoWidget, }; diff --git a/addons/web_editor/static/src/xml/wysiwyg.xml b/addons/web_editor/static/src/xml/wysiwyg.xml index cd20ee3f4ef..9a93066ee48 100644 --- a/addons/web_editor/static/src/xml/wysiwyg.xml +++ b/addons/web_editor/static/src/xml/wysiwyg.xml @@ -93,8 +93,8 @@ - - + +
- - - - +
@@ -122,48 +119,62 @@
- +
- - - - +
- +
- - - + + +
- - - Search a document - Search an image - - +
+ + + Upload an image + https://www.odoo.com/logo.png + Add image + Search an image + The URL does not contain any image. The file will be added in the document section. + + + + + + + + + + Upload a document + https://www.odoo.com/mydocument + Add document + Search a document + The URL contains an image. The file will be added in the image section. + + + - +
- - -
+ + + + +

The image could not be deleted because it is used in the diff --git a/addons/web_editor/static/tests/field_html_tests.js b/addons/web_editor/static/tests/field_html_tests.js index 5c7bd70d117..477519d4060 100644 --- a/addons/web_editor/static/tests/field_html_tests.js +++ b/addons/web_editor/static/tests/field_html_tests.js @@ -193,21 +193,6 @@ QUnit.module('web_editor', {}, function () { if (args.method === "generate_access_token") { return Promise.resolve(); } - if (args.kwargs.domain[7][2].join(',') === "image/gif,image/jpe,image/jpeg,image/jpg,image/gif,image/png") { - return Promise.resolve([{ - "id": 1, - "public": true, - "name": "image", - "datas_fname": "image.png", - "mimetype": "image/png", - "checksum": false, - "url": "/web_editor/static/src/img/transparent.png", - "type": "url", - "res_id": 0, - "res_model": false, - "access_token": false - }]); - } } return this._super(route, args); }, diff --git a/addons/web_editor/static/tests/wysiwyg_tests.js b/addons/web_editor/static/tests/wysiwyg_tests.js index 7462f5a330b..17f9951fe6f 100644 --- a/addons/web_editor/static/tests/wysiwyg_tests.js +++ b/addons/web_editor/static/tests/wysiwyg_tests.js @@ -3406,12 +3406,8 @@ QUnit.module('Media', { }, mockRPC: function (route, args) { - if (args.model === 'ir.attachment' || !args.length) { - if (!args.length && route.indexOf('data:image/png;base64') === 0 || - args.method === "search_read" && - args.kwargs.domain[7][2].join(',') === "image/gif,image/jpe,image/jpeg,image/jpg,image/gif,image/png") { - return Promise.resolve(this.data.records); - } + if (route.indexOf('data:image/png;base64') === 0) { + return Promise.resolve(); } if (route.indexOf('youtube') !== -1) { return Promise.resolve(); diff --git a/addons/web_unsplash/static/src/js/unsplash_image_widget.js b/addons/web_unsplash/static/src/js/unsplash_image_widget.js index 3c0d1964513..5f5100c3da2 100644 --- a/addons/web_unsplash/static/src/js/unsplash_image_widget.js +++ b/addons/web_unsplash/static/src/js/unsplash_image_widget.js @@ -56,9 +56,7 @@ widgetsMedia.ImageWidget.include({ * @override */ start: function () { - if (!this.options.document) { - this.$('.o_we_search_icon').replaceWith(core.qweb.render('web_unsplash.dialog.media.search_icon')); - } + this.$('.o_we_search_icon').replaceWith(core.qweb.render('web_unsplash.dialog.media.search_icon')); return this._super.apply(this, arguments); }, /** @@ -286,18 +284,16 @@ widgetsMedia.ImageWidget.include({ * @override */ _onSearchInput: function (ev) { - if (!this.options.document) { - var $input = $(ev.currentTarget); - var inputValue = $input.val(); - this.$('.o_search_value_input').text(inputValue); + var $input = $(ev.currentTarget); + var inputValue = $input.val(); + this.$('.o_search_value_input').text(inputValue); - var $icon = this.$('.o_we_search_icon'); - if ($icon.parent().is('.show')) { - $icon.dropdown('update'); - } else if (!this.hasSearched) { - $icon.dropdown('toggle'); - $input.focus(); - } + var $icon = this.$('.o_we_search_icon'); + if ($icon.parent().is('.show')) { + $icon.dropdown('update'); + } else if (!this.hasSearched) { + $icon.dropdown('toggle'); + $input.focus(); } this._super.apply(this, arguments); }, diff --git a/addons/web_unsplash/static/src/xml/unsplash_image_widget.xml b/addons/web_unsplash/static/src/xml/unsplash_image_widget.xml index dc680ef00c4..6ecf304034b 100644 --- a/addons/web_unsplash/static/src/xml/unsplash_image_widget.xml +++ b/addons/web_unsplash/static/src/xml/unsplash_image_widget.xml @@ -1,7 +1,7 @@ - +

From 277c30e7e63eed08cbae3661b40cc4bd2cceba56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Theys?= Date: Thu, 23 May 2019 14:47:42 +0000 Subject: [PATCH 4/8] [IMP] web_editor, website: clean up media dialog Restructure the code in a more logical manner. No functional change. PR: #33509 --- .../src/js/wysiwyg/widgets/media_dialog.js | 223 ++++++++++-------- addons/web_editor/static/src/xml/wysiwyg.xml | 16 +- .../static/tests/wysiwyg_snippets_tests.js | 4 +- .../static/src/js/editor/snippets.options.js | 2 +- 4 files changed, 142 insertions(+), 103 deletions(-) diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/media_dialog.js b/addons/web_editor/static/src/js/wysiwyg/widgets/media_dialog.js index 3e68294cf8b..0158dd7e49c 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/media_dialog.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/media_dialog.js @@ -8,9 +8,12 @@ var Dialog = require('wysiwyg.widgets.Dialog'); var _t = core._t; /** - * MediaDialog widget. Lets users change a media, including uploading a - * new image, font awsome or video and can change a media into an other - * media. + * Lets the user select a media. The media can be existing or newly uploaded. + * + * The media can be one of the following types: image, document, video or + * font awesome icon (only existing icons). + * + * The user may change a media into another one depending on the given options. */ var MediaDialog = Dialog.extend({ template: 'wysiwyg.widgets.media', @@ -18,7 +21,10 @@ var MediaDialog = Dialog.extend({ ['/web_editor/static/src/xml/wysiwyg.xml'] ), events: _.extend({}, Dialog.prototype.events, { - 'click a[data-toggle="tab"]': '_onTabChange', + 'click #editor-media-image-tab': '_onClickImageTab', + 'click #editor-media-document-tab': '_onClickDocumentTab', + 'click #editor-media-icon-tab': '_onClickIconTab', + 'click #editor-media-video-tab': '_onClickVideoTab', }), custom_events: _.extend({}, Dialog.prototype.custom_events || {}, { save_request: '_onSaveRequest', @@ -26,10 +32,15 @@ var MediaDialog = Dialog.extend({ /** * @constructor + * @param {Element} media */ init: function (parent, options, media) { - var self = this; - options = options || {}; + var $media = $(media); + + options = _.extend({}, options); + options.noDocuments = options.onlyImages || options.noDocuments; + options.noIcons = options.onlyImages || options.noIcons; + options.noVideos = options.onlyImages || options.noVideos; this._super(parent, _.extend({}, { title: _t("Select a Media"), @@ -44,86 +55,68 @@ var MediaDialog = Dialog.extend({ }, }); - this.media = media; - this.$media = $(media); - - this.multiImages = options.multiImages; - var onlyImages = options.onlyImages || this.multiImages; - this.noImages = options.noImages; - this.noDocuments = onlyImages || options.noDocuments; - this.noIcons = onlyImages || options.noIcons; - this.noVideos = onlyImages || options.noVideos; - - if (!this.noDocuments) { - this.documentDialog = new MediaModules.DocumentWidget(this, this.media, options); - this.documentDialog.tabToShow = 'document'; + if (!options.noImages) { + this.imageWidget = new MediaModules.ImageWidget(this, media, options); } - if (!this.noIcons) { - this.iconDialog = new MediaModules.IconWidget(this, this.media, options); - this.iconDialog.tabToShow = 'icon'; + if (!options.noDocuments) { + this.documentWidget = new MediaModules.DocumentWidget(this, media, options); } - if (!this.noVideos) { - this.videoDialog = new MediaModules.VideoWidget(this, this.media, options); - this.videoDialog.tabToShow = 'video'; + if (!options.noIcons) { + this.iconWidget = new MediaModules.IconWidget(this, media, options); } - if (!this.noImages) { - this.imageDialog = new MediaModules.ImageWidget(this, this.media, options); - this.imageDialog.tabToShow = 'image'; + if (!options.noVideos) { + this.videoWidget = new MediaModules.VideoWidget(this, media, options); } - this.active = this.imageDialog || this.documentDialog || this.iconDialog || this.videoDialog; - if (this.imageDialog && this.$media.is('img')) { - this.active = this.imageDialog; - } else if (this.documentDialog && this.$media.is('a.o_image')) { - this.active = this.documentDialog; - } else if (this.videoDialog && this.$media.hasClass('media_iframe_video')) { - this.active = this.videoDialog; - } else if (this.iconDialog && this.$media.is('span, i')) { - this.active = this.iconDialog; + if (this.imageWidget && $media.is('img')) { + this.activeWidget = this.imageWidget; + } else if (this.documentWidget && $media.is('a.o_image')) { + this.activeWidget = this.documentWidget; + } else if (this.videoWidget && $media.hasClass('media_iframe_video')) { + this.activeWidget = this.videoWidget; + } else if (this.iconWidget && $media.is('span, i')) { + this.activeWidget = this.iconWidget; + } else if (this.imageWidget) { + this.activeWidget = this.imageWidget; } - - this.opened(function () { - self.$('[href="#editor-media-' + self.active.tabToShow + '"]').tab('show'); - }); }, /** + * Adds the appropriate class to the current modal and appends the media + * widgets to their respective tabs. + * * @override */ start: function () { - var self = this; - var defs = [this._super.apply(this, arguments)]; - this.$modal.addClass('note-image-dialog'); + var promises = [this._super.apply(this, arguments)]; this.$modal.find('.modal-dialog').addClass('o_select_media_dialog'); - if (this.imageDialog) { - this.imageDialog.clear(); + if (this.imageWidget) { + this.imageWidget.clear(); } - if (this.documentDialog) { - this.documentDialog.clear(); + if (this.documentWidget) { + this.documentWidget.clear(); } - if (this.iconDialog) { - this.iconDialog.clear(); + if (this.iconWidget) { + this.iconWidget.clear(); } - if (this.videoDialog) { - this.videoDialog.clear(); + if (this.videoWidget) { + this.videoWidget.clear(); } - if (this.imageDialog) { - defs.push(this.imageDialog.appendTo(this.$("#editor-media-image"))); + if (this.imageWidget) { + promises.push(this.imageWidget.appendTo(this.$("#editor-media-image"))); } - if (this.documentDialog) { - defs.push(this.documentDialog.appendTo(this.$("#editor-media-document"))); + if (this.documentWidget) { + promises.push(this.documentWidget.appendTo(this.$("#editor-media-document"))); } - if (this.iconDialog) { - defs.push(this.iconDialog.appendTo(this.$("#editor-media-icon"))); + if (this.iconWidget) { + promises.push(this.iconWidget.appendTo(this.$("#editor-media-icon"))); } - if (this.videoDialog) { - defs.push(this.videoDialog.appendTo(this.$("#editor-media-video"))); + if (this.videoWidget) { + promises.push(this.videoWidget.appendTo(this.$("#editor-media-video"))); } - return Promise.all(defs).then(function () { - self._setActive(self.active); - }); + return Promise.all(promises); }, //-------------------------------------------------------------------------- @@ -131,35 +124,97 @@ var MediaDialog = Dialog.extend({ //-------------------------------------------------------------------------- /** + * Returns whether the document widget is currently active. + * + * @returns {boolean} + */ + isDocumentActive: function () { + return this.activeWidget === this.documentWidget; + }, + /** + * Returns whether the icon widget is currently active. + * + * @returns {boolean} + */ + isIconActive: function () { + return this.activeWidget === this.iconWidget; + }, + /** + * Returns whether the image widget is currently active. + * + * @returns {boolean} + */ + isImageActive: function () { + return this.activeWidget === this.imageWidget; + }, + /** + * Returns whether the video widget is currently active. + * + * @returns {boolean} + */ + isVideoActive: function () { + return this.activeWidget === this.videoWidget; + }, + /** + * Saves the currently selected media from the currently active widget. + * + * The save event data `final_data` will be one Element in general, but it + * will be an Array of Element if `multiImages` is set. + * * @override */ save: function () { var self = this; var _super = this._super; var args = arguments; - return Promise.resolve(this.active.save()).then(function (data) { + return Promise.resolve(this.activeWidget.save()).then(function (data) { self.final_data = data; return _super.apply(self, args); }); }, - //-------------------------------------------------------------------------- - // - //-------------------------------------------------------------------------- - - /** - * @private - * @param {Object} widget - */ - _setActive: function (widget) { - this.active = widget; - }, - //-------------------------------------------------------------------------- // Handlers //-------------------------------------------------------------------------- /** + * Sets the document widget as the active widget. + * + * @private + */ + _onClickDocumentTab: function () { + this.activeWidget = this.documentWidget; + }, + /** + * Sets the icon widget as the active widget. + * + * @private + */ + _onClickIconTab: function () { + this.activeWidget = this.iconWidget; + }, + /** + * Sets the image widget as the active widget. + * + * @private + */ + _onClickImageTab: function () { + this.activeWidget = this.imageWidget; + }, + /** + * Sets the video widget as the active widget. + * + * @private + */ + _onClickVideoTab: function () { + this.activeWidget = this.videoWidget; + }, + /** + * Handles save request from the child widgets. + * + * This is for usability, to allow the user to save from other ways than + * click on the modal button, such as double clicking a media to select it. + * * @private * @param {OdooEvent} ev */ @@ -167,22 +222,6 @@ var MediaDialog = Dialog.extend({ ev.stopPropagation(); this.save(); }, - /** - * @private - * @param {JQueryEvent} ev - */ - _onTabChange: function (ev) { - var $target = $(ev.target); - if ($target.is('[href="#editor-media-image"]')) { - this._setActive(this.imageDialog); - } else if ($target.is('[href="#editor-media-document"]')) { - this._setActive(this.documentDialog); - } else if ($target.is('[href="#editor-media-icon"]')) { - this._setActive(this.active = this.iconDialog); - } else if ($target.is('[href="#editor-media-video"]')) { - this._setActive(this.active = this.videoDialog); - } - }, }); return MediaDialog; diff --git a/addons/web_editor/static/src/xml/wysiwyg.xml b/addons/web_editor/static/src/xml/wysiwyg.xml index 9a93066ee48..00d2878f8c1 100644 --- a/addons/web_editor/static/src/xml/wysiwyg.xml +++ b/addons/web_editor/static/src/xml/wysiwyg.xml @@ -68,17 +68,17 @@
-
-
-
-
+
+
+
+
diff --git a/addons/web_editor/static/tests/wysiwyg_snippets_tests.js b/addons/web_editor/static/tests/wysiwyg_snippets_tests.js index 1f61ff307d4..bd63364d303 100644 --- a/addons/web_editor/static/tests/wysiwyg_snippets_tests.js +++ b/addons/web_editor/static/tests/wysiwyg_snippets_tests.js @@ -352,8 +352,8 @@ QUnit.test('background-image', function (assert) { $('#oe_manipulators .oe_overlay_options a.snippet-option-background[data-choose-image]').click(); defMediaDialogInit.then(function () { - $('.modal.note-image-dialog .existing-attachments .o_image').click(); - $('.modal.note-image-dialog .modal-footer .btn-primary').click(); + $('.o_select_media_dialog .existing-attachments .o_image').click(); + $('.o_select_media_dialog .modal-footer .btn-primary').click(); }); defMediaDialogSave.then(function () { diff --git a/addons/website/static/src/js/editor/snippets.options.js b/addons/website/static/src/js/editor/snippets.options.js index de4507c0ff0..d32f7b4bea3 100644 --- a/addons/website/static/src/js/editor/snippets.options.js +++ b/addons/website/static/src/js/editor/snippets.options.js @@ -1001,7 +1001,7 @@ options.registry.gallery = options.Class.extend({ addImages: function (previewMode) { var self = this; var $container = this.$('.container:first'); - var dialog = new weWidgets.MediaDialog(this, {multiImages: true}, null); + var dialog = new weWidgets.MediaDialog(this, {multiImages: true, onlyImages: true}, null); var lastImage = _.last(this._getImages()); var index = lastImage ? this._getIndex(lastImage) : -1; dialog.on('save', this, function (attachments) { From b0acd056e952c8e09c21f1d00689675c11d8c411 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Theys?= Date: Thu, 23 May 2019 14:47:43 +0000 Subject: [PATCH 5/8] [IMP] web_editor: clean up media file widget selectors Avoid selectors based on DOM structure, use classes whenever possible. Register all the selectors in start to avoid searching the DOM multiple times. No functional change. PR: #33509 --- .../static/src/js/wysiwyg/widgets/media.js | 66 +++++++++---------- addons/web_editor/static/src/xml/wysiwyg.xml | 2 +- .../web_editor/static/tests/wysiwyg_tests.js | 2 +- 3 files changed, 33 insertions(+), 37 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 2170fda3259..4e514985dad 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/media.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/media.js @@ -103,11 +103,11 @@ var FileWidget = SearchableMediaWidget.extend({ events: _.extend({}, SearchableMediaWidget.prototype.events || {}, { 'click .o_upload_media_button': '_onUploadButtonClick', 'click .o_upload_media_button_no_optimization': '_onUploadButtonNoOptimizationClick', - 'change input[type=file]': '_onImageSelection', + 'change .o_file_input': '_onImageSelection', 'click .o_upload_media_url_button': '_onUploadURLButtonClick', - 'input input[name="url"]': '_onURLInputChange', - 'click .existing-attachments [data-src]': '_onImageClick', - 'dblclick .existing-attachments [data-src]': '_onImageDblClick', + '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_remove': '_onRemoveClick', 'click .o_load_more': '_onLoadMoreClick', }), @@ -153,6 +153,15 @@ var FileWidget = SearchableMediaWidget.extend({ start: function () { var def = this._super.apply(this, arguments); var self = this; + this.$urlInput = this.$('.o_we_url_input'); + this.$form = this.$('form'); + this.$fileInput = this.$('.o_file_input'); + this.$uploadButton = this.$('.o_upload_media_button'); + this.$addUrlButton = this.$('.o_upload_media_url_button'); + this.$urlSuccess = this.$('.o_we_url_success'); + this.$urlWarning = this.$('.o_we_url_warning'); + this.$urlError = this.$('.o_we_url_error'); + this.$errorText = this.$('.o_we_error_text'); this._renderImages(true); @@ -189,7 +198,7 @@ var FileWidget = SearchableMediaWidget.extend({ search: function (needle, noRender) { var self = this; if (!noRender) { - this.$('input.o_we_url_input').val('').trigger('input').trigger('change'); + this.$urlInput.val('').trigger('input').trigger('change'); } return this._rpc({ model: 'ir.attachment', @@ -360,7 +369,7 @@ var FileWidget = SearchableMediaWidget.extend({ .values() .value(); - this.$('.form-text').empty(); + this.$errorText.empty(); // Render menu & content this.$('.existing-attachments').replaceWith( @@ -498,16 +507,12 @@ var FileWidget = SearchableMediaWidget.extend({ * @param {boolean} isImage */ _updateAddUrlUi(emptyValue, isURL, isImage) { - var $button = this.$('.o_upload_media_url_button'); - var $success = this.$('.o_we_url_success'); - var $error = this.$('.o_we_url_error'); - - $button.toggleClass('btn-secondary', emptyValue) + this.$addUrlButton.toggleClass('btn-secondary', emptyValue) .toggleClass('btn-primary', !emptyValue) .prop('disabled', !isURL); - $success.toggleClass('d-none', !isURL); - $error.toggleClass('d-none', emptyValue || isURL); + this.$urlSuccess.toggleClass('d-none', !isURL); + this.$urlError.toggleClass('d-none', emptyValue || isURL); }, /** * @private @@ -554,14 +559,14 @@ var FileWidget = SearchableMediaWidget.extend({ resolve(); function _processFile(attachment, error) { - var $button = self.$('.o_upload_image_button'); + var $button = self.$uploadButton; if (!error) { $button.addClass('btn-success'); self._toggleImage(attachment, true); } else { $button.addClass('btn-danger'); self.$el.addClass('o_has_error').find('.form-control, .custom-select').addClass('is-invalid'); - self.$el.find('.form-text').text(error); + self.$errorText.text(error); } if (!self.multiImages) { @@ -571,7 +576,7 @@ var FileWidget = SearchableMediaWidget.extend({ }); self.$el.submit(); - self.$('.o_file_input').val(''); + self.$fileInput.val(''); }); }, @@ -601,11 +606,10 @@ var FileWidget = SearchableMediaWidget.extend({ * @private */ _onImageSelection: function () { - var $form = this.$('form'); this.$el.addClass('nosave'); - $form.removeClass('o_has_error').find('.form-control, .custom-select').removeClass('is-invalid'); - $form.find('.form-text').empty(); - this.$('.o_upload_media_button').removeClass('btn-danger btn-success'); + this.$form.removeClass('o_has_error').find('.form-control, .custom-select').removeClass('is-invalid'); + this.$errorText.empty(); + this.$uploadButton.removeClass('btn-danger btn-success'); this._uploadFile(); }, /** @@ -615,7 +619,7 @@ var FileWidget = SearchableMediaWidget.extend({ var self = this; Dialog.confirm(this, _t("Are you sure you want to delete this file ?"), { confirm_callback: function () { - var $helpBlock = self.$('.form-text').empty(); + var $helpBlock = self.$errorText.empty(); var $a = $(ev.currentTarget); var id = parseInt($a.data('id'), 10); var attachment = _.findWhere(self.records, {id: id}); @@ -658,14 +662,14 @@ var FileWidget = SearchableMediaWidget.extend({ * @private */ _onUploadButtonClick: function () { - this.$('input[type=file]').click(); + this.$fileInput.click(); }, /** * @private */ _onUploadButtonNoOptimizationClick: function () { this.$('input[name="disable_optimization"]').val('1'); - this.$('.o_upload_media_button').click(); + this.$uploadButton.click(); }, /** * @private @@ -716,12 +720,8 @@ var ImageWidget = FileWidget.extend({ */ _updateAddUrlUi: function (emptyValue, isURL, isImage) { this._super.apply(this, arguments); - - var $button = this.$('.o_upload_media_url_button'); - var $warning = this.$('.o_we_url_warning'); - - $button.text((isURL && !isImage) ? _t("Add as document") : _t("Add image")); - $warning.toggleClass('d-none', !isURL || isImage); + this.$addUrlButton.text((isURL && !isImage) ? _t("Add as document") : _t("Add image")); + this.$urlWarning.toggleClass('d-none', !isURL || isImage); }, }); @@ -753,12 +753,8 @@ var DocumentWidget = FileWidget.extend({ */ _updateAddUrlUi: function (emptyValue, isURL, isImage) { this._super.apply(this, arguments); - - var $button = this.$('.o_upload_media_url_button'); - var $warning = this.$('.o_we_url_warning'); - - $button.text((isURL && isImage) ? _t("Add as image") : _t("Add document")); - $warning.toggleClass('d-none', !isURL || !isImage); + this.$addUrlButton.text((isURL && isImage) ? _t("Add as image") : _t("Add document")); + this.$urlWarning.toggleClass('d-none', !isURL || !isImage); }, }); diff --git a/addons/web_editor/static/src/xml/wysiwyg.xml b/addons/web_editor/static/src/xml/wysiwyg.xml index 00d2878f8c1..daa3890fb25 100644 --- a/addons/web_editor/static/src/xml/wysiwyg.xml +++ b/addons/web_editor/static/src/xml/wysiwyg.xml @@ -105,7 +105,7 @@ -
+
diff --git a/addons/web_editor/static/tests/wysiwyg_tests.js b/addons/web_editor/static/tests/wysiwyg_tests.js index 17f9951fe6f..4312121015b 100644 --- a/addons/web_editor/static/tests/wysiwyg_tests.js +++ b/addons/web_editor/static/tests/wysiwyg_tests.js @@ -3474,7 +3474,7 @@ var _clickMedia = async function (wysiwyg, assert, callbackInit, test) { }; var _uploadAndInsertImg = async function (url) { - $('.modal-dialog input[name="url"]:first').val(url).trigger('input'); + $('.modal-dialog .o_we_url_input:first').val(url).trigger('input'); await testUtils.nextTick(); await testUtils.dom.triggerEvents($('.modal-dialog .o_upload_media_url_button:first'), ['mousedown', 'click']); }; From d4b09c11460c280864d64d73598903bc6235e3b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Theys?= Date: Thu, 23 May 2019 14:47:45 +0000 Subject: [PATCH 6/8] [IMP] web_editor, web_unsplash: remove options duplicate attributes Since a reference to the options is already kept, there is no need to keep a reference to each option individually. PR: #33509 --- .../static/src/js/wysiwyg/widgets/media.js | 25 ++++++++----------- addons/web_editor/static/src/xml/wysiwyg.xml | 4 +-- .../static/src/js/unsplash_image_widget.js | 2 +- 3 files changed, 14 insertions(+), 17 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 4e514985dad..6da33d42bd7 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/media.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/media.js @@ -127,14 +127,10 @@ var FileWidget = SearchableMediaWidget.extend({ this.imagesRows = this.IMAGES_ROWS; this.IMAGES_DISPLAYED_TOTAL = this.IMAGES_PER_ROW * this.imagesRows; - this.options = options; - this.context = options.context; - this.accept = options.accept; - - this.multiImages = options.multiImages; - - this.firstFilters = options.firstFilters || []; - this.lastFilters = options.lastFilters || []; + this.options = _.extend({ + firstFilters: [], + lastFilters: [], + }, options || {}); this.images = []; }, @@ -208,7 +204,7 @@ var FileWidget = SearchableMediaWidget.extend({ domain: this._getAttachmentsDomain(needle), fields: ['name', 'datas_fname', 'mimetype', 'checksum', 'url', 'type', 'res_id', 'res_model', 'access_token'], order: [{name: 'id', asc: false}], - context: this.context, + context: this.options.context, }, }).then(function (records) { self.records = _.chain(records) @@ -219,13 +215,13 @@ var FileWidget = SearchableMediaWidget.extend({ return (r.url || r.id); }) .sortBy(function (r) { - if (_.any(self.firstFilters, function (filter) { + if (_.any(self.options.firstFilters, function (filter) { var regex = new RegExp(filter, 'i'); return r.name.match(regex) || r.datas_fname && r.datas_fname.match(regex); })) { return -1; } - if (_.any(self.lastFilters, function (filter) { + if (_.any(self.options.lastFilters, function (filter) { var regex = new RegExp(filter, 'i'); return r.name.match(regex) || r.datas_fname && r.datas_fname.match(regex); })) { @@ -405,7 +401,8 @@ var FileWidget = SearchableMediaWidget.extend({ */ _save: function () { var self = this; - if (this.multiImages) { + + if (this.options.multiImages) { return this.images; } @@ -480,7 +477,7 @@ var FileWidget = SearchableMediaWidget.extend({ * @private */ _toggleImage: function (attachment, clearSearch, forceSelect) { - if (this.multiImages) { + if (this.options.multiImages) { var img = _.select(this.images, function (v) { return v.id === attachment.id; }); if (img.length) { if (!forceSelect) { @@ -569,7 +566,7 @@ var FileWidget = SearchableMediaWidget.extend({ self.$errorText.text(error); } - if (!self.multiImages) { + if (!self.options.multiImages) { self.trigger_up('save_request'); } } diff --git a/addons/web_editor/static/src/xml/wysiwyg.xml b/addons/web_editor/static/src/xml/wysiwyg.xml index daa3890fb25..fd4ad33e54d 100644 --- a/addons/web_editor/static/src/xml/wysiwyg.xml +++ b/addons/web_editor/static/src/xml/wysiwyg.xml @@ -101,7 +101,7 @@ enctype="multipart/form-data" t-att-target="iframeName"> - + @@ -119,7 +119,7 @@
- +
diff --git a/addons/web_unsplash/static/src/js/unsplash_image_widget.js b/addons/web_unsplash/static/src/js/unsplash_image_widget.js index 5f5100c3da2..963d31c961a 100644 --- a/addons/web_unsplash/static/src/js/unsplash_image_widget.js +++ b/addons/web_unsplash/static/src/js/unsplash_image_widget.js @@ -240,7 +240,7 @@ widgetsMedia.ImageWidget.include({ var imgid = $(ev.currentTarget).data('imgid'); var url = $(ev.currentTarget).data('url'); var downloadURL = $(ev.currentTarget).data('download-url'); - if (!this.multiImages) { + if (!this.options.multiImages) { this._unsplash.selectedImages = {}; } if (imgid in this._unsplash.selectedImages) { From 3924abb71bcbd1cc50a38063c1c4f7cff6e6256a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Theys?= Date: Thu, 23 May 2019 14:47:46 +0000 Subject: [PATCH 7/8] [IMP] web_editor: make media widget save always return a Promise Before this commit, the return value would be mixed. For consistency, make it always return a Promise. PR: #33509 --- .../static/src/js/wysiwyg/widgets/media.js | 14 +++++++++----- .../static/src/js/wysiwyg/widgets/media_dialog.js | 2 +- 2 files changed, 10 insertions(+), 6 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 6da33d42bd7..0d255e3ee82 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/media.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/media.js @@ -43,7 +43,7 @@ var MediaWidget = Widget.extend({ * Saves the currently configured media on the target media. * * @abstract - * @returns {*} + * @returns {Promise} */ save: function () {}, @@ -183,6 +183,9 @@ var FileWidget = SearchableMediaWidget.extend({ //-------------------------------------------------------------------------- /** + * Saves the currently selected image on the target media. If new files are + * currently being added, delays the save until all files have been added. + * * @override */ save: function () { @@ -398,17 +401,18 @@ var FileWidget = SearchableMediaWidget.extend({ }, /** * @private + * @returns {Promise} */ _save: function () { var self = this; if (this.options.multiImages) { - return this.images; + return Promise.resolve(this.images); } var img = this.images[0]; if (!img) { - return this.media; + return Promise.resolve(this.media); } var prom; @@ -818,7 +822,7 @@ var IconWidget = SearchableMediaWidget.extend({ class: _.compact(finalClasses).join(' '), style: style || null, }); - return this.media; + return Promise.resolve(this.media); }, /** * @override @@ -976,7 +980,7 @@ var VideoWidget = MediaWidget.extend({ ); this.media = this.$media[0]; } - return this.media; + return Promise.resolve(this.media); }, //-------------------------------------------------------------------------- diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/media_dialog.js b/addons/web_editor/static/src/js/wysiwyg/widgets/media_dialog.js index 0158dd7e49c..92c2f53099e 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/media_dialog.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/media_dialog.js @@ -167,7 +167,7 @@ var MediaDialog = Dialog.extend({ var self = this; var _super = this._super; var args = arguments; - return Promise.resolve(this.activeWidget.save()).then(function (data) { + return this.activeWidget.save().then(function (data) { self.final_data = data; return _super.apply(self, args); }); From 5275f16f2497c2a7c50d9f9b225b7b51b4885384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Theys?= Date: Mon, 27 May 2019 14:04:14 +0000 Subject: [PATCH 8/8] [IMP] web_editor: remove the unused onUpload option This was introduced in b26ad79a8c3f02726ed3f22f73faf49a2a272d1d and only used in `addons/web_editor/static/src/js/editor/rte.summernote.js` at that time. Then that file has been removed in f296992317e96562c66bd7ad59a5080d6c551ed5 PR: #33509 --- addons/web_editor/static/src/js/wysiwyg/widgets/media.js | 5 ----- 1 file changed, 5 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 0d255e3ee82..f901e9eb3f1 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/media.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/media.js @@ -461,11 +461,6 @@ var FileWidget = SearchableMediaWidget.extend({ self.$media.css(style); } - if (self.options.onUpload) { - // We consider that when selecting an image it is as if we upload it in the html content. - self.options.onUpload([img]); - } - // Remove crop related attributes if (self.$media.attr('data-aspect-ratio')) { var attrs = ['aspect-ratio', 'x', 'y', 'width', 'height', 'rotate', 'scale-x', 'scale-y'];